Merge pull request #41729 from smarterclayton/refactor_printers
Automatic merge from submit-queue (batch tested with PRs 41621, 41946, 41941, 41250, 41729) Refactor printers and describers into their own package. This sets the stage for using printer code from the server side (decoupled from kubectl) and loosens the coupling between kubectl and the printers. `pkg/printers` contains interfaces and has an import restriction against pulling in API specific code, while `pkg/printers/internalversion` can be used for internal types. Add a method on `Factory` for retrieving PrinterForCommand which uses the Scheme and RESTMapper from the Factory, not the hardcoded ones. This further separates kubectl from the core API scheme and allows better composition. Change NamePrinter to use RESTMapper (previously it was hardcoding those conversions). This means that we now return plural resource names (`pods/foo`) but is correct once aliases and shortnames start being returned by the mapper. This is a prerequisite for server side get, but is pure refactor (contains no new features). @deads2k @liggitt
This commit is contained in:
@@ -38,8 +38,8 @@ go_library(
|
||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||
"//cmd/kubeadm/app/util/token:go_default_library",
|
||||
"//pkg/bootstrap/api:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util/initsystem:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor:github.com/blang/semver",
|
||||
|
@@ -37,7 +37,7 @@ import (
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
|
||||
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
|
||||
@@ -207,7 +207,7 @@ func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing expiration time [%v]", err)
|
||||
}
|
||||
expires = kubectl.ShortHumanDuration(expireTime.Sub(time.Now()))
|
||||
expires = printers.ShortHumanDuration(expireTime.Sub(time.Now()))
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", tokenId, tokenutil.BearerToken(td), expires)
|
||||
}
|
||||
|
@@ -180,6 +180,7 @@ pkg/kubelet/volumemanager/cache
|
||||
pkg/kubelet/volumemanager/populator
|
||||
pkg/kubelet/volumemanager/reconciler
|
||||
pkg/labels
|
||||
pkg/printers
|
||||
pkg/proxy/config
|
||||
pkg/proxy/healthcheck
|
||||
pkg/quota
|
||||
|
@@ -92,6 +92,7 @@ filegroup(
|
||||
"//pkg/labels:all-srcs",
|
||||
"//pkg/master:all-srcs",
|
||||
"//pkg/metrics:all-srcs",
|
||||
"//pkg/printers:all-srcs",
|
||||
"//pkg/probe:all-srcs",
|
||||
"//pkg/proxy:all-srcs",
|
||||
"//pkg/quota:all-srcs",
|
||||
|
@@ -13,7 +13,7 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||
|
@@ -30,7 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
|
||||
@@ -94,7 +94,7 @@ func TestCompatibility(
|
||||
}
|
||||
|
||||
if hasError {
|
||||
printer := new(kubectl.JSONPrinter)
|
||||
printer := &printers.JSONPrinter{}
|
||||
printer.PrintObj(obj, os.Stdout)
|
||||
t.Logf("2: Encoded value: %#v", string(output))
|
||||
}
|
||||
|
@@ -63,6 +63,7 @@ go_test(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/api/testing/compat:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
|
@@ -25,6 +25,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/testing/compat"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
)
|
||||
|
||||
func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
|
||||
|
@@ -17,9 +17,7 @@ go_library(
|
||||
"cluster.go",
|
||||
"clusterrolebinding.go",
|
||||
"configmap.go",
|
||||
"custom_column_printer.go",
|
||||
"deployment.go",
|
||||
"describe.go",
|
||||
"doc.go",
|
||||
"explain.go",
|
||||
"generate.go",
|
||||
@@ -31,7 +29,6 @@ go_library(
|
||||
"proxy_server.go",
|
||||
"quota.go",
|
||||
"resource_filter.go",
|
||||
"resource_printer.go",
|
||||
"rolebinding.go",
|
||||
"rollback.go",
|
||||
"rolling_updater.go",
|
||||
@@ -44,31 +41,24 @@ go_library(
|
||||
"service.go",
|
||||
"service_basic.go",
|
||||
"serviceaccount.go",
|
||||
"sorted_resource_name_list.go",
|
||||
"sorting_printer.go",
|
||||
"stop.go",
|
||||
"versioned_client.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/annotations:go_default_library",
|
||||
"//pkg/api/events:go_default_library",
|
||||
"//pkg/api/util:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/certificates:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/apis/storage/util:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/extensions/v1beta1:go_default_library",
|
||||
@@ -81,14 +71,12 @@ go_library(
|
||||
"//pkg/client/unversioned:go_default_library",
|
||||
"//pkg/controller/deployment/util:go_default_library",
|
||||
"//pkg/credentialprovider:go_default_library",
|
||||
"//pkg/fieldpath:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubelet/qos:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/slice:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:github.com/ghodss/yaml",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:github.com/spf13/pflag",
|
||||
@@ -104,12 +92,10 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/uuid",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/validation",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/integer",
|
||||
"//vendor:k8s.io/client-go/util/jsonpath",
|
||||
@@ -121,15 +107,12 @@ go_test(
|
||||
srcs = [
|
||||
"cluster_test.go",
|
||||
"configmap_test.go",
|
||||
"custom_column_printer_test.go",
|
||||
"deployment_test.go",
|
||||
"describe_test.go",
|
||||
"generate_test.go",
|
||||
"kubectl_test.go",
|
||||
"namespace_test.go",
|
||||
"proxy_server_test.go",
|
||||
"quota_test.go",
|
||||
"resource_printer_test.go",
|
||||
"rolling_updater_test.go",
|
||||
"rollout_status_test.go",
|
||||
"run_test.go",
|
||||
@@ -140,46 +123,32 @@ go_test(
|
||||
"service_basic_test.go",
|
||||
"service_test.go",
|
||||
"serviceaccount_test.go",
|
||||
"sorted_resource_name_list_test.go",
|
||||
"sorting_printer_test.go",
|
||||
"stop_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/testing:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
|
||||
"//pkg/controller/deployment/util:go_default_library",
|
||||
"//pkg/kubectl/testing:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//vendor:github.com/ghodss/yaml",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/equality",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/yaml",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
|
@@ -90,6 +90,8 @@ go_library(
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/kubelet/server/remotecommand:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util/crlf:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/i18n:go_default_library",
|
||||
@@ -198,6 +200,8 @@ go_test(
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//pkg/util/term:go_default_library",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
@@ -208,6 +212,7 @@ go_test(
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json",
|
||||
|
@@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -101,7 +102,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
|
@@ -26,9 +26,9 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -93,10 +93,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, args []string, out i
|
||||
return err
|
||||
}
|
||||
|
||||
printer, _, err := kubectl.GetPrinter("json", "", false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer := &printers.JSONPrinter{}
|
||||
|
||||
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
|
@@ -35,9 +35,10 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
"k8s.io/kubernetes/pkg/util/strings"
|
||||
)
|
||||
|
||||
@@ -97,12 +98,12 @@ func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
|
||||
|
||||
type testDescriber struct {
|
||||
Name, Namespace string
|
||||
Settings kubectl.DescriberSettings
|
||||
Settings printers.DescriberSettings
|
||||
Output string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (t *testDescriber) Describe(namespace, name string, describerSettings kubectl.DescriberSettings) (output string, err error) {
|
||||
func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
t.Namespace, t.Name = namespace, name
|
||||
t.Settings = describerSettings
|
||||
return t.Output, t.Err
|
||||
@@ -146,10 +147,12 @@ func stringBody(body string) io.ReadCloser {
|
||||
|
||||
func Example_printReplicationControllerWithNamespace() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
WithNamespace: true,
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -197,10 +200,12 @@ func Example_printReplicationControllerWithNamespace() {
|
||||
|
||||
func Example_printMultiContainersReplicationControllerWithWide() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
Wide: true,
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -250,9 +255,11 @@ func Example_printMultiContainersReplicationControllerWithWide() {
|
||||
|
||||
func Example_printReplicationController() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -302,10 +309,12 @@ func Example_printReplicationController() {
|
||||
|
||||
func Example_printPodWithWideFormat() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
Wide: true,
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -343,10 +352,12 @@ func Example_printPodWithWideFormat() {
|
||||
|
||||
func Example_printPodWithShowLabels() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ShowLabels: true,
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -479,9 +490,11 @@ func newAllPhasePodList() *api.PodList {
|
||||
|
||||
func Example_printPodHideTerminated() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -512,10 +525,12 @@ func Example_printPodHideTerminated() {
|
||||
|
||||
func Example_printPodShowAll() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ShowAll: true,
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -539,10 +554,12 @@ func Example_printPodShowAll() {
|
||||
|
||||
func Example_printServiceWithNamespacesAndLabels() {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{
|
||||
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
WithNamespace: true,
|
||||
ColumnLabels: []string{"l1"},
|
||||
})
|
||||
printersinternal.AddHandlers(p)
|
||||
tf.Printer = p
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
|
@@ -28,11 +28,13 @@ go_library(
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util/i18n:go_default_library",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||
|
@@ -52,7 +52,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *co
|
||||
// file paths are common to all sub commands
|
||||
cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
|
||||
|
||||
cmd.AddCommand(NewCmdConfigView(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigView(out, errOut, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions))
|
||||
cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions))
|
||||
|
@@ -23,13 +23,14 @@ import (
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -108,7 +109,7 @@ func (o GetContextsOptions) RunGetContexts() error {
|
||||
|
||||
out, found := o.out.(*tabwriter.Writer)
|
||||
if !found {
|
||||
out = kubectl.GetNewTabWriter(o.out)
|
||||
out = printers.GetNewTabWriter(o.out)
|
||||
defer out.Flush()
|
||||
}
|
||||
|
||||
|
@@ -23,13 +23,15 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/clientcmd/api/latest"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -55,7 +57,7 @@ var (
|
||||
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`)
|
||||
)
|
||||
|
||||
func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
func NewCmdConfigView(out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
|
||||
options := &ViewOptions{ConfigAccess: ConfigAccess}
|
||||
// Default to yaml
|
||||
defaultOutputFormat := "yaml"
|
||||
@@ -69,17 +71,19 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra
|
||||
options.Complete()
|
||||
outputFormat := cmdutil.GetFlagString(cmd, "output")
|
||||
if outputFormat == "wide" {
|
||||
fmt.Printf("--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
|
||||
fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
if outputFormat == "" {
|
||||
fmt.Printf("Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
|
||||
fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
|
||||
printer, _, err := cmdutil.PrinterForCommand(cmd)
|
||||
printer, _, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, []runtime.Decoder{latest.Codec})
|
||||
cmdutil.CheckErr(err)
|
||||
printer = kubectl.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
|
||||
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
|
||||
|
||||
cmdutil.CheckErr(options.Run(out, printer))
|
||||
},
|
||||
@@ -97,7 +101,7 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o ViewOptions) Run(out io.Writer, printer kubectl.ResourcePrinter) error {
|
||||
func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error {
|
||||
config, err := o.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -25,10 +25,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -96,7 +96,7 @@ type ConvertOptions struct {
|
||||
|
||||
encoder runtime.Encoder
|
||||
out io.Writer
|
||||
printer kubectl.ResourcePrinter
|
||||
printer printers.ResourcePrinter
|
||||
|
||||
outputVersion schema.GroupVersion
|
||||
}
|
||||
@@ -160,9 +160,11 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
} else {
|
||||
outputFormat = "template"
|
||||
}
|
||||
// TODO: once printing is abstracted, this should be handled at flag declaration time
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
}
|
||||
o.encoder = f.JSONEncoder()
|
||||
o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false, cmdutil.GetFlagBool(cmd, "allow-missing-template-keys"))
|
||||
o.printer, _, err = f.PrinterForCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -117,7 +118,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
|
@@ -33,6 +33,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -72,9 +74,11 @@ var (
|
||||
|
||||
func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
describerSettings := &kubectl.DescriberSettings{}
|
||||
describerSettings := &printers.DescriberSettings{}
|
||||
|
||||
validArgs := kubectl.DescribableResources()
|
||||
// TODO: this should come from the factory, and may need to be loaded from the server, and so is probably
|
||||
// going to have to be removed
|
||||
validArgs := printersinternal.DescribableResources()
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -98,7 +102,7 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *kubectl.DescriberSettings) error {
|
||||
func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *printers.DescriberSettings) error {
|
||||
selector := cmdutil.GetFlagString(cmd, "selector")
|
||||
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
@@ -172,7 +176,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *kubectl.DescriberSettings, out io.Writer, originalError error) error {
|
||||
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error {
|
||||
mapper, typer, err := f.UnstructuredObject()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -43,6 +43,7 @@ import (
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/crlf"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
|
||||
@@ -92,7 +93,7 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
@@ -343,14 +344,14 @@ func getPrinter(cmd *cobra.Command) (*editPrinterOptions, error) {
|
||||
switch format := cmdutil.GetFlagString(cmd, "output"); format {
|
||||
case "json":
|
||||
return &editPrinterOptions{
|
||||
printer: &kubectl.JSONPrinter{},
|
||||
printer: &printers.JSONPrinter{},
|
||||
ext: ".json",
|
||||
addHeader: false,
|
||||
}, nil
|
||||
// If flag -o is not specified, use yaml as default
|
||||
case "yaml", "":
|
||||
return &editPrinterOptions{
|
||||
printer: &kubectl.YAMLPrinter{},
|
||||
printer: &printers.YAMLPrinter{},
|
||||
ext: ".yaml",
|
||||
addHeader: true,
|
||||
}, nil
|
||||
@@ -589,7 +590,7 @@ func (h *editHeader) flush() {
|
||||
}
|
||||
|
||||
type editPrinterOptions struct {
|
||||
printer kubectl.ResourcePrinter
|
||||
printer printers.ResourcePrinter
|
||||
ext string
|
||||
addHeader bool
|
||||
}
|
||||
|
@@ -28,8 +28,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func TestRunExposeService(t *testing.T) {
|
||||
@@ -460,7 +460,7 @@ func TestRunExposeService(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &kubectl.JSONPrinter{}
|
||||
tf.Printer = &printers.JSONPrinter{}
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
|
@@ -34,6 +34,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||
)
|
||||
@@ -95,7 +96,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
@@ -303,7 +304,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
return err
|
||||
}
|
||||
|
||||
printer, generic, err := cmdutil.PrinterForCommand(cmd)
|
||||
printer, generic, err := f.PrinterForCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -430,7 +431,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
// use the default printer for each object
|
||||
printer = nil
|
||||
var lastMapping *meta.RESTMapping
|
||||
w := kubectl.GetNewTabWriter(out)
|
||||
w := printers.GetNewTabWriter(out)
|
||||
filteredResourceCount := 0
|
||||
|
||||
if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) {
|
||||
@@ -486,7 +487,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
}
|
||||
}
|
||||
|
||||
if resourcePrinter, found := printer.(*kubectl.HumanReadablePrinter); found {
|
||||
if resourcePrinter, found := printer.(*printers.HumanReadablePrinter); found {
|
||||
resourceName := resourcePrinter.GetResourceKind()
|
||||
if mapping != nil {
|
||||
if resourceName == "" {
|
||||
|
@@ -29,6 +29,7 @@ import (
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
@@ -506,7 +507,8 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
pods, svc, _ := testData()
|
||||
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
tf.CommandPrinter = &testPrinter{}
|
||||
tf.GenericPrinter = true
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
@@ -533,34 +535,37 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
||||
cmd.Flags().Set("output", "json")
|
||||
cmd.Run(cmd, []string{"pods,services"})
|
||||
|
||||
if tf.Printer.(*testPrinter).Objects != nil {
|
||||
t.Errorf("unexpected print to default printer")
|
||||
actual := tf.CommandPrinter.(*testPrinter).Objects
|
||||
fn := func(obj runtime.Object) *unstructured.Unstructured {
|
||||
data, err := runtime.Encode(api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"}), obj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
out := &unstructured.Unstructured{Object: make(map[string]interface{})}
|
||||
if err := encjson.Unmarshal(data, &out.Object); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
out, err := runtime.Decode(codec, buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
list, err := meta.ExtractList(out)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if errs := runtime.DecodeList(list, codec); len(errs) > 0 {
|
||||
t.Fatalf("unexpected error: %v", errs)
|
||||
}
|
||||
if err := meta.SetList(out, list); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expected := &api.List{
|
||||
Items: []runtime.Object{
|
||||
&pods.Items[0],
|
||||
&pods.Items[1],
|
||||
&svc.Items[0],
|
||||
expected := &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{"kind": "List", "apiVersion": "v1", "metadata": map[string]interface{}{}, "selfLink": "", "resourceVersion": ""},
|
||||
Items: []*unstructured.Unstructured{
|
||||
fn(&pods.Items[0]),
|
||||
fn(&pods.Items[1]),
|
||||
fn(&svc.Items[0]),
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expected, out) {
|
||||
t.Errorf("unexpected output: %#v", out)
|
||||
actualBytes, err := encjson.Marshal(actual[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedBytes, err := encjson.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(actualBytes) != string(expectedBytes) {
|
||||
t.Errorf("unexpected object:\n%s\n%s", expectedBytes, actualBytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -99,7 +100,7 @@ func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
|
@@ -39,6 +39,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
)
|
||||
|
||||
@@ -81,7 +82,7 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
|
||||
// retrieve a list of handled resources from printer as valid args
|
||||
validArgs, argAliases := []string{}, []string{}
|
||||
p, err := f.Printer(nil, kubectl.PrintOptions{
|
||||
p, err := f.Printer(nil, printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
})
|
||||
cmdutil.CheckErr(err)
|
||||
|
@@ -56,6 +56,7 @@ go_test(
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
|
@@ -22,16 +22,17 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func TestImageLocal(t *testing.T) {
|
||||
f, tf, _, ns := cmdtesting.NewAPIFactory()
|
||||
f, tf, codec, ns := cmdtesting.NewAPIFactory()
|
||||
tf.Client = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
@@ -47,7 +48,8 @@ func TestImageLocal(t *testing.T) {
|
||||
cmd := NewCmdImage(f, buf, buf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set("output", "name")
|
||||
tf.Printer, _, _ = cmdutil.PrinterForCommand(cmd)
|
||||
mapper, typer := f.Object()
|
||||
tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{codec}, Typer: typer, Mapper: mapper}
|
||||
|
||||
opts := ImageOptions{FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../../examples/storage/cassandra/cassandra-controller.yaml"}},
|
||||
@@ -63,7 +65,7 @@ func TestImageLocal(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), "replicationcontroller/cassandra") {
|
||||
if !strings.Contains(buf.String(), "replicationcontrollers/cassandra") {
|
||||
t.Errorf("did not set image: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ go_library(
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:github.com/spf13/pflag",
|
||||
|
@@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type InternalType struct {
|
||||
@@ -214,13 +215,15 @@ type TestFactory struct {
|
||||
Typer runtime.ObjectTyper
|
||||
Client kubectl.RESTClient
|
||||
UnstructuredClient kubectl.RESTClient
|
||||
Describer kubectl.Describer
|
||||
Printer kubectl.ResourcePrinter
|
||||
Describer printers.Describer
|
||||
Printer printers.ResourcePrinter
|
||||
CommandPrinter printers.ResourcePrinter
|
||||
Validator validation.Schema
|
||||
Namespace string
|
||||
ClientConfig *restclient.Config
|
||||
Err error
|
||||
Command string
|
||||
GenericPrinter bool
|
||||
|
||||
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
@@ -331,11 +334,15 @@ func (f *FakeFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (r
|
||||
return f.tf.UnstructuredClient, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *FakeFactory) Describer(*meta.RESTMapping) (kubectl.Describer, error) {
|
||||
func (f *FakeFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
||||
return f.tf.Describer, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
|
||||
func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
||||
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@@ -451,7 +458,7 @@ func (f *FakeFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, ob
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
|
||||
func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@@ -459,8 +466,8 @@ func (f *FakeFactory) NewBuilder() *resource.Builder {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions {
|
||||
return &kubectl.PrintOptions{}
|
||||
func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions {
|
||||
return &printers.PrintOptions{}
|
||||
}
|
||||
|
||||
func (f *FakeFactory) DefaultResourceFilterFunc() kubectl.Filters {
|
||||
@@ -587,11 +594,15 @@ func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (reso
|
||||
return f.tf.UnstructuredClient, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (kubectl.Describer, error) {
|
||||
func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
||||
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
||||
return f.tf.Describer, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
|
||||
func (f *fakeAPIFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@@ -664,7 +675,7 @@ func (f *fakeAPIFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper,
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
|
||||
func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
|
@@ -38,6 +38,8 @@ go_library(
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/printers/internalversion:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -136,7 +137,8 @@ type ClientAccessFactory interface {
|
||||
// BindExternalFlags adds any flags defined by external projects (not part of pflags)
|
||||
BindExternalFlags(flags *pflag.FlagSet)
|
||||
|
||||
DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions
|
||||
// TODO: Break the dependency on cmd here.
|
||||
DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions
|
||||
// DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types.
|
||||
DefaultResourceFilterFunc() kubectl.Filters
|
||||
|
||||
@@ -144,7 +146,7 @@ type ClientAccessFactory interface {
|
||||
SuggestedPodTemplateResources() []schema.GroupResource
|
||||
|
||||
// Returns a Printer for formatting objects of the given type or an error.
|
||||
Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error)
|
||||
Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error)
|
||||
// Pauser marks the object in the info as paused. Currently supported only for Deployments.
|
||||
// Returns the patched object in bytes and any error that occured during the encoding or
|
||||
// in case the object is already paused.
|
||||
@@ -193,7 +195,7 @@ type ObjectMappingFactory interface {
|
||||
// Returns a RESTClient for working with Unstructured objects.
|
||||
UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||
Describer(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||
Describer(mapping *meta.RESTMapping) (printers.Describer, error)
|
||||
|
||||
// LogsForObject returns a request for the logs associated with the provided object
|
||||
LogsForObject(object, options runtime.Object) (*restclient.Request, error)
|
||||
@@ -211,10 +213,6 @@ type ObjectMappingFactory interface {
|
||||
// AttachablePodForObject returns the pod to which to attach given an object.
|
||||
AttachablePodForObject(object runtime.Object) (*api.Pod, error)
|
||||
|
||||
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error)
|
||||
|
||||
// Returns a schema that can validate objects stored on disk.
|
||||
Validator(validate bool, cacheDir string) (validation.Schema, error)
|
||||
// SwaggerSchema returns the schema declaration for the provided group version kind.
|
||||
@@ -224,6 +222,14 @@ type ObjectMappingFactory interface {
|
||||
// BuilderFactory holds the second level of factory methods. These functions depend upon ObjectMappingFactory and ClientAccessFactory methods.
|
||||
// Generally they depend upon client mapper functions
|
||||
type BuilderFactory interface {
|
||||
// PrinterForCommand returns the default printer for the command. It requires that certain options
|
||||
// are declared on the command (see AddPrinterFlags). Returns a printer, true if the printer is
|
||||
// generic (is not internal), or an error if a printer could not be found.
|
||||
// TODO: Break the dependency on cmd here.
|
||||
PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error)
|
||||
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
|
||||
// PrintObject prints an api object given command line flags to modify the output format
|
||||
PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error
|
||||
// One stop shopping for a Builder
|
||||
|
@@ -19,13 +19,16 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
type ring2Factory struct {
|
||||
@@ -42,6 +45,54 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
|
||||
mapper, typer := f.objectMappingFactory.Object()
|
||||
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
||||
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
||||
return PrinterForCommand(cmd, mapper, typer, decoders)
|
||||
}
|
||||
|
||||
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
printer, generic, err := f.PrinterForCommand(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure we output versioned data for generic printers
|
||||
if generic {
|
||||
if mapping == nil {
|
||||
return nil, fmt.Errorf("no serialization format found")
|
||||
}
|
||||
version := mapping.GroupVersionKind.GroupVersion()
|
||||
if version.Empty() {
|
||||
return nil, fmt.Errorf("no serialization format found")
|
||||
}
|
||||
|
||||
printer = printers.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
||||
} else {
|
||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||
if err != nil {
|
||||
columnLabel = []string{}
|
||||
}
|
||||
printer, err = f.clientAccessFactory.Printer(mapping, printers.PrintOptions{
|
||||
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
||||
WithNamespace: withNamespace,
|
||||
Wide: GetWideFlag(cmd),
|
||||
ShowAll: GetFlagBool(cmd, "show-all"),
|
||||
ShowLabels: GetFlagBool(cmd, "show-labels"),
|
||||
AbsoluteTimestamps: isWatch(cmd),
|
||||
ColumnLabels: columnLabel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printer = maybeWrapSortingPrinter(cmd, printer)
|
||||
}
|
||||
|
||||
return printer, nil
|
||||
}
|
||||
|
||||
func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
|
||||
// try to get a typed object
|
||||
_, typer := f.objectMappingFactory.Object()
|
||||
@@ -66,7 +117,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, o
|
||||
return err
|
||||
}
|
||||
|
||||
printer, err := f.objectMappingFactory.PrinterForMapping(cmd, mapping, false)
|
||||
printer, err := f.PrinterForMapping(cmd, mapping, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -49,6 +49,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
)
|
||||
|
||||
type ring0Factory struct {
|
||||
@@ -360,12 +362,12 @@ func (f *ring0Factory) BindExternalFlags(flags *pflag.FlagSet) {
|
||||
flags.AddGoFlagSet(flag.CommandLine)
|
||||
}
|
||||
|
||||
func (f *ring0Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions {
|
||||
func (f *ring0Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions {
|
||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||
if err != nil {
|
||||
columnLabel = []string{}
|
||||
}
|
||||
opts := &kubectl.PrintOptions{
|
||||
opts := &printers.PrintOptions{
|
||||
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
||||
WithNamespace: withNamespace,
|
||||
Wide: GetWideFlag(cmd),
|
||||
@@ -392,8 +394,10 @@ func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *ring0Factory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
|
||||
return kubectl.NewHumanReadablePrinter(options), nil
|
||||
func (f *ring0Factory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
p := printers.NewHumanReadablePrinter(options)
|
||||
printersinternal.AddHandlers(p)
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (f *ring0Factory) Pauser(info *resource.Info) ([]byte, error) {
|
||||
|
@@ -27,7 +27,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -48,6 +47,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
)
|
||||
|
||||
type ring1Factory struct {
|
||||
@@ -58,10 +59,12 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp
|
||||
f := &ring1Factory{
|
||||
clientAccessFactory: clientAccessFactory,
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// TODO: This method should return an error now that it can fail. Alternatively, it needs to
|
||||
// return lazy implementations of mapper and typer that don't hit the wire until they are
|
||||
// invoked.
|
||||
func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
mapper := api.Registry.RESTMapper()
|
||||
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
|
||||
@@ -143,7 +146,7 @@ func (f *ring1Factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (
|
||||
return restclient.RESTClientFor(cfg)
|
||||
}
|
||||
|
||||
func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) {
|
||||
func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (printers.Describer, error) {
|
||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||
if mapping.GroupVersionKind.Group == federation.GroupName {
|
||||
fedClientSet, err := f.clientAccessFactory.FederationClientSetForVersion(&mappingVersion)
|
||||
@@ -151,7 +154,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
|
||||
return nil, err
|
||||
}
|
||||
if mapping.GroupVersionKind.Kind == "Cluster" {
|
||||
return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil
|
||||
return &printersinternal.ClusterDescriber{Interface: fedClientSet}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +169,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
|
||||
}
|
||||
|
||||
// try to get a describer
|
||||
if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok {
|
||||
if describer, ok := printersinternal.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok {
|
||||
return describer, nil
|
||||
}
|
||||
// if this is a kind we don't have a describer for yet, go generic if possible
|
||||
@@ -178,7 +181,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
|
||||
}
|
||||
|
||||
// helper function to make a generic describer, or return an error
|
||||
func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RESTMapping) (kubectl.Describer, error) {
|
||||
func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RESTMapping) (printers.Describer, error) {
|
||||
clientConfig, err := clientAccessFactory.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -202,7 +205,7 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES
|
||||
}
|
||||
eventsClient := clientSet.Core()
|
||||
|
||||
return kubectl.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
|
||||
return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
|
||||
}
|
||||
|
||||
func (f *ring1Factory) LogsForObject(object, options runtime.Object) (*restclient.Request, error) {
|
||||
@@ -361,48 +364,6 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object) (*api.Pod,
|
||||
return pod, err
|
||||
}
|
||||
|
||||
func (f *ring1Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
|
||||
printer, generic, err := PrinterForCommand(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure we output versioned data for generic printers
|
||||
if generic {
|
||||
if mapping == nil {
|
||||
return nil, fmt.Errorf("no serialization format found")
|
||||
}
|
||||
version := mapping.GroupVersionKind.GroupVersion()
|
||||
if version.Empty() {
|
||||
return nil, fmt.Errorf("no serialization format found")
|
||||
}
|
||||
|
||||
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
|
||||
|
||||
} else {
|
||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||
if err != nil {
|
||||
columnLabel = []string{}
|
||||
}
|
||||
printer, err = f.clientAccessFactory.Printer(mapping, kubectl.PrintOptions{
|
||||
NoHeaders: GetFlagBool(cmd, "no-headers"),
|
||||
WithNamespace: withNamespace,
|
||||
Wide: GetWideFlag(cmd),
|
||||
ShowAll: GetFlagBool(cmd, "show-all"),
|
||||
ShowLabels: GetFlagBool(cmd, "show-labels"),
|
||||
AbsoluteTimestamps: isWatch(cmd),
|
||||
ColumnLabels: columnLabel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printer = maybeWrapSortingPrinter(cmd, printer)
|
||||
}
|
||||
|
||||
return printer, nil
|
||||
}
|
||||
|
||||
func (f *ring1Factory) Validator(validate bool, cacheDir string) (validation.Schema, error) {
|
||||
if validate {
|
||||
discovery, err := f.clientAccessFactory.DiscoveryClient()
|
||||
|
@@ -47,6 +47,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
@@ -672,7 +673,7 @@ func MustPrintWithKinds(objs []runtime.Object, infos []*resource.Info, sorter *k
|
||||
|
||||
// FilterResourceList receives a list of runtime objects.
|
||||
// If any objects are filtered, that number is returned along with a modified list.
|
||||
func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *kubectl.PrintOptions) (int, []runtime.Object, error) {
|
||||
func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *printers.PrintOptions) (int, []runtime.Object, error) {
|
||||
items, err := meta.ExtractList(obj)
|
||||
if err != nil {
|
||||
return 0, []runtime.Object{obj}, utilerrors.NewAggregate([]error{err})
|
||||
@@ -697,7 +698,7 @@ func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterO
|
||||
return filterCount, list, nil
|
||||
}
|
||||
|
||||
func PrintFilterCount(hiddenObjNum int, resource string, options *kubectl.PrintOptions) {
|
||||
func PrintFilterCount(hiddenObjNum int, resource string, options *printers.PrintOptions) {
|
||||
if !options.NoHeaders && !options.ShowAll && hiddenObjNum > 0 {
|
||||
glog.V(2).Infof(" info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", hiddenObjNum, resource)
|
||||
}
|
||||
|
@@ -22,8 +22,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -105,7 +107,7 @@ func ValidateOutputArgs(cmd *cobra.Command) error {
|
||||
|
||||
// PrinterForCommand returns the default printer for this command.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) {
|
||||
func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (printers.ResourcePrinter, bool, error) {
|
||||
outputFormat := GetFlagString(cmd, "output")
|
||||
|
||||
// templates are logically optional for specifying a format.
|
||||
@@ -131,7 +133,10 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error
|
||||
if cmd.Flags().Lookup("allow-missing-template-keys") != nil {
|
||||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
|
||||
}
|
||||
printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys)
|
||||
printer, generic, err := printers.GetStandardPrinter(
|
||||
outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys,
|
||||
mapper, typer, decoders,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, generic, err
|
||||
}
|
||||
@@ -144,7 +149,7 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error
|
||||
// object passed is non-generic, it attempts to print the object using a HumanReadablePrinter.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error {
|
||||
printer, generic, err := PrinterForCommand(cmd)
|
||||
printer, generic, err := f.PrinterForCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -157,7 +162,7 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact
|
||||
return printer.PrintObj(info.Object, out)
|
||||
}
|
||||
|
||||
func maybeWrapSortingPrinter(cmd *cobra.Command, printer kubectl.ResourcePrinter) kubectl.ResourcePrinter {
|
||||
func maybeWrapSortingPrinter(cmd *cobra.Command, printer printers.ResourcePrinter) printers.ResourcePrinter {
|
||||
sorting, err := cmd.Flags().GetString("sort-by")
|
||||
if err != nil {
|
||||
// error can happen on missing flag or bad flag type. In either case, this command didn't intent to sort
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
sliceutil "k8s.io/kubernetes/pkg/util/slice"
|
||||
)
|
||||
|
||||
@@ -55,6 +57,7 @@ type DeploymentHistoryViewer struct {
|
||||
}
|
||||
|
||||
// ViewHistory returns a revision-to-replicaset map as the revision history of a deployment
|
||||
// TODO: this should be a describer
|
||||
func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) {
|
||||
versionedClient := versionedClientsetForDeployment(h.c)
|
||||
deployment, err := versionedClient.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{})
|
||||
@@ -101,7 +104,7 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i
|
||||
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
|
||||
return "", fmt.Errorf("failed to convert podtemplate, %v", err)
|
||||
}
|
||||
DescribePodTemplate(internalTemplate, buf)
|
||||
printersinternal.DescribePodTemplate(internalTemplate, buf)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
@@ -126,6 +129,22 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: copied here until this becomes a describer
|
||||
func tabbedString(f func(io.Writer) error) (string, error) {
|
||||
out := new(tabwriter.Writer)
|
||||
buf := &bytes.Buffer{}
|
||||
out.Init(buf, 0, 8, 1, '\t', 0)
|
||||
|
||||
err := f(out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
out.Flush()
|
||||
str := string(buf.String())
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// getChangeCause returns the change-cause annotation of the input object
|
||||
func getChangeCause(obj runtime.Object) string {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
|
@@ -24,7 +24,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,18 +34,6 @@ type NamespaceInfo struct {
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func listOfImages(spec *api.PodSpec) []string {
|
||||
images := make([]string, 0, len(spec.Containers))
|
||||
for _, container := range spec.Containers {
|
||||
images = append(images, container.Image)
|
||||
}
|
||||
return images
|
||||
}
|
||||
|
||||
func makeImageList(spec *api.PodSpec) string {
|
||||
return strings.Join(listOfImages(spec), ",")
|
||||
}
|
||||
|
||||
// ResourceShortcuts represents a structure that holds the information how to
|
||||
// transition from resource's shortcut to its full name.
|
||||
type ResourceShortcuts struct {
|
||||
|
@@ -18,7 +18,7 @@ go_library(
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
|
@@ -23,7 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metricsapi "k8s.io/heapster/metrics/apis/metrics/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -55,7 +55,7 @@ func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics,
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
w := kubectl.GetNewTabWriter(printer.out)
|
||||
w := printers.GetNewTabWriter(printer.out)
|
||||
defer w.Flush()
|
||||
|
||||
printColumnNames(w, NodeColumns)
|
||||
@@ -78,7 +78,7 @@ func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, p
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
w := kubectl.GetNewTabWriter(printer.out)
|
||||
w := printers.GetNewTabWriter(printer.out)
|
||||
defer w.Flush()
|
||||
|
||||
if withNamespace {
|
||||
|
@@ -20,12 +20,13 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// FilterFunc is a function that knows how to filter a specific resource kind.
|
||||
// It receives a generic runtime.Object which must be type-checked by the function.
|
||||
// Returns a boolean value true if a resource is filtered, or false otherwise.
|
||||
type FilterFunc func(runtime.Object, PrintOptions) bool
|
||||
type FilterFunc func(runtime.Object, printers.PrintOptions) bool
|
||||
|
||||
// Filters is a collection of filter funcs
|
||||
type Filters []FilterFunc
|
||||
@@ -38,7 +39,7 @@ func NewResourceFilter() Filters {
|
||||
|
||||
// filterPods returns true if a pod should be skipped.
|
||||
// defaults to true for terminated pods
|
||||
func filterPods(obj runtime.Object, options PrintOptions) bool {
|
||||
func filterPods(obj runtime.Object, options printers.PrintOptions) bool {
|
||||
switch p := obj.(type) {
|
||||
case *v1.Pod:
|
||||
reason := string(p.Status.Phase)
|
||||
@@ -57,7 +58,7 @@ func filterPods(obj runtime.Object, options PrintOptions) bool {
|
||||
}
|
||||
|
||||
// Filter loops through a collection of FilterFuncs until it finds one that can filter the given resource
|
||||
func (f Filters) Filter(obj runtime.Object, opts *PrintOptions) (bool, error) {
|
||||
func (f Filters) Filter(obj runtime.Object, opts *printers.PrintOptions) (bool, error) {
|
||||
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand
|
||||
// before apply filter func.
|
||||
obj, _ = DecodeUnknownObject(obj)
|
||||
|
@@ -33,6 +33,7 @@ import (
|
||||
externalextensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
sliceutil "k8s.io/kubernetes/pkg/util/slice"
|
||||
)
|
||||
|
||||
@@ -170,7 +171,7 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe
|
||||
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
|
||||
return "", fmt.Errorf("failed to convert podtemplate, %v", err)
|
||||
}
|
||||
DescribePodTemplate(internalTemplate, buf)
|
||||
printersinternal.DescribePodTemplate(internalTemplate, buf)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
@@ -188,6 +189,6 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe
|
||||
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
|
||||
return "", fmt.Errorf("failed to convert podtemplate, %v", err)
|
||||
}
|
||||
DescribePodTemplate(internalTemplate, buf)
|
||||
printersinternal.DescribePodTemplate(internalTemplate, buf)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
)
|
||||
|
||||
type SortableResourceNames []api.ResourceName
|
||||
|
||||
func (list SortableResourceNames) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableResourceNames) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableResourceNames) Less(i, j int) bool {
|
||||
return list[i] < list[j]
|
||||
}
|
||||
|
||||
// SortedResourceNames returns the sorted resource names of a resource list.
|
||||
func SortedResourceNames(list api.ResourceList) []api.ResourceName {
|
||||
resources := make([]api.ResourceName, 0, len(list))
|
||||
for res := range list {
|
||||
resources = append(resources, res)
|
||||
}
|
||||
sort.Sort(SortableResourceNames(resources))
|
||||
return resources
|
||||
}
|
||||
|
||||
type SortableResourceQuotas []api.ResourceQuota
|
||||
|
||||
func (list SortableResourceQuotas) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableResourceQuotas) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableResourceQuotas) Less(i, j int) bool {
|
||||
return list[i].Name < list[j].Name
|
||||
}
|
||||
|
||||
type SortableVolumeMounts []api.VolumeMount
|
||||
|
||||
func (list SortableVolumeMounts) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableVolumeMounts) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableVolumeMounts) Less(i, j int) bool {
|
||||
return list[i].MountPath < list[j].MountPath
|
||||
}
|
||||
|
||||
// SortedQoSResourceNames returns the sorted resource names of a QoS list.
|
||||
func SortedQoSResourceNames(list qos.QOSList) []api.ResourceName {
|
||||
resources := make([]api.ResourceName, 0, len(list))
|
||||
for res := range list {
|
||||
resources = append(resources, api.ResourceName(res))
|
||||
}
|
||||
sort.Sort(SortableResourceNames(resources))
|
||||
return resources
|
||||
}
|
@@ -31,13 +31,14 @@ import (
|
||||
"k8s.io/client-go/util/integer"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// Sorting printer sorts list types before delegating to another printer.
|
||||
// Non-list types are simply passed through
|
||||
type SortingPrinter struct {
|
||||
SortField string
|
||||
Delegate ResourcePrinter
|
||||
Delegate printers.ResourcePrinter
|
||||
Decoder runtime.Decoder
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri
|
||||
}
|
||||
}
|
||||
|
||||
field, err := massageJSONPath(fieldInput)
|
||||
field, err := printers.RelaxedJSONPathExpression(fieldInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
10
pkg/printers/.import-restrictions
Normal file
10
pkg/printers/.import-restrictions
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"Rules": [
|
||||
{
|
||||
"SelectorRegexp": "k8s[.]io/kubernetes/pkg/(api$|apis/)",
|
||||
"ForbiddenPrefixes": [
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
66
pkg/printers/BUILD
Normal file
66
pkg/printers/BUILD
Normal file
@@ -0,0 +1,66 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"common.go",
|
||||
"customcolumn.go",
|
||||
"humanreadable.go",
|
||||
"interface.go",
|
||||
"json.go",
|
||||
"jsonpath.go",
|
||||
"name.go",
|
||||
"printers.go",
|
||||
"tabwriter.go",
|
||||
"template.go",
|
||||
"versioned.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/ghodss/yaml",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||
"//vendor:k8s.io/client-go/util/jsonpath",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = ["customcolumn_test.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/printers/internalversion:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
41
pkg/printers/common.go
Normal file
41
pkg/printers/common.go
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ShortHumanDuration(d time.Duration) string {
|
||||
// Allow deviation no more than 2 seconds(excluded) to tolerate machine time
|
||||
// inconsistence, it can be considered as almost now.
|
||||
if seconds := int(d.Seconds()); seconds < -1 {
|
||||
return fmt.Sprintf("<invalid>")
|
||||
} else if seconds < 0 {
|
||||
return fmt.Sprintf("0s")
|
||||
} else if seconds < 60 {
|
||||
return fmt.Sprintf("%ds", seconds)
|
||||
} else if minutes := int(d.Minutes()); minutes < 60 {
|
||||
return fmt.Sprintf("%dm", minutes)
|
||||
} else if hours := int(d.Hours()); hours < 24 {
|
||||
return fmt.Sprintf("%dh", hours)
|
||||
} else if hours < 24*364 {
|
||||
return fmt.Sprintf("%dd", hours/24)
|
||||
}
|
||||
return fmt.Sprintf("%dy", int(d.Hours()/24/365))
|
||||
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package printers
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -41,14 +41,14 @@ const (
|
||||
|
||||
var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$")
|
||||
|
||||
// MassageJSONPath attempts to be flexible with JSONPath expressions, it accepts:
|
||||
// RelaxedJSONPathExpression attempts to be flexible with JSONPath expressions, it accepts:
|
||||
// * metadata.name (no leading '.' or curly brances '{...}'
|
||||
// * {metadata.name} (no leading '.')
|
||||
// * .metadata.name (no curly braces '{...}')
|
||||
// * {.metadata.name} (complete expression)
|
||||
// And transforms them all into a valid jsonpat expression:
|
||||
// And transforms them all into a valid jsonpath expression:
|
||||
// {.metadata.name}
|
||||
func massageJSONPath(pathExpression string) (string, error) {
|
||||
func RelaxedJSONPathExpression(pathExpression string) (string, error) {
|
||||
if len(pathExpression) == 0 {
|
||||
return pathExpression, nil
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder, noHea
|
||||
if len(colSpec) != 2 {
|
||||
return nil, fmt.Errorf("unexpected custom-columns spec: %s, expected <header>:<json-path-expr>", parts[ix])
|
||||
}
|
||||
spec, err := massageJSONPath(colSpec[1])
|
||||
spec, err := RelaxedJSONPathExpression(colSpec[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runti
|
||||
|
||||
columns := make([]Column, len(headers))
|
||||
for ix := range headers {
|
||||
spec, err := massageJSONPath(specs[ix])
|
||||
spec, err := RelaxedJSONPathExpression(specs[ix])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package printers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func TestMassageJSONPath(t *testing.T) {
|
||||
@@ -45,7 +46,7 @@ func TestMassageJSONPath(t *testing.T) {
|
||||
{input: "{{foo.bar}", expectErr: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
output, err := massageJSONPath(test.input)
|
||||
output, err := printers.RelaxedJSONPathExpression(test.input)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
@@ -65,7 +66,7 @@ func TestMassageJSONPath(t *testing.T) {
|
||||
func TestNewColumnPrinterFromSpec(t *testing.T) {
|
||||
tests := []struct {
|
||||
spec string
|
||||
expectedColumns []Column
|
||||
expectedColumns []printers.Column
|
||||
expectErr bool
|
||||
name string
|
||||
noHeaders bool
|
||||
@@ -93,7 +94,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
|
||||
{
|
||||
spec: "NAME:metadata.name,API_VERSION:apiVersion",
|
||||
name: "ok",
|
||||
expectedColumns: []Column{
|
||||
expectedColumns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -111,7 +112,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
printer, err := NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder(), test.noHeaders)
|
||||
printer, err := printers.NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder(), test.noHeaders)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("[%s] unexpected non-error", test.name)
|
||||
@@ -141,6 +142,15 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func contains(arr []string, s string) bool {
|
||||
for i := range arr {
|
||||
if arr[i] == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const exampleTemplateOne = `NAME API_VERSION
|
||||
{metadata.name} {apiVersion}`
|
||||
|
||||
@@ -150,7 +160,7 @@ const exampleTemplateTwo = `NAME API_VERSION
|
||||
func TestNewColumnPrinterFromTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
spec string
|
||||
expectedColumns []Column
|
||||
expectedColumns []printers.Column
|
||||
expectErr bool
|
||||
name string
|
||||
}{
|
||||
@@ -177,7 +187,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
|
||||
{
|
||||
spec: exampleTemplateOne,
|
||||
name: "ok",
|
||||
expectedColumns: []Column{
|
||||
expectedColumns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -191,7 +201,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
|
||||
{
|
||||
spec: exampleTemplateTwo,
|
||||
name: "ok-2",
|
||||
expectedColumns: []Column{
|
||||
expectedColumns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -205,7 +215,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
|
||||
}
|
||||
for _, test := range tests {
|
||||
reader := bytes.NewBufferString(test.spec)
|
||||
printer, err := NewCustomColumnsPrinterFromTemplate(reader, api.Codecs.UniversalDecoder())
|
||||
printer, err := printers.NewCustomColumnsPrinterFromTemplate(reader, api.Codecs.UniversalDecoder())
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("[%s] unexpected non-error", test.name)
|
||||
@@ -226,12 +236,12 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
|
||||
|
||||
func TestColumnPrint(t *testing.T) {
|
||||
tests := []struct {
|
||||
columns []Column
|
||||
columns []printers.Column
|
||||
obj runtime.Object
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
columns: []Column{
|
||||
columns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -243,7 +253,7 @@ foo
|
||||
`,
|
||||
},
|
||||
{
|
||||
columns: []Column{
|
||||
columns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -261,7 +271,7 @@ bar
|
||||
`,
|
||||
},
|
||||
{
|
||||
columns: []Column{
|
||||
columns: []printers.Column{
|
||||
{
|
||||
Header: "NAME",
|
||||
FieldSpec: "{.metadata.name}",
|
||||
@@ -279,7 +289,7 @@ foo baz
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
printer := &CustomColumnsPrinter{
|
||||
printer := &printers.CustomColumnsPrinter{
|
||||
Columns: test.columns,
|
||||
Decoder: api.Codecs.UniversalDecoder(),
|
||||
}
|
329
pkg/printers/humanreadable.go
Normal file
329
pkg/printers/humanreadable.go
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
|
||||
|
||||
type handlerEntry struct {
|
||||
columns []string
|
||||
columnsWithWide []string
|
||||
printFunc reflect.Value
|
||||
args []reflect.Value
|
||||
}
|
||||
|
||||
// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide
|
||||
// more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers
|
||||
// will only be printed if the object type changes. This makes it useful for printing items
|
||||
// received from watches.
|
||||
type HumanReadablePrinter struct {
|
||||
handlerMap map[reflect.Type]*handlerEntry
|
||||
options PrintOptions
|
||||
lastType reflect.Type
|
||||
hiddenObjNum int
|
||||
}
|
||||
|
||||
// NewHumanReadablePrinter creates a HumanReadablePrinter.
|
||||
func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
|
||||
printer := &HumanReadablePrinter{
|
||||
handlerMap: make(map[reflect.Type]*handlerEntry),
|
||||
options: options,
|
||||
}
|
||||
return printer
|
||||
}
|
||||
|
||||
// GetResourceKind returns the type currently set for a resource
|
||||
func (h *HumanReadablePrinter) GetResourceKind() string {
|
||||
return h.options.Kind
|
||||
}
|
||||
|
||||
// EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true
|
||||
// and "Kind" to the string arg it receives, pre-pending this string
|
||||
// to the "NAME" column in an output of resources.
|
||||
func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) {
|
||||
h.options.WithKind = true
|
||||
h.options.Kind = kind
|
||||
}
|
||||
|
||||
// EnsurePrintHeaders sets the HumanReadablePrinter option "NoHeaders" to false
|
||||
// and removes the .lastType that was printed, which forces headers to be
|
||||
// printed in cases where multiple lists of the same resource are printed
|
||||
// consecutively, but are separated by non-printer related information.
|
||||
func (h *HumanReadablePrinter) EnsurePrintHeaders() {
|
||||
h.options.NoHeaders = false
|
||||
h.lastType = nil
|
||||
}
|
||||
|
||||
// Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
|
||||
// See validatePrintHandlerFunc for required method signature.
|
||||
func (h *HumanReadablePrinter) Handler(columns, columnsWithWide []string, printFunc interface{}) error {
|
||||
printFuncValue := reflect.ValueOf(printFunc)
|
||||
if err := h.validatePrintHandlerFunc(printFuncValue); err != nil {
|
||||
glog.Errorf("Unable to add print handler: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
objType := printFuncValue.Type().In(0)
|
||||
h.handlerMap[objType] = &handlerEntry{
|
||||
columns: columns,
|
||||
columnsWithWide: columnsWithWide,
|
||||
printFunc: printFuncValue,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePrintHandlerFunc validates print handler signature.
|
||||
// printFunc is the function that will be called to print an object.
|
||||
// It must be of the following type:
|
||||
// func printFunc(object ObjectType, w io.Writer, options PrintOptions) error
|
||||
// where ObjectType is the type of the object that will be printed.
|
||||
func (h *HumanReadablePrinter) validatePrintHandlerFunc(printFunc reflect.Value) error {
|
||||
if printFunc.Kind() != reflect.Func {
|
||||
return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
|
||||
}
|
||||
funcType := printFunc.Type()
|
||||
if funcType.NumIn() != 3 || funcType.NumOut() != 1 {
|
||||
return fmt.Errorf("invalid print handler." +
|
||||
"Must accept 3 parameters and return 1 value.")
|
||||
}
|
||||
if funcType.In(1) != reflect.TypeOf((*io.Writer)(nil)).Elem() ||
|
||||
funcType.In(2) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
|
||||
funcType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
|
||||
return fmt.Errorf("invalid print handler. The expected signature is: "+
|
||||
"func handler(obj %v, w io.Writer, options PrintOptions) error", funcType.In(0))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) HandledResources() []string {
|
||||
keys := make([]string, 0)
|
||||
|
||||
for k := range h.handlerMap {
|
||||
// k.String looks like "*api.PodList" and we want just "pod"
|
||||
api := strings.Split(k.String(), ".")
|
||||
resource := api[len(api)-1]
|
||||
if strings.HasSuffix(resource, "List") {
|
||||
continue
|
||||
}
|
||||
resource = strings.ToLower(resource)
|
||||
keys = append(keys, resource)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) AfterPrint(output io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) printHeader(columnNames []string, w io.Writer) error {
|
||||
if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
|
||||
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
||||
// if output is a tabwriter (when it's called by kubectl get), we use it; create a new tabwriter otherwise
|
||||
w, found := output.(*tabwriter.Writer)
|
||||
if !found {
|
||||
w = GetNewTabWriter(output)
|
||||
defer w.Flush()
|
||||
}
|
||||
|
||||
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand before
|
||||
// trying to print, since the printers are keyed by type. This is extremely expensive.
|
||||
//obj, _ = DecodeUnknownObject(obj)
|
||||
|
||||
t := reflect.TypeOf(obj)
|
||||
if handler := h.handlerMap[t]; handler != nil {
|
||||
if !h.options.NoHeaders && t != h.lastType {
|
||||
headers := handler.columns
|
||||
if h.options.Wide {
|
||||
headers = append(headers, handler.columnsWithWide...)
|
||||
}
|
||||
headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
|
||||
// LABELS is always the last column.
|
||||
headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
|
||||
if h.options.WithNamespace {
|
||||
headers = append(withNamespacePrefixColumns, headers...)
|
||||
}
|
||||
h.printHeader(headers, w)
|
||||
h.lastType = t
|
||||
}
|
||||
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(w), reflect.ValueOf(h.options)}
|
||||
resultValue := handler.printFunc.Call(args)[0]
|
||||
if resultValue.IsNil() {
|
||||
return nil
|
||||
}
|
||||
return resultValue.Interface().(error)
|
||||
}
|
||||
|
||||
if _, err := meta.Accessor(obj); err == nil {
|
||||
if !h.options.NoHeaders && t != h.lastType {
|
||||
headers := []string{"NAME", "KIND"}
|
||||
headers = append(headers, formatLabelHeaders(h.options.ColumnLabels)...)
|
||||
// LABELS is always the last column.
|
||||
headers = append(headers, formatShowLabelsHeader(h.options.ShowLabels, t)...)
|
||||
if h.options.WithNamespace {
|
||||
headers = append(withNamespacePrefixColumns, headers...)
|
||||
}
|
||||
h.printHeader(headers, w)
|
||||
h.lastType = t
|
||||
}
|
||||
|
||||
// we don't recognize this type, but we can still attempt to print some reasonable information about.
|
||||
unstructured, ok := obj.(runtime.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("error: unknown type %#v", obj)
|
||||
}
|
||||
// if the error isn't nil, report the "I don't recognize this" error
|
||||
if err := printUnstructured(unstructured, w, h.options); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// we failed all reasonable printing efforts, report failure
|
||||
return fmt.Errorf("error: unknown type %#v", obj)
|
||||
}
|
||||
|
||||
// TODO: this method assumes the meta/v1 server API, so should be refactored out of this package
|
||||
func printUnstructured(unstructured runtime.Unstructured, w io.Writer, options PrintOptions) error {
|
||||
metadata, err := meta.Accessor(unstructured)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", metadata.GetNamespace()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
content := unstructured.UnstructuredContent()
|
||||
kind := "<missing>"
|
||||
if objKind, ok := content["kind"]; ok {
|
||||
if str, ok := objKind.(string); ok {
|
||||
kind = str
|
||||
}
|
||||
}
|
||||
if objAPIVersion, ok := content["apiVersion"]; ok {
|
||||
if str, ok := objAPIVersion.(string); ok {
|
||||
version, err := schema.ParseGroupVersion(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kind = kind + "." + version.Version + "." + version.Group
|
||||
}
|
||||
}
|
||||
name := formatResourceName(options.Kind, metadata.GetName(), options.WithKind)
|
||||
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s", name, kind); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, appendLabels(metadata.GetLabels(), options.ColumnLabels)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, appendAllLabels(options.ShowLabels, metadata.GetLabels())); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatLabelHeaders(columnLabels []string) []string {
|
||||
formHead := make([]string, len(columnLabels))
|
||||
for i, l := range columnLabels {
|
||||
p := strings.Split(l, "/")
|
||||
formHead[i] = strings.ToUpper((p[len(p)-1]))
|
||||
}
|
||||
return formHead
|
||||
}
|
||||
|
||||
// headers for --show-labels=true
|
||||
func formatShowLabelsHeader(showLabels bool, t reflect.Type) []string {
|
||||
if showLabels {
|
||||
// TODO: this is all sorts of hack, fix
|
||||
if t.String() != "*api.ThirdPartyResource" && t.String() != "*api.ThirdPartyResourceList" {
|
||||
return []string{"LABELS"}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// formatResourceName receives a resource kind, name, and boolean specifying
|
||||
// whether or not to update the current name to "kind/name"
|
||||
// TODO: dedup this with printers/internalversions
|
||||
func formatResourceName(kind, name string, withKind bool) string {
|
||||
if !withKind || kind == "" {
|
||||
return name
|
||||
}
|
||||
|
||||
return kind + "/" + name
|
||||
}
|
||||
|
||||
// TODO: dedup this with printers/internalversions
|
||||
func appendLabels(itemLabels map[string]string, columnLabels []string) string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
for _, cl := range columnLabels {
|
||||
buffer.WriteString(fmt.Sprint("\t"))
|
||||
if il, ok := itemLabels[cl]; ok {
|
||||
buffer.WriteString(fmt.Sprint(il))
|
||||
} else {
|
||||
buffer.WriteString("<none>")
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// Append all labels to a single column. We need this even when show-labels flag* is
|
||||
// false, since this adds newline delimiter to the end of each row.
|
||||
// TODO: dedup this with printers/internalversions
|
||||
func appendAllLabels(showLabels bool, itemLabels map[string]string) string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
if showLabels {
|
||||
buffer.WriteString(fmt.Sprint("\t"))
|
||||
buffer.WriteString(labels.FormatLabels(itemLabels))
|
||||
}
|
||||
buffer.WriteString("\n")
|
||||
|
||||
return buffer.String()
|
||||
}
|
96
pkg/printers/interface.go
Normal file
96
pkg/printers/interface.go
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// ResourcePrinter is an interface that knows how to print runtime objects.
|
||||
type ResourcePrinter interface {
|
||||
// Print receives a runtime object, formats it and prints it to a writer.
|
||||
PrintObj(runtime.Object, io.Writer) error
|
||||
HandledResources() []string
|
||||
//Can be used to print out warning/clarifications if needed
|
||||
//after all objects were printed
|
||||
AfterPrint(io.Writer, string) error
|
||||
}
|
||||
|
||||
// ResourcePrinterFunc is a function that can print objects
|
||||
type ResourcePrinterFunc func(runtime.Object, io.Writer) error
|
||||
|
||||
// PrintObj implements ResourcePrinter
|
||||
func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
return fn(obj, w)
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (fn ResourcePrinterFunc) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (fn ResourcePrinterFunc) AfterPrint(io.Writer, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type PrintOptions struct {
|
||||
NoHeaders bool
|
||||
WithNamespace bool
|
||||
WithKind bool
|
||||
Wide bool
|
||||
ShowAll bool
|
||||
ShowLabels bool
|
||||
AbsoluteTimestamps bool
|
||||
Kind string
|
||||
ColumnLabels []string
|
||||
}
|
||||
|
||||
// Describer generates output for the named resource or an error
|
||||
// if the output could not be generated. Implementers typically
|
||||
// abstract the retrieval of the named object from a remote server.
|
||||
type Describer interface {
|
||||
Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error)
|
||||
}
|
||||
|
||||
// DescriberSettings holds display configuration for each object
|
||||
// describer to control what is printed.
|
||||
type DescriberSettings struct {
|
||||
ShowEvents bool
|
||||
}
|
||||
|
||||
// ObjectDescriber is an interface for displaying arbitrary objects with extra
|
||||
// information. Use when an object is in hand (on disk, or already retrieved).
|
||||
// Implementers may ignore the additional information passed on extra, or use it
|
||||
// by default. ObjectDescribers may return ErrNoDescriber if no suitable describer
|
||||
// is found.
|
||||
type ObjectDescriber interface {
|
||||
DescribeObject(object interface{}, extra ...interface{}) (output string, err error)
|
||||
}
|
||||
|
||||
// ErrNoDescriber is a structured error indicating the provided object or objects
|
||||
// cannot be described.
|
||||
type ErrNoDescriber struct {
|
||||
Types []string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e ErrNoDescriber) Error() string {
|
||||
return fmt.Sprintf("no describer has been defined for %v", e.Types)
|
||||
}
|
4
pkg/printers/internalversion/.import-restrictions
Normal file
4
pkg/printers/internalversion/.import-restrictions
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"Rules": [
|
||||
]
|
||||
}
|
112
pkg/printers/internalversion/BUILD
Normal file
112
pkg/printers/internalversion/BUILD
Normal file
@@ -0,0 +1,112 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"describe_test.go",
|
||||
"printers_test.go",
|
||||
"sorted_resource_name_list_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/kubectl/testing:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//vendor:github.com/ghodss/yaml",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/equality",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/yaml",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"describe.go",
|
||||
"printers.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/annotations:go_default_library",
|
||||
"//pkg/api/events:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/certificates:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/apis/storage/util:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
|
||||
"//pkg/controller/deployment/util:go_default_library",
|
||||
"//pkg/fieldpath:go_default_library",
|
||||
"//pkg/kubelet/qos:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/fields",
|
||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -26,8 +26,11 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
@@ -42,7 +45,6 @@ import (
|
||||
"k8s.io/kubernetes/federation/apis/federation"
|
||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/annotations"
|
||||
"k8s.io/kubernetes/pkg/api/events"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
@@ -55,48 +57,17 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
versionedclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
coreclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1"
|
||||
extensionsclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/extensions/v1beta1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion"
|
||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||
"k8s.io/kubernetes/pkg/fieldpath"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
// Describer generates output for the named resource or an error
|
||||
// if the output could not be generated. Implementers typically
|
||||
// abstract the retrieval of the named object from a remote server.
|
||||
type Describer interface {
|
||||
Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error)
|
||||
}
|
||||
|
||||
// DescriberSettings holds display configuration for each object
|
||||
// describer to control what is printed.
|
||||
type DescriberSettings struct {
|
||||
ShowEvents bool
|
||||
}
|
||||
|
||||
// ObjectDescriber is an interface for displaying arbitrary objects with extra
|
||||
// information. Use when an object is in hand (on disk, or already retrieved).
|
||||
// Implementers may ignore the additional information passed on extra, or use it
|
||||
// by default. ObjectDescribers may return ErrNoDescriber if no suitable describer
|
||||
// is found.
|
||||
type ObjectDescriber interface {
|
||||
DescribeObject(object interface{}, extra ...interface{}) (output string, err error)
|
||||
}
|
||||
|
||||
// ErrNoDescriber is a structured error indicating the provided object or objects
|
||||
// cannot be described.
|
||||
type ErrNoDescriber struct {
|
||||
Types []string
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e ErrNoDescriber) Error() string {
|
||||
return fmt.Sprintf("no describer has been defined for %v", e.Types)
|
||||
}
|
||||
|
||||
// Each level has 2 spaces for PrefixWriter
|
||||
const (
|
||||
LEVEL_0 = iota
|
||||
@@ -122,8 +93,8 @@ func (pw *PrefixWriter) WriteLine(a ...interface{}) {
|
||||
fmt.Fprintln(pw.out, a...)
|
||||
}
|
||||
|
||||
func describerMap(c clientset.Interface) map[schema.GroupKind]Describer {
|
||||
m := map[schema.GroupKind]Describer{
|
||||
func describerMap(c clientset.Interface) map[schema.GroupKind]printers.Describer {
|
||||
m := map[schema.GroupKind]printers.Describer{
|
||||
api.Kind("Pod"): &PodDescriber{c},
|
||||
api.Kind("ReplicationController"): &ReplicationControllerDescriber{c},
|
||||
api.Kind("Secret"): &SecretDescriber{c},
|
||||
@@ -155,7 +126,7 @@ func describerMap(c clientset.Interface) map[schema.GroupKind]Describer {
|
||||
return m
|
||||
}
|
||||
|
||||
// List of all resource types we can describe
|
||||
// DescribableResources lists all resource types we can describe.
|
||||
func DescribableResources() []string {
|
||||
keys := make([]string, 0)
|
||||
|
||||
@@ -166,16 +137,16 @@ func DescribableResources() []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
// Describer returns the default describe functions for each of the standard
|
||||
// DescriberFor returns the default describe functions for each of the standard
|
||||
// Kubernetes types.
|
||||
func DescriberFor(kind schema.GroupKind, c clientset.Interface) (Describer, bool) {
|
||||
func DescriberFor(kind schema.GroupKind, c clientset.Interface) (printers.Describer, bool) {
|
||||
f, ok := describerMap(c)[kind]
|
||||
return f, ok
|
||||
}
|
||||
|
||||
// GenericDescriberFor returns a generic describer for the specified mapping
|
||||
// that uses only information available from runtime.Unstructured
|
||||
func GenericDescriberFor(mapping *meta.RESTMapping, dynamic *dynamic.Client, events coreclient.EventsGetter) Describer {
|
||||
func GenericDescriberFor(mapping *meta.RESTMapping, dynamic *dynamic.Client, events coreclient.EventsGetter) printers.Describer {
|
||||
return &genericDescriber{mapping, dynamic, events}
|
||||
}
|
||||
|
||||
@@ -185,7 +156,7 @@ type genericDescriber struct {
|
||||
events coreclient.EventsGetter
|
||||
}
|
||||
|
||||
func (g *genericDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error) {
|
||||
func (g *genericDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
apiResource := &metav1.APIResource{
|
||||
Name: g.mapping.Resource,
|
||||
Namespaced: g.mapping.Scope.Name() == meta.RESTScopeNameNamespace,
|
||||
@@ -214,7 +185,7 @@ func (g *genericDescriber) Describe(namespace, name string, describerSettings De
|
||||
}
|
||||
|
||||
// DefaultObjectDescriber can describe the default Kubernetes objects.
|
||||
var DefaultObjectDescriber ObjectDescriber
|
||||
var DefaultObjectDescriber printers.ObjectDescriber
|
||||
|
||||
func init() {
|
||||
d := &Describers{}
|
||||
@@ -239,7 +210,7 @@ type NamespaceDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *NamespaceDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *NamespaceDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
ns, err := d.Core().Namespaces().Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -411,7 +382,7 @@ type LimitRangeDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *LimitRangeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *LimitRangeDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
lr := d.Core().LimitRanges(namespace)
|
||||
|
||||
limitRange, err := lr.Get(name, metav1.GetOptions{})
|
||||
@@ -438,7 +409,7 @@ type ResourceQuotaDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ResourceQuotaDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ResourceQuotaDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
rq := d.Core().ResourceQuotas(namespace)
|
||||
|
||||
resourceQuota, err := rq.Get(name, metav1.GetOptions{})
|
||||
@@ -508,7 +479,7 @@ type PodDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *PodDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *PodDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
pod, err := d.Core().Pods(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if describerSettings.ShowEvents {
|
||||
@@ -810,7 +781,7 @@ type PersistentVolumeDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().PersistentVolumes()
|
||||
|
||||
pv, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -881,7 +852,7 @@ type PersistentVolumeClaimDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *PersistentVolumeClaimDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().PersistentVolumeClaims(namespace)
|
||||
|
||||
pvc, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -1214,7 +1185,7 @@ type ReplicationControllerDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
rc := d.Core().ReplicationControllers(namespace)
|
||||
pc := d.Core().Pods(namespace)
|
||||
|
||||
@@ -1286,7 +1257,7 @@ type ReplicaSetDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ReplicaSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ReplicaSetDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
rsc := d.Extensions().ReplicaSets(namespace)
|
||||
pc := d.Core().Pods(namespace)
|
||||
|
||||
@@ -1338,7 +1309,7 @@ type JobDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *JobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *JobDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
job, err := d.Batch().Jobs(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -1387,7 +1358,7 @@ type CronJobDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *CronJobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *CronJobDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
scheduledJob, err := d.Batch().CronJobs(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -1474,7 +1445,7 @@ type DaemonSetDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *DaemonSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *DaemonSetDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
dc := d.Extensions().DaemonSets(namespace)
|
||||
pc := d.Core().Pods(namespace)
|
||||
|
||||
@@ -1529,7 +1500,7 @@ type SecretDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *SecretDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *SecretDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().Secrets(namespace)
|
||||
|
||||
secret, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -1569,7 +1540,7 @@ type IngressDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (i *IngressDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (i *IngressDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := i.Extensions().Ingresses(namespace)
|
||||
ing, err := c.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
@@ -1598,7 +1569,7 @@ func (i *IngressDescriber) describeBackend(ns string, backend *extensions.Ingres
|
||||
return formatEndpoints(endpoints, sets.NewString(spName))
|
||||
}
|
||||
|
||||
func (i *IngressDescriber) describeIngress(ing *extensions.Ingress, describerSettings DescriberSettings) (string, error) {
|
||||
func (i *IngressDescriber) describeIngress(ing *extensions.Ingress, describerSettings printers.DescriberSettings) (string, error) {
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
w := &PrefixWriter{out}
|
||||
w.Write(LEVEL_0, "Name:\t%v\n", ing.Name)
|
||||
@@ -1682,7 +1653,7 @@ type ServiceDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ServiceDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ServiceDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().Services(namespace)
|
||||
|
||||
service, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -1762,7 +1733,7 @@ type EndpointsDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *EndpointsDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *EndpointsDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().Endpoints(namespace)
|
||||
|
||||
ep, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -1836,7 +1807,7 @@ type ServiceAccountDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ServiceAccountDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ServiceAccountDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().ServiceAccounts(namespace)
|
||||
|
||||
serviceAccount, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -1944,7 +1915,7 @@ type NodeDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *NodeDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *NodeDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
mc := d.Core().Nodes()
|
||||
node, err := mc.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
@@ -2065,7 +2036,7 @@ type StatefulSetDescriber struct {
|
||||
client clientset.Interface
|
||||
}
|
||||
|
||||
func (p *StatefulSetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (p *StatefulSetDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
ps, err := p.client.Apps().StatefulSets(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2108,7 +2079,7 @@ type CertificateSigningRequestDescriber struct {
|
||||
client clientset.Interface
|
||||
}
|
||||
|
||||
func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
csr, err := p.client.Certificates().CertificateSigningRequests().Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2178,7 +2149,7 @@ type HorizontalPodAutoscalerDescriber struct {
|
||||
client clientset.Interface
|
||||
}
|
||||
|
||||
func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
hpa, err := d.client.Autoscaling().HorizontalPodAutoscalers(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2369,7 +2340,7 @@ type DeploymentDescriber struct {
|
||||
versionedClient versionedclientset.Interface
|
||||
}
|
||||
|
||||
func (dd *DeploymentDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (dd *DeploymentDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
d, err := dd.versionedClient.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2504,7 +2475,7 @@ type ConfigMapDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *ConfigMapDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ConfigMapDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Core().ConfigMaps(namespace)
|
||||
|
||||
configMap, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -2537,7 +2508,7 @@ type ClusterDescriber struct {
|
||||
fedclientset.Interface
|
||||
}
|
||||
|
||||
func (d *ClusterDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *ClusterDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
cluster, err := d.Federation().Clusters().Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2579,7 +2550,7 @@ type NetworkPolicyDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (d *NetworkPolicyDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (d *NetworkPolicyDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
c := d.Extensions().NetworkPolicies(namespace)
|
||||
|
||||
networkPolicy, err := c.Get(name, metav1.GetOptions{})
|
||||
@@ -2606,7 +2577,7 @@ type StorageClassDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (s *StorageClassDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (s *StorageClassDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
sc, err := s.Storage().StorageClasses().Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2635,7 +2606,7 @@ type PodDisruptionBudgetDescriber struct {
|
||||
clientset.Interface
|
||||
}
|
||||
|
||||
func (p *PodDisruptionBudgetDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
func (p *PodDisruptionBudgetDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (string, error) {
|
||||
pdb, err := p.Policy().PodDisruptionBudgets(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -2673,7 +2644,7 @@ func newErrNoDescriber(types ...reflect.Type) error {
|
||||
for _, t := range types {
|
||||
names = append(names, t.String())
|
||||
}
|
||||
return ErrNoDescriber{Types: names}
|
||||
return printers.ErrNoDescriber{Types: names}
|
||||
}
|
||||
|
||||
// Describers implements ObjectDescriber against functions registered via Add. Those functions can
|
||||
@@ -2720,7 +2691,7 @@ func (d *Describers) DescribeObject(exact interface{}, extra ...interface{}) (st
|
||||
return "", newErrNoDescriber(append([]reflect.Type{exactType}, types...)...)
|
||||
}
|
||||
|
||||
// Add adds one or more describer functions to the Describer. The passed function must
|
||||
// Add adds one or more describer functions to the printers.Describer. The passed function must
|
||||
// match the signature:
|
||||
//
|
||||
// func(...) (string, error)
|
||||
@@ -2928,3 +2899,102 @@ func printTolerationsMultilineWithIndent(w *PrefixWriter, initialIndent, title,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tabbedString(f func(io.Writer) error) (string, error) {
|
||||
out := new(tabwriter.Writer)
|
||||
buf := &bytes.Buffer{}
|
||||
out.Init(buf, 0, 8, 1, '\t', 0)
|
||||
|
||||
err := f(out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
out.Flush()
|
||||
str := string(buf.String())
|
||||
return str, nil
|
||||
}
|
||||
|
||||
type SortableResourceNames []api.ResourceName
|
||||
|
||||
func (list SortableResourceNames) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableResourceNames) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableResourceNames) Less(i, j int) bool {
|
||||
return list[i] < list[j]
|
||||
}
|
||||
|
||||
// SortedResourceNames returns the sorted resource names of a resource list.
|
||||
func SortedResourceNames(list api.ResourceList) []api.ResourceName {
|
||||
resources := make([]api.ResourceName, 0, len(list))
|
||||
for res := range list {
|
||||
resources = append(resources, res)
|
||||
}
|
||||
sort.Sort(SortableResourceNames(resources))
|
||||
return resources
|
||||
}
|
||||
|
||||
type SortableResourceQuotas []api.ResourceQuota
|
||||
|
||||
func (list SortableResourceQuotas) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableResourceQuotas) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableResourceQuotas) Less(i, j int) bool {
|
||||
return list[i].Name < list[j].Name
|
||||
}
|
||||
|
||||
type SortableVolumeMounts []api.VolumeMount
|
||||
|
||||
func (list SortableVolumeMounts) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SortableVolumeMounts) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (list SortableVolumeMounts) Less(i, j int) bool {
|
||||
return list[i].MountPath < list[j].MountPath
|
||||
}
|
||||
|
||||
// SortedQoSResourceNames returns the sorted resource names of a QoS list.
|
||||
func SortedQoSResourceNames(list qos.QOSList) []api.ResourceName {
|
||||
resources := make([]api.ResourceName, 0, len(list))
|
||||
for res := range list {
|
||||
resources = append(resources, api.ResourceName(res))
|
||||
}
|
||||
sort.Sort(SortableResourceNames(resources))
|
||||
return resources
|
||||
}
|
||||
|
||||
func listOfImages(spec *api.PodSpec) []string {
|
||||
images := make([]string, 0, len(spec.Containers))
|
||||
for _, container := range spec.Containers {
|
||||
images = append(images, container.Image)
|
||||
}
|
||||
return images
|
||||
}
|
||||
|
||||
func makeImageList(spec *api.PodSpec) string {
|
||||
return strings.Join(listOfImages(spec), ",")
|
||||
}
|
||||
|
||||
func versionedClientsetForDeployment(internalClient clientset.Interface) versionedclientset.Interface {
|
||||
if internalClient == nil {
|
||||
return &versionedclientset.Clientset{}
|
||||
}
|
||||
return &versionedclientset.Clientset{
|
||||
CoreV1Client: coreclientset.New(internalClient.Core().RESTClient()),
|
||||
ExtensionsV1beta1Client: extensionsclientset.New(internalClient.Extensions().RESTClient()),
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
versionedfake "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
@@ -59,7 +60,7 @@ func TestDescribePod(t *testing.T) {
|
||||
})
|
||||
c := &describeClient{T: t, Namespace: "foo", Interface: fake}
|
||||
d := PodDescriber{c}
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -83,7 +84,7 @@ func TestDescribePodTolerations(t *testing.T) {
|
||||
})
|
||||
c := &describeClient{T: t, Namespace: "foo", Interface: fake}
|
||||
d := PodDescriber{c}
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -100,7 +101,7 @@ func TestDescribeNamespace(t *testing.T) {
|
||||
})
|
||||
c := &describeClient{T: t, Namespace: "", Interface: fake}
|
||||
d := NamespaceDescriber{c}
|
||||
out, err := d.Describe("", "myns", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("", "myns", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -118,7 +119,7 @@ func TestDescribeService(t *testing.T) {
|
||||
})
|
||||
c := &describeClient{T: t, Namespace: "foo", Interface: fake}
|
||||
d := ServiceDescriber{c}
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -167,7 +168,7 @@ func TestPodDescribeResultsSorted(t *testing.T) {
|
||||
d := PodDescriber{c}
|
||||
|
||||
// Act
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@@ -436,7 +437,7 @@ func TestDescribers(t *testing.T) {
|
||||
if out, err := d.DescribeObject(first, second, third); out != "" || err == nil {
|
||||
t.Errorf("unexpected result: %s %v", out, err)
|
||||
} else {
|
||||
if noDescriber, ok := err.(ErrNoDescriber); ok {
|
||||
if noDescriber, ok := err.(printers.ErrNoDescriber); ok {
|
||||
if !reflect.DeepEqual(noDescriber.Types, []string{"*api.Event", "*api.Pod", "*api.Pod"}) {
|
||||
t.Errorf("unexpected describer: %v", err)
|
||||
}
|
||||
@@ -649,7 +650,7 @@ func TestPersistentVolumeDescriber(t *testing.T) {
|
||||
for name, pv := range tests {
|
||||
fake := fake.NewSimpleClientset(pv)
|
||||
c := PersistentVolumeDescriber{fake}
|
||||
str, err := c.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error for test %s: %v", name, err)
|
||||
}
|
||||
@@ -673,7 +674,7 @@ func TestDescribeDeployment(t *testing.T) {
|
||||
},
|
||||
})
|
||||
d := DeploymentDescriber{fake, versionedFake}
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -707,7 +708,7 @@ func TestDescribeCluster(t *testing.T) {
|
||||
}
|
||||
fake := fedfake.NewSimpleClientset(&cluster)
|
||||
d := ClusterDescriber{Interface: fake}
|
||||
out, err := d.Describe("any", "foo", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("any", "foo", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -732,7 +733,7 @@ func TestDescribeStorageClass(t *testing.T) {
|
||||
},
|
||||
})
|
||||
s := StorageClassDescriber{f}
|
||||
out, err := s.Describe("", "foo", DescriberSettings{ShowEvents: true})
|
||||
out, err := s.Describe("", "foo", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -756,7 +757,7 @@ func TestDescribePodDisruptionBudget(t *testing.T) {
|
||||
},
|
||||
})
|
||||
s := PodDisruptionBudgetDescriber{f}
|
||||
out, err := s.Describe("ns1", "pdb1", DescriberSettings{ShowEvents: true})
|
||||
out, err := s.Describe("ns1", "pdb1", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -1112,7 +1113,7 @@ func TestDescribeHorizontalPodAutoscaler(t *testing.T) {
|
||||
}
|
||||
fake := fake.NewSimpleClientset(&test.hpa)
|
||||
desc := HorizontalPodAutoscalerDescriber{fake}
|
||||
str, err := desc.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
str, err := desc.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error for test %s: %v", test.name, err)
|
||||
}
|
||||
@@ -1141,7 +1142,7 @@ func TestDescribeEvents(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
m := map[string]Describer{
|
||||
m := map[string]printers.Describer{
|
||||
"DaemonSetDescriber": &DaemonSetDescriber{
|
||||
fake.NewSimpleClientset(&extensions.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -1241,7 +1242,7 @@ func TestDescribeEvents(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, d := range m {
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", name, err)
|
||||
}
|
||||
@@ -1252,7 +1253,7 @@ func TestDescribeEvents(t *testing.T) {
|
||||
t.Errorf("events not found for %q when ShowEvents=true: %s", name, out)
|
||||
}
|
||||
|
||||
out, err = d.Describe("foo", "bar", DescriberSettings{ShowEvents: false})
|
||||
out, err = d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: false})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error for %q: %s", name, err)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -26,8 +26,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
@@ -42,8 +45,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
kubectltesting "k8s.io/kubernetes/pkg/kubectl/testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -60,8 +62,8 @@ var testData = kubectltesting.TestStruct{
|
||||
|
||||
func TestVersionedPrinter(t *testing.T) {
|
||||
original := &kubectltesting.TestStruct{Key: "value"}
|
||||
p := NewVersionedPrinter(
|
||||
ResourcePrinterFunc(func(obj runtime.Object, w io.Writer) error {
|
||||
p := printers.NewVersionedPrinter(
|
||||
printers.ResourcePrinterFunc(func(obj runtime.Object, w io.Writer) error {
|
||||
if obj == original {
|
||||
t.Fatalf("object should not be identical: %#v", obj)
|
||||
}
|
||||
@@ -79,7 +81,7 @@ func TestVersionedPrinter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintDefault(t *testing.T) {
|
||||
printer, found, err := GetPrinter("", "", false, false)
|
||||
printer, found, err := printers.GetStandardPrinter("", "", false, false, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %#v", err)
|
||||
}
|
||||
@@ -129,17 +131,17 @@ func TestPrinter(t *testing.T) {
|
||||
{"test jsonpath", "jsonpath", "{.metadata.name}", podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"},
|
||||
{"test jsonpath list", "jsonpath", "{.items[*].metadata.name}", podListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo bar"},
|
||||
{"test jsonpath empty list", "jsonpath", "{.items[*].metadata.name}", emptyListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, ""},
|
||||
{"test name", "name", "", podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "pod/foo\n"},
|
||||
{"test name", "name", "", podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "pods/foo\n"},
|
||||
{"emits versioned objects", "template", "{{.kind}}", testapi, []schema.GroupVersion{v1.SchemeGroupVersion}, "Pod"},
|
||||
}
|
||||
for _, test := range printerTests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer, generic, err := GetPrinter(test.Format, test.FormatArgument, false, true)
|
||||
printer, generic, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, true, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
||||
if err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
}
|
||||
if generic && len(test.OutputVersions) > 0 {
|
||||
printer = NewVersionedPrinter(printer, api.Scheme, test.OutputVersions...)
|
||||
printer = printers.NewVersionedPrinter(printer, api.Scheme, test.OutputVersions...)
|
||||
}
|
||||
if err := printer.PrintObj(test.Input, buf); err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
@@ -164,14 +166,14 @@ func TestBadPrinter(t *testing.T) {
|
||||
{"bad jsonpath", "jsonpath", "{.Name", fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")},
|
||||
}
|
||||
for _, test := range badPrinterTests {
|
||||
_, _, err := GetPrinter(test.Format, test.FormatArgument, false, false)
|
||||
_, _, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
||||
if err == nil || err.Error() != test.Error.Error() {
|
||||
t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testPrinter(t *testing.T, printer ResourcePrinter, unmarshalFunc func(data []byte, v interface{}) error) {
|
||||
func testPrinter(t *testing.T, printer printers.ResourcePrinter, unmarshalFunc func(data []byte, v interface{}) error) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
err := printer.PrintObj(&testData, buf)
|
||||
@@ -216,11 +218,11 @@ func testPrinter(t *testing.T, printer ResourcePrinter, unmarshalFunc func(data
|
||||
}
|
||||
|
||||
func TestYAMLPrinter(t *testing.T) {
|
||||
testPrinter(t, &YAMLPrinter{}, yaml.Unmarshal)
|
||||
testPrinter(t, &printers.YAMLPrinter{}, yaml.Unmarshal)
|
||||
}
|
||||
|
||||
func TestJSONPrinter(t *testing.T) {
|
||||
testPrinter(t, &JSONPrinter{}, json.Unmarshal)
|
||||
testPrinter(t, &printers.JSONPrinter{}, json.Unmarshal)
|
||||
}
|
||||
|
||||
func TestFormatResourceName(t *testing.T) {
|
||||
@@ -240,7 +242,7 @@ func TestFormatResourceName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func PrintCustomType(obj *TestPrintType, w io.Writer, options PrintOptions) error {
|
||||
func PrintCustomType(obj *TestPrintType, w io.Writer, options printers.PrintOptions) error {
|
||||
data := obj.Data
|
||||
kind := options.Kind
|
||||
if options.WithKind {
|
||||
@@ -250,13 +252,13 @@ func PrintCustomType(obj *TestPrintType, w io.Writer, options PrintOptions) erro
|
||||
return err
|
||||
}
|
||||
|
||||
func ErrorPrintHandler(obj *TestPrintType, w io.Writer, options PrintOptions) error {
|
||||
func ErrorPrintHandler(obj *TestPrintType, w io.Writer, options printers.PrintOptions) error {
|
||||
return fmt.Errorf("ErrorPrintHandler error")
|
||||
}
|
||||
|
||||
func TestCustomTypePrinting(t *testing.T) {
|
||||
columns := []string{"Data"}
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
printer.Handler(columns, nil, PrintCustomType)
|
||||
|
||||
obj := TestPrintType{"test object"}
|
||||
@@ -273,7 +275,7 @@ func TestCustomTypePrinting(t *testing.T) {
|
||||
|
||||
func TestCustomTypePrintingWithKind(t *testing.T) {
|
||||
columns := []string{"Data"}
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
printer.Handler(columns, nil, PrintCustomType)
|
||||
printer.EnsurePrintWithKind("test")
|
||||
|
||||
@@ -291,7 +293,7 @@ func TestCustomTypePrintingWithKind(t *testing.T) {
|
||||
|
||||
func TestPrintHandlerError(t *testing.T) {
|
||||
columns := []string{"Data"}
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
printer.Handler(columns, nil, ErrorPrintHandler)
|
||||
obj := TestPrintType{"test object"}
|
||||
buffer := &bytes.Buffer{}
|
||||
@@ -302,7 +304,7 @@ func TestPrintHandlerError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnknownTypePrinting(t *testing.T) {
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
buffer := &bytes.Buffer{}
|
||||
err := printer.PrintObj(&TestUnknownType{}, buffer)
|
||||
if err == nil {
|
||||
@@ -312,7 +314,7 @@ func TestUnknownTypePrinting(t *testing.T) {
|
||||
|
||||
func TestTemplatePanic(t *testing.T) {
|
||||
tmpl := `{{and ((index .currentState.info "foo").state.running.startedAt) .currentState.info.net.state.running.startedAt}}`
|
||||
printer, err := NewTemplatePrinter([]byte(tmpl))
|
||||
printer, err := printers.NewTemplatePrinter([]byte(tmpl))
|
||||
if err != nil {
|
||||
t.Fatalf("tmpl fail: %v", err)
|
||||
}
|
||||
@@ -340,7 +342,7 @@ func TestNamePrinter(t *testing.T) {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
"pod/foo\n"},
|
||||
"pods/foo\n"},
|
||||
"List": {
|
||||
&v1.List{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
@@ -355,9 +357,9 @@ func TestNamePrinter(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"pod/foo\npod/bar\n"},
|
||||
"pods/foo\npods/bar\n"},
|
||||
}
|
||||
printer, _, _ := GetPrinter("name", "", false, false)
|
||||
printer, _, _ := printers.GetStandardPrinter("name", "", false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
||||
for name, item := range tests {
|
||||
buff := &bytes.Buffer{}
|
||||
err := printer.PrintObj(item.obj, buff)
|
||||
@@ -467,12 +469,12 @@ func TestTemplateStrings(t *testing.T) {
|
||||
}
|
||||
// The point of this test is to verify that the below template works.
|
||||
tmpl := `{{if (exists . "status" "containerStatuses")}}{{range .status.containerStatuses}}{{if (and (eq .name "foo") (exists . "state" "running"))}}true{{end}}{{end}}{{end}}`
|
||||
p, err := NewTemplatePrinter([]byte(tmpl))
|
||||
p, err := printers.NewTemplatePrinter([]byte(tmpl))
|
||||
if err != nil {
|
||||
t.Fatalf("tmpl fail: %v", err)
|
||||
}
|
||||
|
||||
printer := NewVersionedPrinter(p, api.Scheme, api.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
printer := printers.NewVersionedPrinter(p, api.Scheme, api.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
|
||||
for name, item := range table {
|
||||
buffer := &bytes.Buffer{}
|
||||
@@ -496,44 +498,47 @@ func TestPrinters(t *testing.T) {
|
||||
|
||||
var (
|
||||
err error
|
||||
templatePrinter ResourcePrinter
|
||||
templatePrinter2 ResourcePrinter
|
||||
jsonpathPrinter ResourcePrinter
|
||||
templatePrinter printers.ResourcePrinter
|
||||
templatePrinter2 printers.ResourcePrinter
|
||||
jsonpathPrinter printers.ResourcePrinter
|
||||
)
|
||||
|
||||
templatePrinter, err = NewTemplatePrinter([]byte("{{.name}}"))
|
||||
templatePrinter, err = printers.NewTemplatePrinter([]byte("{{.name}}"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
templatePrinter = NewVersionedPrinter(templatePrinter, api.Scheme, v1.SchemeGroupVersion)
|
||||
templatePrinter = printers.NewVersionedPrinter(templatePrinter, api.Scheme, v1.SchemeGroupVersion)
|
||||
|
||||
templatePrinter2, err = NewTemplatePrinter([]byte("{{len .items}}"))
|
||||
templatePrinter2, err = printers.NewTemplatePrinter([]byte("{{len .items}}"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
templatePrinter2 = NewVersionedPrinter(templatePrinter2, api.Scheme, v1.SchemeGroupVersion)
|
||||
templatePrinter2 = printers.NewVersionedPrinter(templatePrinter2, api.Scheme, v1.SchemeGroupVersion)
|
||||
|
||||
jsonpathPrinter, err = NewJSONPathPrinter("{.metadata.name}")
|
||||
jsonpathPrinter, err = printers.NewJSONPathPrinter("{.metadata.name}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
jsonpathPrinter = NewVersionedPrinter(jsonpathPrinter, api.Scheme, v1.SchemeGroupVersion)
|
||||
jsonpathPrinter = printers.NewVersionedPrinter(jsonpathPrinter, api.Scheme, v1.SchemeGroupVersion)
|
||||
|
||||
printers := map[string]ResourcePrinter{
|
||||
"humanReadable": NewHumanReadablePrinter(PrintOptions{
|
||||
allPrinters := map[string]printers.ResourcePrinter{
|
||||
"humanReadable": printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
NoHeaders: true,
|
||||
}),
|
||||
"humanReadableHeaders": NewHumanReadablePrinter(PrintOptions{}),
|
||||
"json": &JSONPrinter{},
|
||||
"yaml": &YAMLPrinter{},
|
||||
"humanReadableHeaders": printers.NewHumanReadablePrinter(printers.PrintOptions{}),
|
||||
"json": &printers.JSONPrinter{},
|
||||
"yaml": &printers.YAMLPrinter{},
|
||||
"template": templatePrinter,
|
||||
"template2": templatePrinter2,
|
||||
"jsonpath": jsonpathPrinter,
|
||||
"name": &NamePrinter{
|
||||
"name": &printers.NamePrinter{
|
||||
Typer: api.Scheme,
|
||||
Decoder: api.Codecs.UniversalDecoder(),
|
||||
Decoders: []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme},
|
||||
Mapper: api.Registry.RESTMapper(api.Registry.EnabledVersions()...),
|
||||
},
|
||||
}
|
||||
AddHandlers((allPrinters["humanReadable"]).(*printers.HumanReadablePrinter))
|
||||
AddHandlers((allPrinters["humanReadableHeaders"]).(*printers.HumanReadablePrinter))
|
||||
objects := map[string]runtime.Object{
|
||||
"pod": &api.Pod{ObjectMeta: om("pod")},
|
||||
"emptyPodList": &api.PodList{},
|
||||
@@ -550,7 +555,7 @@ func TestPrinters(t *testing.T) {
|
||||
"jsonpath": sets.NewString("emptyPodList", "nonEmptyPodList", "endpoints"),
|
||||
}
|
||||
|
||||
for pName, p := range printers {
|
||||
for pName, p := range allPrinters {
|
||||
for oName, obj := range objects {
|
||||
b := &bytes.Buffer{}
|
||||
if err := p.PrintObj(obj, b); err != nil {
|
||||
@@ -566,7 +571,8 @@ func TestPrinters(t *testing.T) {
|
||||
|
||||
func TestPrintEventsResultSorted(t *testing.T) {
|
||||
// Arrange
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
AddHandlers(printer)
|
||||
|
||||
obj := api.EventList{
|
||||
Items: []api.Event{
|
||||
@@ -610,7 +616,8 @@ func TestPrintEventsResultSorted(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintNodeStatus(t *testing.T) {
|
||||
printer := NewHumanReadablePrinter(PrintOptions{})
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
|
||||
AddHandlers(printer)
|
||||
table := []struct {
|
||||
node api.Node
|
||||
status string
|
||||
@@ -729,10 +736,11 @@ func TestPrintNodeStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintNodeOSImage(t *testing.T) {
|
||||
printer := NewHumanReadablePrinter(PrintOptions{
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
Wide: true,
|
||||
})
|
||||
AddHandlers(printer)
|
||||
|
||||
table := []struct {
|
||||
node api.Node
|
||||
@@ -773,10 +781,11 @@ func TestPrintNodeOSImage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintNodeKernelVersion(t *testing.T) {
|
||||
printer := NewHumanReadablePrinter(PrintOptions{
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
ColumnLabels: []string{},
|
||||
Wide: true,
|
||||
})
|
||||
AddHandlers(printer)
|
||||
|
||||
table := []struct {
|
||||
node api.Node
|
||||
@@ -817,9 +826,10 @@ func TestPrintNodeKernelVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintNodeExternalIP(t *testing.T) {
|
||||
printer := NewHumanReadablePrinter(PrintOptions{
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
Wide: true,
|
||||
})
|
||||
AddHandlers(printer)
|
||||
table := []struct {
|
||||
node api.Node
|
||||
externalIP string
|
||||
@@ -900,7 +910,7 @@ func TestPrintHunmanReadableIngressWithColumnLabels(t *testing.T) {
|
||||
},
|
||||
}
|
||||
buff := bytes.Buffer{}
|
||||
printIngress(&ingress, &buff, PrintOptions{
|
||||
printIngress(&ingress, &buff, printers.PrintOptions{
|
||||
ColumnLabels: []string{"app_name"},
|
||||
})
|
||||
output := string(buff.Bytes())
|
||||
@@ -1025,7 +1035,7 @@ func TestPrintHumanReadableService(t *testing.T) {
|
||||
for _, svc := range tests {
|
||||
for _, wide := range []bool{false, true} {
|
||||
buff := bytes.Buffer{}
|
||||
printService(&svc, &buff, PrintOptions{Wide: wide})
|
||||
printService(&svc, &buff, printers.PrintOptions{Wide: wide})
|
||||
output := string(buff.Bytes())
|
||||
ip := svc.Spec.ClusterIP
|
||||
if !strings.Contains(output, ip) {
|
||||
@@ -1209,9 +1219,10 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) {
|
||||
for _, test := range table {
|
||||
if test.isNamespaced {
|
||||
// Expect output to include namespace when requested.
|
||||
printer := NewHumanReadablePrinter(PrintOptions{
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
WithNamespace: true,
|
||||
})
|
||||
AddHandlers(printer)
|
||||
buffer := &bytes.Buffer{}
|
||||
err := printer.PrintObj(test.obj, buffer)
|
||||
if err != nil {
|
||||
@@ -1223,7 +1234,7 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) {
|
||||
}
|
||||
} else {
|
||||
// Expect error when trying to get all namespaces for un-namespaced object.
|
||||
printer := NewHumanReadablePrinter(PrintOptions{
|
||||
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
|
||||
WithNamespace: true,
|
||||
})
|
||||
buffer := &bytes.Buffer{}
|
||||
@@ -1319,9 +1330,8 @@ func TestPrintPod(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer := HumanReadablePrinter{}
|
||||
for _, test := range tests {
|
||||
printer.printPod(&test.pod, buf, PrintOptions{ShowAll: true})
|
||||
printPod(&test.pod, buf, printers.PrintOptions{ShowAll: true})
|
||||
// We ignore time
|
||||
if !strings.HasPrefix(buf.String(), test.expect) {
|
||||
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
|
||||
@@ -1413,9 +1423,8 @@ func TestPrintNonTerminatedPod(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer := HumanReadablePrinter{}
|
||||
for _, test := range tests {
|
||||
printer.printPod(&test.pod, buf, PrintOptions{})
|
||||
printPod(&test.pod, buf, printers.PrintOptions{})
|
||||
// We ignore time
|
||||
if !strings.HasPrefix(buf.String(), test.expect) {
|
||||
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
|
||||
@@ -1474,9 +1483,8 @@ func TestPrintPodWithLabels(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer := HumanReadablePrinter{}
|
||||
for _, test := range tests {
|
||||
printer.printPod(&test.pod, buf, PrintOptions{ColumnLabels: test.labelColumns})
|
||||
printPod(&test.pod, buf, printers.PrintOptions{ColumnLabels: test.labelColumns})
|
||||
// We ignore time
|
||||
if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) {
|
||||
t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String())
|
||||
@@ -1554,13 +1562,13 @@ func TestPrintDeployment(t *testing.T) {
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
printDeployment(&test.deployment, buf, PrintOptions{})
|
||||
printDeployment(&test.deployment, buf, printers.PrintOptions{})
|
||||
if buf.String() != test.expect {
|
||||
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
|
||||
}
|
||||
buf.Reset()
|
||||
// print deployment with '-o wide' option
|
||||
printDeployment(&test.deployment, buf, PrintOptions{Wide: true})
|
||||
printDeployment(&test.deployment, buf, printers.PrintOptions{Wide: true})
|
||||
if buf.String() != test.wideExpect {
|
||||
t.Fatalf("Expected: %s, got: %s", test.wideExpect, buf.String())
|
||||
}
|
||||
@@ -1596,7 +1604,7 @@ func TestPrintDaemonSet(t *testing.T) {
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
printDaemonSet(&test.ds, buf, PrintOptions{})
|
||||
printDaemonSet(&test.ds, buf, printers.PrintOptions{})
|
||||
if !strings.HasPrefix(buf.String(), test.startsWith) {
|
||||
t.Fatalf("Expected to start with %s but got %s", test.startsWith, buf.String())
|
||||
}
|
||||
@@ -1644,7 +1652,7 @@ func TestPrintJob(t *testing.T) {
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
printJob(&test.job, buf, PrintOptions{})
|
||||
printJob(&test.job, buf, printers.PrintOptions{})
|
||||
if buf.String() != test.expect {
|
||||
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
|
||||
}
|
||||
@@ -2014,7 +2022,7 @@ func TestPrintHPA(t *testing.T) {
|
||||
|
||||
buff := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
err := printHorizontalPodAutoscaler(&test.hpa, buff, PrintOptions{})
|
||||
err := printHorizontalPodAutoscaler(&test.hpa, buff, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("expected %q, got error: %v", test.expected, err)
|
||||
buff.Reset()
|
||||
@@ -2079,10 +2087,8 @@ func TestPrintPodShowLabels(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer := HumanReadablePrinter{}
|
||||
|
||||
for _, test := range tests {
|
||||
printer.printPod(&test.pod, buf, PrintOptions{ShowLabels: test.showLabels})
|
||||
printPod(&test.pod, buf, printers.PrintOptions{ShowLabels: test.showLabels})
|
||||
// We ignore time
|
||||
if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) {
|
||||
t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String())
|
||||
@@ -2132,7 +2138,7 @@ func TestPrintService(t *testing.T) {
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
printService(&test.service, buf, PrintOptions{})
|
||||
printService(&test.service, buf, printers.PrintOptions{})
|
||||
// We ignore time
|
||||
if buf.String() != test.expect {
|
||||
t.Fatalf("Expected: %s, got: %s %d", test.expect, buf.String(), strings.Compare(test.expect, buf.String()))
|
||||
@@ -2165,7 +2171,7 @@ func TestPrintPodDisruptionBudget(t *testing.T) {
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
for _, test := range tests {
|
||||
printPodDisruptionBudget(&test.pdb, buf, PrintOptions{})
|
||||
printPodDisruptionBudget(&test.pdb, buf, printers.PrintOptions{})
|
||||
if buf.String() != test.expect {
|
||||
t.Fatalf("Expected: %s, got: %s", test.expect, buf.String())
|
||||
}
|
||||
@@ -2190,7 +2196,7 @@ func TestAllowMissingKeys(t *testing.T) {
|
||||
}
|
||||
for _, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer, _, err := GetPrinter(test.Format, test.Template, false, test.AllowMissingTemplateKeys)
|
||||
printer, _, err := printers.GetStandardPrinter(test.Format, test.Template, false, test.AllowMissingTemplateKeys, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme})
|
||||
if err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
}
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubectl
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"reflect"
|
101
pkg/printers/json.go
Normal file
101
pkg/printers/json.go
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
// JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
|
||||
type JSONPrinter struct {
|
||||
}
|
||||
|
||||
func (p *JSONPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
|
||||
func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
switch obj := obj.(type) {
|
||||
case *runtime.Unknown:
|
||||
var buf bytes.Buffer
|
||||
err := json.Indent(&buf, obj.Raw, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteRune('\n')
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = append(data, '\n')
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *JSONPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
|
||||
// The input object is assumed to be in the internal version of an API and is converted
|
||||
// to the given version first.
|
||||
type YAMLPrinter struct {
|
||||
version string
|
||||
converter runtime.ObjectConvertor
|
||||
}
|
||||
|
||||
func (p *YAMLPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj prints the data as YAML.
|
||||
func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
switch obj := obj.(type) {
|
||||
case *runtime.Unknown:
|
||||
data, err := yaml.JSONToYAML(obj.Raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := yaml.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprint(w, string(output))
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *YAMLPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
157
pkg/printers/jsonpath.go
Normal file
157
pkg/printers/jsonpath.go
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
)
|
||||
|
||||
// exists returns true if it would be possible to call the index function
|
||||
// with these arguments.
|
||||
//
|
||||
// TODO: how to document this for users?
|
||||
//
|
||||
// index returns the result of indexing its first argument by the following
|
||||
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
|
||||
// indexed item must be a map, slice, or array.
|
||||
func exists(item interface{}, indices ...interface{}) bool {
|
||||
v := reflect.ValueOf(item)
|
||||
for _, i := range indices {
|
||||
index := reflect.ValueOf(i)
|
||||
var isNil bool
|
||||
if v, isNil = indirect(v); isNil {
|
||||
return false
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.String:
|
||||
var x int64
|
||||
switch index.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
x = index.Int()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
x = int64(index.Uint())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
if x < 0 || x >= int64(v.Len()) {
|
||||
return false
|
||||
}
|
||||
v = v.Index(int(x))
|
||||
case reflect.Map:
|
||||
if !index.IsValid() {
|
||||
index = reflect.Zero(v.Type().Key())
|
||||
}
|
||||
if !index.Type().AssignableTo(v.Type().Key()) {
|
||||
return false
|
||||
}
|
||||
if x := v.MapIndex(index); x.IsValid() {
|
||||
v = x
|
||||
} else {
|
||||
v = reflect.Zero(v.Type().Elem())
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
if _, isNil := indirect(v); isNil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// stolen from text/template
|
||||
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
||||
// We indirect through pointers and empty interfaces (only) because
|
||||
// non-empty interfaces have methods we might need.
|
||||
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
||||
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
|
||||
if v.IsNil() {
|
||||
return v, true
|
||||
}
|
||||
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return v, false
|
||||
}
|
||||
|
||||
// JSONPathPrinter is an implementation of ResourcePrinter which formats data with jsonpath expression.
|
||||
type JSONPathPrinter struct {
|
||||
rawTemplate string
|
||||
*jsonpath.JSONPath
|
||||
}
|
||||
|
||||
func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
|
||||
j := jsonpath.New("out")
|
||||
if err := j.Parse(tmpl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &JSONPathPrinter{tmpl, j}, nil
|
||||
}
|
||||
|
||||
func (j *JSONPathPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj formats the obj with the JSONPath Template.
|
||||
func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
var queryObj interface{} = obj
|
||||
if meta.IsListType(obj) {
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryObj = map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &queryObj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if unknown, ok := obj.(*runtime.Unknown); ok {
|
||||
data, err := json.Marshal(unknown)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryObj = map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &queryObj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if unstructured, ok := obj.(runtime.Unstructured); ok {
|
||||
queryObj = unstructured.UnstructuredContent()
|
||||
}
|
||||
|
||||
if err := j.JSONPath.Execute(w, queryObj); err != nil {
|
||||
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
|
||||
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
|
||||
fmt.Fprintf(w, "\tobject given to jsonpath engine was:\n\t\t%#v\n\n", queryObj)
|
||||
return fmt.Errorf("error executing jsonpath %q: %v\n", j.rawTemplate, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *JSONPathPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
91
pkg/printers/name.go
Normal file
91
pkg/printers/name.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
// NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
|
||||
type NamePrinter struct {
|
||||
Decoders []runtime.Decoder
|
||||
Typer runtime.ObjectTyper
|
||||
Mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
func (p *NamePrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
|
||||
// and print "resource/name" pair. If the object is a List, print all items in it.
|
||||
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
if meta.IsListType(obj) {
|
||||
items, err := meta.ExtractList(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if errs := runtime.DecodeList(items, p.Decoders...); len(errs) > 0 {
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
for _, obj := range items {
|
||||
if err := p.PrintObj(obj, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
name := "<unknown>"
|
||||
if acc, err := meta.Accessor(obj); err == nil {
|
||||
if n := acc.GetName(); len(n) > 0 {
|
||||
name = n
|
||||
}
|
||||
}
|
||||
|
||||
kind := obj.GetObjectKind().GroupVersionKind()
|
||||
if len(kind.Kind) == 0 {
|
||||
if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
|
||||
for _, gvk := range gvks {
|
||||
if mappings, err := p.Mapper.RESTMappings(gvk.GroupKind(), gvk.Version); err == nil && len(mappings) > 0 {
|
||||
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "<unknown>/%s\n", name)
|
||||
}
|
||||
|
||||
} else {
|
||||
if mappings, err := p.Mapper.RESTMappings(kind.GroupKind(), kind.Version); err == nil && len(mappings) > 0 {
|
||||
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
|
||||
} else {
|
||||
fmt.Fprintf(w, "<unknown>/%s\n", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *NamePrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
116
pkg/printers/printers.go
Normal file
116
pkg/printers/printers.go
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// GetStandardPrinter takes a format type, an optional format argument. It will return true
|
||||
// if the format is generic (untyped), otherwise it will return false. The printer
|
||||
// is agnostic to schema versions, so you must send arguments to PrintObj in the
|
||||
// version you wish them to be shown using a VersionedPrinter (typically when
|
||||
// generic is true).
|
||||
func GetStandardPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (ResourcePrinter, bool, error) {
|
||||
var printer ResourcePrinter
|
||||
switch format {
|
||||
case "json":
|
||||
printer = &JSONPrinter{}
|
||||
case "yaml":
|
||||
printer = &YAMLPrinter{}
|
||||
case "name":
|
||||
printer = &NamePrinter{
|
||||
Typer: typer,
|
||||
Decoders: decoders,
|
||||
Mapper: mapper,
|
||||
}
|
||||
case "template", "go-template":
|
||||
if len(formatArgument) == 0 {
|
||||
return nil, false, fmt.Errorf("template format specified but no template given")
|
||||
}
|
||||
templatePrinter, err := NewTemplatePrinter([]byte(formatArgument))
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
|
||||
}
|
||||
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||
printer = templatePrinter
|
||||
case "templatefile", "go-template-file":
|
||||
if len(formatArgument) == 0 {
|
||||
return nil, false, fmt.Errorf("templatefile format specified but no template file given")
|
||||
}
|
||||
data, err := ioutil.ReadFile(formatArgument)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||
}
|
||||
templatePrinter, err := NewTemplatePrinter(data)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
||||
}
|
||||
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||
printer = templatePrinter
|
||||
case "jsonpath":
|
||||
if len(formatArgument) == 0 {
|
||||
return nil, false, fmt.Errorf("jsonpath template format specified but no template given")
|
||||
}
|
||||
jsonpathPrinter, err := NewJSONPathPrinter(formatArgument)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
|
||||
}
|
||||
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||
printer = jsonpathPrinter
|
||||
case "jsonpath-file":
|
||||
if len(formatArgument) == 0 {
|
||||
return nil, false, fmt.Errorf("jsonpath file format specified but no template file file given")
|
||||
}
|
||||
data, err := ioutil.ReadFile(formatArgument)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||
}
|
||||
jsonpathPrinter, err := NewJSONPathPrinter(string(data))
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
|
||||
}
|
||||
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
|
||||
printer = jsonpathPrinter
|
||||
case "custom-columns":
|
||||
var err error
|
||||
if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, decoders[0], noHeaders); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
case "custom-columns-file":
|
||||
file, err := os.Open(formatArgument)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
|
||||
}
|
||||
defer file.Close()
|
||||
if printer, err = NewCustomColumnsPrinterFromTemplate(file, decoders[0]); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
case "wide":
|
||||
fallthrough
|
||||
case "":
|
||||
return nil, false, nil
|
||||
default:
|
||||
return nil, false, fmt.Errorf("output format %q not recognized", format)
|
||||
}
|
||||
return printer, true, nil
|
||||
}
|
35
pkg/printers/tabwriter.go
Normal file
35
pkg/printers/tabwriter.go
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
const (
|
||||
tabwriterMinWidth = 10
|
||||
tabwriterWidth = 4
|
||||
tabwriterPadding = 3
|
||||
tabwriterPadChar = ' '
|
||||
tabwriterFlags = 0
|
||||
)
|
||||
|
||||
// GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
|
||||
func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
|
||||
return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
|
||||
}
|
110
pkg/printers/template.go
Normal file
110
pkg/printers/template.go
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/template"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
|
||||
type TemplatePrinter struct {
|
||||
rawTemplate string
|
||||
template *template.Template
|
||||
}
|
||||
|
||||
func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
|
||||
t, err := template.New("output").
|
||||
Funcs(template.FuncMap{"exists": exists}).
|
||||
Parse(string(tmpl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TemplatePrinter{
|
||||
rawTemplate: string(tmpl),
|
||||
template: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AllowMissingKeys tells the template engine if missing keys are allowed.
|
||||
func (p *TemplatePrinter) AllowMissingKeys(allow bool) {
|
||||
if allow {
|
||||
p.template.Option("missingkey=default")
|
||||
} else {
|
||||
p.template.Option("missingkey=error")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TemplatePrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj formats the obj with the Go Template.
|
||||
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
var data []byte
|
||||
var err error
|
||||
data, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = p.safeExecute(w, out); err != nil {
|
||||
// It is way easier to debug this stuff when it shows up in
|
||||
// stdout instead of just stdin. So in addition to returning
|
||||
// a nice error, also print useful stuff with the writer.
|
||||
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
|
||||
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", p.rawTemplate)
|
||||
fmt.Fprintf(w, "\traw data was:\n\t\t%v\n", string(data))
|
||||
fmt.Fprintf(w, "\tobject given to template engine was:\n\t\t%+v\n\n", out)
|
||||
return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *TemplatePrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// safeExecute tries to execute the template, but catches panics and returns an error
|
||||
// should the template engine panic.
|
||||
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
|
||||
var panicErr error
|
||||
// Sorry for the double anonymous function. There's probably a clever way
|
||||
// to do this that has the defer'd func setting the value to be returned, but
|
||||
// that would be even less obvious.
|
||||
retErr := func() error {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
panicErr = fmt.Errorf("caught panic: %+v", x)
|
||||
}
|
||||
}()
|
||||
return p.template.Execute(w, obj)
|
||||
}()
|
||||
if panicErr != nil {
|
||||
return panicErr
|
||||
}
|
||||
return retErr
|
||||
}
|
63
pkg/printers/versioned.go
Normal file
63
pkg/printers/versioned.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package printers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// VersionedPrinter takes runtime objects and ensures they are converted to a given API version
|
||||
// prior to being passed to a nested printer.
|
||||
type VersionedPrinter struct {
|
||||
printer ResourcePrinter
|
||||
converter runtime.ObjectConvertor
|
||||
versions []schema.GroupVersion
|
||||
}
|
||||
|
||||
// NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
|
||||
func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...schema.GroupVersion) ResourcePrinter {
|
||||
return &VersionedPrinter{
|
||||
printer: printer,
|
||||
converter: converter,
|
||||
versions: versions,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *VersionedPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintObj implements ResourcePrinter
|
||||
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
if len(p.versions) == 0 {
|
||||
return fmt.Errorf("no version specified, object cannot be converted")
|
||||
}
|
||||
converted, err := p.converter.ConvertToVersion(obj, schema.GroupVersions(p.versions))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.printer.PrintObj(converted, w)
|
||||
}
|
||||
|
||||
// TODO: implement HandledResources()
|
||||
func (p *VersionedPrinter) HandledResources() []string {
|
||||
return []string{}
|
||||
}
|
@@ -73,11 +73,24 @@ func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
|
||||
}
|
||||
return obj.Object
|
||||
}
|
||||
|
||||
// UnstructuredContent returns a map contain an overlay of the Items field onto
|
||||
// the Object field. Items always overwrites overlay. Changing "items" in the
|
||||
// returned object will affect items in the underlying Items field, but changing
|
||||
// the "items" slice itself will have no effect.
|
||||
// TODO: expose SetUnstructuredContent on runtime.Unstructured that allows
|
||||
// items to be changed.
|
||||
func (obj *UnstructuredList) UnstructuredContent() map[string]interface{} {
|
||||
if obj.Object == nil {
|
||||
obj.Object = make(map[string]interface{})
|
||||
out := obj.Object
|
||||
if out == nil {
|
||||
out = make(map[string]interface{})
|
||||
}
|
||||
return obj.Object
|
||||
items := make([]interface{}, len(obj.Items))
|
||||
for i, item := range obj.Items {
|
||||
items[i] = item.Object
|
||||
}
|
||||
out["items"] = items
|
||||
return out
|
||||
}
|
||||
|
||||
// MarshalJSON ensures that the unstructured object produces proper
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package unstructured
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUnstructuredList(t *testing.T) {
|
||||
list := &UnstructuredList{
|
||||
Object: map[string]interface{}{"kind": "List", "apiVersion": "v1"},
|
||||
Items: []*Unstructured{
|
||||
{Object: map[string]interface{}{"kind": "Pod", "apiVersion": "v1", "metadata": map[string]interface{}{"name": "test"}}},
|
||||
},
|
||||
}
|
||||
content := list.UnstructuredContent()
|
||||
items := content["items"].([]interface{})
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("unexpected items: %#v", items)
|
||||
}
|
||||
if getNestedField(items[0].(map[string]interface{}), "metadata", "name") != "test" {
|
||||
t.Fatalf("unexpected fields: %#v", items[0])
|
||||
}
|
||||
}
|
7
vendor/BUILD
vendored
7
vendor/BUILD
vendored
@@ -17116,3 +17116,10 @@ go_library(
|
||||
"//vendor:k8s.io/kube-aggregator/pkg/apis/apiregistration/install",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured_test",
|
||||
srcs = ["k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go"],
|
||||
library = ":k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
Reference in New Issue
Block a user