|
|
@ -23,6 +23,7 @@ import (
|
|
|
|
goerrors "errors"
|
|
|
|
goerrors "errors"
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"log"
|
|
|
|
"sort"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
@ -42,6 +43,8 @@ import (
|
|
|
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
|
|
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
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/fields"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
@ -51,13 +54,14 @@ import (
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
"k8s.io/apimachinery/pkg/watch"
|
|
|
|
"k8s.io/apimachinery/pkg/watch"
|
|
|
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
|
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
|
|
|
|
|
|
"k8s.io/cli-runtime/pkg/printers"
|
|
|
|
"k8s.io/cli-runtime/pkg/resource"
|
|
|
|
"k8s.io/cli-runtime/pkg/resource"
|
|
|
|
"k8s.io/client-go/kubernetes/scheme"
|
|
|
|
"k8s.io/client-go/kubernetes/scheme"
|
|
|
|
|
|
|
|
"k8s.io/client-go/rest"
|
|
|
|
cachetools "k8s.io/client-go/tools/cache"
|
|
|
|
cachetools "k8s.io/client-go/tools/cache"
|
|
|
|
watchtools "k8s.io/client-go/tools/watch"
|
|
|
|
watchtools "k8s.io/client-go/tools/watch"
|
|
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
|
|
"k8s.io/kubectl/pkg/validation"
|
|
|
|
"k8s.io/kubectl/pkg/validation"
|
|
|
|
"k8s.io/kubernetes/pkg/apis/core"
|
|
|
|
|
|
|
|
"k8s.io/kubernetes/pkg/kubectl/cmd/get"
|
|
|
|
"k8s.io/kubernetes/pkg/kubectl/cmd/get"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
@ -158,6 +162,40 @@ func (c *Client) BuildUnstructured(namespace string, reader io.Reader) (Result,
|
|
|
|
return result, scrubValidationError(err)
|
|
|
|
return result, scrubValidationError(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// BuildUnstructuredTable reads Kubernetes objects and returns unstructured infos
|
|
|
|
|
|
|
|
// as a Table. This is meant for viewing resources and displaying them in a table.
|
|
|
|
|
|
|
|
// This is similar to BuildUnstructured but transforms the request for table
|
|
|
|
|
|
|
|
// display.
|
|
|
|
|
|
|
|
func (c *Client) BuildUnstructuredTable(namespace string, reader io.Reader) (Result, error) {
|
|
|
|
|
|
|
|
var result Result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result, err := c.NewBuilder().
|
|
|
|
|
|
|
|
Unstructured().
|
|
|
|
|
|
|
|
ContinueOnError().
|
|
|
|
|
|
|
|
NamespaceParam(namespace).
|
|
|
|
|
|
|
|
DefaultNamespace().
|
|
|
|
|
|
|
|
Stream(reader, "").
|
|
|
|
|
|
|
|
Flatten().
|
|
|
|
|
|
|
|
TransformRequests(transformRequests).
|
|
|
|
|
|
|
|
Do().Infos()
|
|
|
|
|
|
|
|
return result, scrubValidationError(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This is used to retrieve a table view of the data. A table view is how kubectl
|
|
|
|
|
|
|
|
// retrieves the information Helm displays as resources in status. Note, table
|
|
|
|
|
|
|
|
// data is returned as a Table type that does not conform to the runtime.Object
|
|
|
|
|
|
|
|
// interface but is that type. So, you can't transform it into Go objects easily.
|
|
|
|
|
|
|
|
func transformRequests(req *rest.Request) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The request headers are for both the v1 and v1beta1 versions of the table
|
|
|
|
|
|
|
|
// as Kubernetes 1.14 and older used the beta version.
|
|
|
|
|
|
|
|
req.SetHeader("Accept", 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",
|
|
|
|
|
|
|
|
}, ","))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate reads Kubernetes manifests and validates the content.
|
|
|
|
// Validate reads Kubernetes manifests and validates the content.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// This function does not actually do schema validation of manifests. Adding
|
|
|
|
// This function does not actually do schema validation of manifests. Adding
|
|
|
@ -170,6 +208,7 @@ func (c *Client) Validate(namespace string, reader io.Reader) error {
|
|
|
|
DefaultNamespace().
|
|
|
|
DefaultNamespace().
|
|
|
|
// Schema(c.validator()). // No schema validation
|
|
|
|
// Schema(c.validator()). // No schema validation
|
|
|
|
Stream(reader, "").
|
|
|
|
Stream(reader, "").
|
|
|
|
|
|
|
|
Latest().
|
|
|
|
Flatten().
|
|
|
|
Flatten().
|
|
|
|
Do().Infos()
|
|
|
|
Do().Infos()
|
|
|
|
return scrubValidationError(err)
|
|
|
|
return scrubValidationError(err)
|
|
|
@ -199,7 +238,7 @@ func resourceInfoToObject(info *resource.Info, c *Client) runtime.Object {
|
|
|
|
return internalObj
|
|
|
|
return internalObj
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func sortByKey(objs map[string](map[string]runtime.Object)) []string {
|
|
|
|
func sortByKey(objs map[string][]runtime.Object) []string {
|
|
|
|
var keys []string
|
|
|
|
var keys []string
|
|
|
|
// Create a simple slice, so we can sort it
|
|
|
|
// Create a simple slice, so we can sort it
|
|
|
|
for key := range objs {
|
|
|
|
for key := range objs {
|
|
|
@ -210,24 +249,79 @@ func sortByKey(objs map[string](map[string]runtime.Object)) []string {
|
|
|
|
return keys
|
|
|
|
return keys
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We have slices of tables that need to be sorted by name. In this case the
|
|
|
|
|
|
|
|
// self link is used so the sorting will include namespace and name.
|
|
|
|
|
|
|
|
func sortTableSlice(objs []runtime.Object) []runtime.Object {
|
|
|
|
|
|
|
|
// If there are 0 or 1 objects to sort there is nothing to sort so
|
|
|
|
|
|
|
|
// the list can be returned
|
|
|
|
|
|
|
|
if len(objs) < 2 {
|
|
|
|
|
|
|
|
return objs
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ntbl := &metav1.Table{}
|
|
|
|
|
|
|
|
unstr, ok := objs[0].(*unstructured.Unstructured)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
|
|
return objs
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.Object, ntbl); err != nil {
|
|
|
|
|
|
|
|
return objs
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get gets Kubernetes resources as pretty-printed string.
|
|
|
|
// Get gets Kubernetes resources as pretty-printed string.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Namespace will set the namespace.
|
|
|
|
// Namespace will set the namespace.
|
|
|
|
func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
|
|
|
|
func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
|
|
|
|
// Since we don't know what order the objects come in, let's group them by the types and then sort them, so
|
|
|
|
// Since we don't know what order the objects come in, let's group them by the types and then sort them, so
|
|
|
|
// that when we print them, they come out looking good (headers apply to subgroups, etc.).
|
|
|
|
// that when we print them, they come out looking good (headers apply to subgroups, etc.).
|
|
|
|
objs := make(map[string](map[string]runtime.Object))
|
|
|
|
objs := make(map[string][]runtime.Object)
|
|
|
|
|
|
|
|
gk := make(map[string]schema.GroupKind)
|
|
|
|
mux := &sync.Mutex{}
|
|
|
|
mux := &sync.Mutex{}
|
|
|
|
|
|
|
|
|
|
|
|
infos, err := c.BuildUnstructured(namespace, reader)
|
|
|
|
// The contents of the reader are used two times. The bytes are coppied out
|
|
|
|
|
|
|
|
// for use in future readers.
|
|
|
|
|
|
|
|
b, err := ioutil.ReadAll(reader)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var objPods = make(map[string][]v1.Pod)
|
|
|
|
// Get the table display for the objects associated with the release. This
|
|
|
|
|
|
|
|
// is done in table format so that it can be displayed in the status in
|
|
|
|
|
|
|
|
// the same way kubectl displays the resource information.
|
|
|
|
|
|
|
|
// Note, the response returns unstructured data instead of typed objects.
|
|
|
|
|
|
|
|
// These cannot be easily (i.e., via the go packages) transformed into
|
|
|
|
|
|
|
|
// Go types.
|
|
|
|
|
|
|
|
tinfos, err := c.BuildUnstructuredTable(namespace, bytes.NewBuffer(b))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
missing := []string{}
|
|
|
|
missing := []string{}
|
|
|
|
err = perform(infos, func(info *resource.Info) error {
|
|
|
|
err = perform(tinfos, func(info *resource.Info) error {
|
|
|
|
mux.Lock()
|
|
|
|
mux.Lock()
|
|
|
|
defer mux.Unlock()
|
|
|
|
defer mux.Unlock()
|
|
|
|
c.Log("Doing get for %s: %q", info.Mapping.GroupVersionKind.Kind, info.Name)
|
|
|
|
c.Log("Doing get for %s: %q", info.Mapping.GroupVersionKind.Kind, info.Name)
|
|
|
@ -241,18 +335,36 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
|
|
|
|
// versions per cluster, but this certainly won't hurt anything, so let's be safe.
|
|
|
|
// versions per cluster, but this certainly won't hurt anything, so let's be safe.
|
|
|
|
gvk := info.ResourceMapping().GroupVersionKind
|
|
|
|
gvk := info.ResourceMapping().GroupVersionKind
|
|
|
|
vk := gvk.Version + "/" + gvk.Kind
|
|
|
|
vk := gvk.Version + "/" + gvk.Kind
|
|
|
|
|
|
|
|
gk[vk] = gvk.GroupKind()
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize map. The main map groups resources based on version/kind
|
|
|
|
// Initialize map. The main map groups resources based on version/kind
|
|
|
|
// The second level is a simple 'Name' to 'Object', that will help sort
|
|
|
|
// The second level is a simple 'Name' to 'Object', that will help sort
|
|
|
|
// the individual resource later
|
|
|
|
// the individual resource later
|
|
|
|
if objs[vk] == nil {
|
|
|
|
if objs[vk] == nil {
|
|
|
|
objs[vk] = make(map[string]runtime.Object)
|
|
|
|
objs[vk] = []runtime.Object{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Map between the resource name to the underlying info object
|
|
|
|
// Map between the resource name to the underlying info object
|
|
|
|
objs[vk][info.Name] = resourceInfoToObject(info, c)
|
|
|
|
objs[vk] = append(objs[vk], resourceInfoToObject(info, c))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This section finds related resources (e.g., pods). Before looking up pods
|
|
|
|
|
|
|
|
// the resources the pods are made from need to be looked up in a manner
|
|
|
|
|
|
|
|
// that can be turned into Go types and worked with.
|
|
|
|
|
|
|
|
infos, err := c.BuildUnstructured(namespace, bytes.NewBuffer(b))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
err = perform(infos, func(info *resource.Info) error {
|
|
|
|
|
|
|
|
mux.Lock()
|
|
|
|
|
|
|
|
defer mux.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
//Get the relation pods
|
|
|
|
//Get the relation pods
|
|
|
|
objPods, err = c.getSelectRelationPod(info, objPods)
|
|
|
|
objs, err = c.getSelectRelationPod(info, objs)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
c.Log("Warning: get the relation pod is failed, err:%s", err.Error())
|
|
|
|
c.Log("Warning: get the relation pod is failed, err:%s", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -263,25 +375,11 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
|
|
|
|
return "", err
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//here, we will add the objPods to the objs
|
|
|
|
|
|
|
|
for key, podItems := range objPods {
|
|
|
|
|
|
|
|
for i := range podItems {
|
|
|
|
|
|
|
|
pod := &core.Pod{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scheme.Scheme.Convert(&podItems[i], pod, nil)
|
|
|
|
|
|
|
|
if objs[key+"(related)"] == nil {
|
|
|
|
|
|
|
|
objs[key+"(related)"] = make(map[string]runtime.Object)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
objs[key+"(related)"][pod.ObjectMeta.Name] = runtime.Object(pod)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ok, now we have all the objects grouped by types (say, by v1/Pod, v1/Service, etc.), so
|
|
|
|
// Ok, now we have all the objects grouped by types (say, by v1/Pod, v1/Service, etc.), so
|
|
|
|
// spin through them and print them. Printer is cool since it prints the header only when
|
|
|
|
// spin through them and print them. Printer is cool since it prints the header only when
|
|
|
|
// an object type changes, so we can just rely on that. Problem is it doesn't seem to keep
|
|
|
|
// an object type changes, so we can just rely on that. Problem is it doesn't seem to keep
|
|
|
|
// track of tab widths.
|
|
|
|
// track of tab widths.
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
printFlags := get.NewHumanPrintFlags()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sort alphabetically by version/kind keys
|
|
|
|
// Sort alphabetically by version/kind keys
|
|
|
|
vkKeys := sortByKey(objs)
|
|
|
|
vkKeys := sortByKey(objs)
|
|
|
@ -290,20 +388,29 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
|
|
|
|
if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil {
|
|
|
|
if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil {
|
|
|
|
return "", err
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
typePrinter, _ := printFlags.ToPrinter("")
|
|
|
|
vk := objs[t]
|
|
|
|
|
|
|
|
|
|
|
|
var sortedResources []string
|
|
|
|
// The request made for tables returns each Kubernetes object as its
|
|
|
|
for resource := range objs[t] {
|
|
|
|
// own table. The normal sorting provided by kubectl and cli-runtime
|
|
|
|
sortedResources = append(sortedResources, resource)
|
|
|
|
// does not handle this case. Here we sort within each of our own
|
|
|
|
|
|
|
|
// grouping.
|
|
|
|
|
|
|
|
vk = sortTableSlice(vk)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The printer flag setup follows a simalar setup to kubectl
|
|
|
|
|
|
|
|
printFlags := get.NewHumanPrintFlags()
|
|
|
|
|
|
|
|
if lgk, ok := gk[t]; ok {
|
|
|
|
|
|
|
|
printFlags.SetKind(lgk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Strings(sortedResources)
|
|
|
|
printer, _ := printFlags.ToPrinter("")
|
|
|
|
|
|
|
|
printer, err = printers.NewTypeSetter(scheme.Scheme).WrapToPrinter(printer, nil)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
printer = &get.TablePrinter{Delegate: printer}
|
|
|
|
|
|
|
|
|
|
|
|
// Now that each individual resource within the specific version/kind
|
|
|
|
for _, resource := range vk {
|
|
|
|
// is sorted, we print each resource using the k8s printer
|
|
|
|
if err := printer.PrintObj(resource, buf); err != nil {
|
|
|
|
vk := objs[t]
|
|
|
|
c.Log("failed to print object type %s: %v", t, err)
|
|
|
|
for _, resourceName := range sortedResources {
|
|
|
|
|
|
|
|
if err := typePrinter.PrintObj(vk[resourceName], buf); err != nil {
|
|
|
|
|
|
|
|
c.Log("failed to print object type %s, object: %q :\n %v", t, resourceName, err)
|
|
|
|
|
|
|
|
return "", err
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -985,11 +1092,11 @@ func isPodComplete(event watch.Event) (bool, error) {
|
|
|
|
return false, nil
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//get a kubernetes resources' relation pods
|
|
|
|
// get a kubernetes resources' relation pods
|
|
|
|
// kubernetes resource used select labels to relate pods
|
|
|
|
// kubernetes resource used select labels to relate pods
|
|
|
|
func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][]v1.Pod) (map[string][]v1.Pod, error) {
|
|
|
|
func (c *Client) getSelectRelationPod(info *resource.Info, objs map[string][]runtime.Object) (map[string][]runtime.Object, error) {
|
|
|
|
if info == nil {
|
|
|
|
if info == nil {
|
|
|
|
return objPods, nil
|
|
|
|
return objs, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name)
|
|
|
|
c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name)
|
|
|
@ -997,34 +1104,31 @@ func (c *Client) getSelectRelationPod(info *resource.Info, objPods map[string][]
|
|
|
|
versioned := asVersionedOrUnstructured(info)
|
|
|
|
versioned := asVersionedOrUnstructured(info)
|
|
|
|
selector, ok := getSelectorFromObject(versioned)
|
|
|
|
selector, ok := getSelectorFromObject(versioned)
|
|
|
|
if !ok {
|
|
|
|
if !ok {
|
|
|
|
return objPods, nil
|
|
|
|
return objs, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
client, _ := c.KubernetesClientSet()
|
|
|
|
// The related pods are looked up in Table format so that their display can
|
|
|
|
|
|
|
|
// be printed in a manner similar to kubectl when it get pods. The response
|
|
|
|
pods, err := client.CoreV1().Pods(info.Namespace).List(metav1.ListOptions{
|
|
|
|
// can be used with a table printer.
|
|
|
|
LabelSelector: labels.Set(selector).AsSelector().String(),
|
|
|
|
infos, err := c.NewBuilder().
|
|
|
|
})
|
|
|
|
Unstructured().
|
|
|
|
|
|
|
|
ContinueOnError().
|
|
|
|
|
|
|
|
NamespaceParam(info.Namespace).
|
|
|
|
|
|
|
|
DefaultNamespace().
|
|
|
|
|
|
|
|
ResourceTypes("pods").
|
|
|
|
|
|
|
|
LabelSelector(labels.Set(selector).AsSelector().String()).
|
|
|
|
|
|
|
|
TransformRequests(transformRequests).
|
|
|
|
|
|
|
|
Do().Infos()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return objPods, err
|
|
|
|
return objs, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, pod := range pods.Items {
|
|
|
|
for _, info := range infos {
|
|
|
|
vk := "v1/Pod"
|
|
|
|
vk := "v1/Pod(related)"
|
|
|
|
if !isFoundPod(objPods[vk], pod) {
|
|
|
|
objs[vk] = append(objs[vk], info.Object)
|
|
|
|
objPods[vk] = append(objPods[vk], pod)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return objPods, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func isFoundPod(podItem []v1.Pod, pod v1.Pod) bool {
|
|
|
|
return objs, nil
|
|
|
|
for _, value := range podItem {
|
|
|
|
|
|
|
|
if (value.Namespace == pod.Namespace) && (value.Name == pod.Name) {
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func asVersionedOrUnstructured(info *resource.Info) runtime.Object {
|
|
|
|
func asVersionedOrUnstructured(info *resource.Info) runtime.Object {
|
|
|
|