Refactor printers to separate typed printers from generic code

This commit is contained in:
Clayton Coleman 2017-02-19 17:37:24 -05:00
parent 6d1c7308a5
commit 3704ceffd2
No known key found for this signature in database
GPG Key ID: 3D16906B4F1C5CB3
16 changed files with 729 additions and 529 deletions

View File

@ -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",

View File

@ -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))
}

View File

@ -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",

View File

@ -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) {

41
pkg/printers/common.go Normal file
View 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))
}

View File

@ -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
}

View File

@ -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(),
}

View File

@ -17,14 +17,23 @@ 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
@ -49,20 +58,9 @@ func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
handlerMap: make(map[reflect.Type]*handlerEntry),
options: options,
}
printer.addDefaultHandlers()
return printer
}
// formatResourceName receives a resource kind, name, and boolean specifying
// whether or not to update the current name to "kind/name"
func formatResourceName(kind, name string, withKind bool) string {
if !withKind || kind == "" {
return name
}
return kind + "/" + name
}
// GetResourceKind returns the type currently set for a resource
func (h *HumanReadablePrinter) GetResourceKind() string {
return h.options.Kind
@ -157,3 +155,175 @@ func (h *HumanReadablePrinter) printHeader(columnNames []string, w io.Writer) er
}
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()
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
@ -60,3 +61,36 @@ type PrintOptions struct {
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)
}

View File

@ -0,0 +1,113 @@
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/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",
"//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"],
)

View File

@ -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()),
}
}

View File

@ -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)
}

View File

@ -20,19 +20,12 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
"sort"
"strings"
"text/tabwriter"
"time"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/pkg/api"
@ -46,98 +39,11 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/node"
)
// GetPrinter 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 GetPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool) (ResourcePrinter, bool, error) {
var printer ResourcePrinter
switch format {
case "json":
printer = &JSONPrinter{}
case "yaml":
printer = &YAMLPrinter{}
case "name":
printer = &NamePrinter{
// TODO: this is wrong, these should be provided as an argument to GetPrinter
Typer: api.Scheme,
Decoder: api.Codecs.UniversalDecoder(),
}
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, api.Codecs.UniversalDecoder(), 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, api.Codecs.UniversalDecoder()); 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
}
const loadBalancerWidth = 16
// NOTE: When adding a new resource type here, please update the list
// pkg/kubectl/cmd/get.go to reflect the new resource type.
@ -184,7 +90,6 @@ var (
// TODO: consider having 'KIND' for third party resource data
thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGETS", "MINPODS", "MAXPODS", "REPLICAS", "AGE"}
withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
deploymentColumns = []string{"NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE"}
deploymentWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
configMapColumns = []string{"NAME", "DATA", "AGE"}
@ -194,7 +99,7 @@ var (
certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"}
)
func printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
func printPod(pod *api.Pod, w io.Writer, options printers.PrintOptions) error {
if err := printPodBase(pod, w, options); err != nil {
return err
}
@ -202,7 +107,7 @@ func printPod(pod *api.Pod, w io.Writer, options PrintOptions) error {
return nil
}
func printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error {
func printPodList(podList *api.PodList, w io.Writer, options printers.PrintOptions) error {
for _, pod := range podList.Items {
if err := printPodBase(&pod, w, options); err != nil {
return err
@ -211,10 +116,10 @@ func printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error
return nil
}
// addDefaultHandlers adds print handlers for default Kubernetes types.
func (h *HumanReadablePrinter) addDefaultHandlers() {
h.Handler(podColumns, podWideColumns, h.printPodList)
h.Handler(podColumns, podWideColumns, h.printPod)
// AddHandlers adds print handlers for default Kubernetes types dealing with internal versions.
func AddHandlers(h *printers.HumanReadablePrinter) {
h.Handler(podColumns, podWideColumns, printPodList)
h.Handler(podColumns, podWideColumns, printPod)
h.Handler(podTemplateColumns, nil, printPodTemplate)
h.Handler(podTemplateColumns, nil, printPodTemplateList)
h.Handler(podDisruptionBudgetColumns, nil, printPodDisruptionBudget)
@ -288,6 +193,16 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
h.Handler(statusColumns, nil, printStatus)
}
// formatResourceName receives a resource kind, name, and boolean specifying
// whether or not to update the current name to "kind/name"
func formatResourceName(kind, name string, withKind bool) string {
if !withKind || kind == "" {
return name
}
return kind + "/" + name
}
// Pass ports=nil for all ports.
func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
if len(endpoints.Subsets) == 0 {
@ -322,35 +237,16 @@ func formatEndpoints(endpoints *api.Endpoints, ports sets.String) string {
return ret
}
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))
}
// translateTimestamp returns the elapsed time since timestamp in
// human-readable approximation.
func translateTimestamp(timestamp metav1.Time) string {
if timestamp.IsZero() {
return "<unknown>"
}
return ShortHumanDuration(time.Now().Sub(timestamp.Time))
return printers.ShortHumanDuration(time.Now().Sub(timestamp.Time))
}
func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
func printPodBase(pod *api.Pod, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, pod.Name, options.WithKind)
namespace := pod.Namespace
@ -459,7 +355,7 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error {
return nil
}
func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error {
func printPodTemplate(pod *api.PodTemplate, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, pod.Name, options.WithKind)
namespace := pod.Namespace
@ -490,7 +386,7 @@ func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) e
return nil
}
func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options PrintOptions) error {
func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options printers.PrintOptions) error {
for _, pod := range podList.Items {
if err := printPodTemplate(&pod, w, options); err != nil {
return err
@ -499,7 +395,7 @@ func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options Pri
return nil
}
func printPodDisruptionBudget(pdb *policy.PodDisruptionBudget, w io.Writer, options PrintOptions) error {
func printPodDisruptionBudget(pdb *policy.PodDisruptionBudget, w io.Writer, options printers.PrintOptions) error {
// name, minavailable, selector
name := formatResourceName(options.Kind, pdb.Name, options.WithKind)
namespace := pdb.Namespace
@ -521,7 +417,7 @@ func printPodDisruptionBudget(pdb *policy.PodDisruptionBudget, w io.Writer, opti
return nil
}
func printPodDisruptionBudgetList(pdbList *policy.PodDisruptionBudgetList, w io.Writer, options PrintOptions) error {
func printPodDisruptionBudgetList(pdbList *policy.PodDisruptionBudgetList, w io.Writer, options printers.PrintOptions) error {
for _, pdb := range pdbList.Items {
if err := printPodDisruptionBudget(&pdb, w, options); err != nil {
return err
@ -531,7 +427,7 @@ func printPodDisruptionBudgetList(pdbList *policy.PodDisruptionBudgetList, w io.
}
// TODO(AdoHe): try to put wide output in a single method
func printReplicationController(controller *api.ReplicationController, w io.Writer, options PrintOptions) error {
func printReplicationController(controller *api.ReplicationController, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, controller.Name, options.WithKind)
namespace := controller.Namespace
@ -574,7 +470,7 @@ func printReplicationController(controller *api.ReplicationController, w io.Writ
return nil
}
func printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer, options PrintOptions) error {
func printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer, options printers.PrintOptions) error {
for _, controller := range list.Items {
if err := printReplicationController(&controller, w, options); err != nil {
return err
@ -583,7 +479,7 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr
return nil
}
func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOptions) error {
func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, rs.Name, options.WithKind)
namespace := rs.Namespace
@ -625,7 +521,7 @@ func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOption
return nil
}
func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options PrintOptions) error {
func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options printers.PrintOptions) error {
for _, rs := range list.Items {
if err := printReplicaSet(&rs, w, options); err != nil {
return err
@ -634,7 +530,7 @@ func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options P
return nil
}
func printCluster(c *federation.Cluster, w io.Writer, options PrintOptions) error {
func printCluster(c *federation.Cluster, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, c.Name, options.WithKind)
var statuses []string
@ -658,7 +554,7 @@ func printCluster(c *federation.Cluster, w io.Writer, options PrintOptions) erro
}
return nil
}
func printClusterList(list *federation.ClusterList, w io.Writer, options PrintOptions) error {
func printClusterList(list *federation.ClusterList, w io.Writer, options printers.PrintOptions) error {
for _, rs := range list.Items {
if err := printCluster(&rs, w, options); err != nil {
return err
@ -667,7 +563,7 @@ func printClusterList(list *federation.ClusterList, w io.Writer, options PrintOp
return nil
}
func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
func printJob(job *batch.Job, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, job.Name, options.WithKind)
namespace := job.Namespace
@ -721,7 +617,7 @@ func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
return nil
}
func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error {
func printJobList(list *batch.JobList, w io.Writer, options printers.PrintOptions) error {
for _, job := range list.Items {
if err := printJob(&job, w, options); err != nil {
return err
@ -730,7 +626,7 @@ func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error
return nil
}
func printCronJob(cronJob *batch.CronJob, w io.Writer, options PrintOptions) error {
func printCronJob(cronJob *batch.CronJob, w io.Writer, options printers.PrintOptions) error {
name := cronJob.Name
namespace := cronJob.Namespace
@ -757,7 +653,7 @@ func printCronJob(cronJob *batch.CronJob, w io.Writer, options PrintOptions) err
return nil
}
func printCronJobList(list *batch.CronJobList, w io.Writer, options PrintOptions) error {
func printCronJobList(list *batch.CronJobList, w io.Writer, options printers.PrintOptions) error {
for _, cronJob := range list.Items {
if err := printCronJob(&cronJob, w, options); err != nil {
return err
@ -825,7 +721,7 @@ func makePortString(ports []api.ServicePort) string {
return strings.Join(pieces, ",")
}
func printService(svc *api.Service, w io.Writer, options PrintOptions) error {
func printService(svc *api.Service, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, svc.Name, options.WithKind)
namespace := svc.Namespace
@ -859,7 +755,7 @@ func printService(svc *api.Service, w io.Writer, options PrintOptions) error {
return err
}
func printServiceList(list *api.ServiceList, w io.Writer, options PrintOptions) error {
func printServiceList(list *api.ServiceList, w io.Writer, options printers.PrintOptions) error {
for _, svc := range list.Items {
if err := printService(&svc, w, options); err != nil {
return err
@ -905,7 +801,7 @@ func formatPorts(tls []extensions.IngressTLS) string {
return "80"
}
func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions) error {
func printIngress(ingress *extensions.Ingress, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, ingress.Name, options.WithKind)
namespace := ingress.Namespace
@ -935,7 +831,7 @@ func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions
return nil
}
func printIngressList(ingressList *extensions.IngressList, w io.Writer, options PrintOptions) error {
func printIngressList(ingressList *extensions.IngressList, w io.Writer, options printers.PrintOptions) error {
for _, ingress := range ingressList.Items {
if err := printIngress(&ingress, w, options); err != nil {
return err
@ -944,7 +840,7 @@ func printIngressList(ingressList *extensions.IngressList, w io.Writer, options
return nil
}
func printStatefulSet(ps *apps.StatefulSet, w io.Writer, options PrintOptions) error {
func printStatefulSet(ps *apps.StatefulSet, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, ps.Name, options.WithKind)
namespace := ps.Namespace
@ -983,7 +879,7 @@ func printStatefulSet(ps *apps.StatefulSet, w io.Writer, options PrintOptions) e
return nil
}
func printStatefulSetList(statefulSetList *apps.StatefulSetList, w io.Writer, options PrintOptions) error {
func printStatefulSetList(statefulSetList *apps.StatefulSetList, w io.Writer, options printers.PrintOptions) error {
for _, ps := range statefulSetList.Items {
if err := printStatefulSet(&ps, w, options); err != nil {
return err
@ -992,7 +888,7 @@ func printStatefulSetList(statefulSetList *apps.StatefulSetList, w io.Writer, op
return nil
}
func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error {
func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, ds.Name, options.WithKind)
namespace := ds.Namespace
@ -1041,7 +937,7 @@ func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions)
return nil
}
func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options PrintOptions) error {
func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options printers.PrintOptions) error {
for _, ds := range list.Items {
if err := printDaemonSet(&ds, w, options); err != nil {
return err
@ -1050,7 +946,7 @@ func printDaemonSetList(list *extensions.DaemonSetList, w io.Writer, options Pri
return nil
}
func printEndpoints(endpoints *api.Endpoints, w io.Writer, options PrintOptions) error {
func printEndpoints(endpoints *api.Endpoints, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, endpoints.Name, options.WithKind)
namespace := endpoints.Namespace
@ -1070,7 +966,7 @@ func printEndpoints(endpoints *api.Endpoints, w io.Writer, options PrintOptions)
return err
}
func printEndpointsList(list *api.EndpointsList, w io.Writer, options PrintOptions) error {
func printEndpointsList(list *api.EndpointsList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printEndpoints(&item, w, options); err != nil {
return err
@ -1079,7 +975,7 @@ func printEndpointsList(list *api.EndpointsList, w io.Writer, options PrintOptio
return nil
}
func printNamespace(item *api.Namespace, w io.Writer, options PrintOptions) error {
func printNamespace(item *api.Namespace, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, item.Name, options.WithKind)
if options.WithNamespace {
@ -1096,7 +992,7 @@ func printNamespace(item *api.Namespace, w io.Writer, options PrintOptions) erro
return err
}
func printNamespaceList(list *api.NamespaceList, w io.Writer, options PrintOptions) error {
func printNamespaceList(list *api.NamespaceList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printNamespace(&item, w, options); err != nil {
return err
@ -1105,7 +1001,7 @@ func printNamespaceList(list *api.NamespaceList, w io.Writer, options PrintOptio
return nil
}
func printSecret(item *api.Secret, w io.Writer, options PrintOptions) error {
func printSecret(item *api.Secret, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, item.Name, options.WithKind)
namespace := item.Namespace
@ -1125,7 +1021,7 @@ func printSecret(item *api.Secret, w io.Writer, options PrintOptions) error {
return err
}
func printSecretList(list *api.SecretList, w io.Writer, options PrintOptions) error {
func printSecretList(list *api.SecretList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printSecret(&item, w, options); err != nil {
return err
@ -1135,7 +1031,7 @@ func printSecretList(list *api.SecretList, w io.Writer, options PrintOptions) er
return nil
}
func printServiceAccount(item *api.ServiceAccount, w io.Writer, options PrintOptions) error {
func printServiceAccount(item *api.ServiceAccount, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, item.Name, options.WithKind)
namespace := item.Namespace
@ -1155,7 +1051,7 @@ func printServiceAccount(item *api.ServiceAccount, w io.Writer, options PrintOpt
return err
}
func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options PrintOptions) error {
func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printServiceAccount(&item, w, options); err != nil {
return err
@ -1165,7 +1061,7 @@ func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, options
return nil
}
func printNode(node *api.Node, w io.Writer, options PrintOptions) error {
func printNode(node *api.Node, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, node.Name, options.WithKind)
if options.WithNamespace {
@ -1249,7 +1145,7 @@ func findNodeRole(node *api.Node) string {
return ""
}
func printNodeList(list *api.NodeList, w io.Writer, options PrintOptions) error {
func printNodeList(list *api.NodeList, w io.Writer, options printers.PrintOptions) error {
for _, node := range list.Items {
if err := printNode(&node, w, options); err != nil {
return err
@ -1258,7 +1154,7 @@ func printNodeList(list *api.NodeList, w io.Writer, options PrintOptions) error
return nil
}
func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options PrintOptions) error {
func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, pv.Name, options.WithKind)
if options.WithNamespace {
@ -1296,7 +1192,7 @@ func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, options PrintO
return err
}
func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, options PrintOptions) error {
func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, options printers.PrintOptions) error {
for _, pv := range list.Items {
if err := printPersistentVolume(&pv, w, options); err != nil {
return err
@ -1305,7 +1201,7 @@ func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, opti
return nil
}
func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, options PrintOptions) error {
func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, pvc.Name, options.WithKind)
namespace := pvc.Namespace
@ -1336,7 +1232,7 @@ func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, opt
return err
}
func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Writer, options PrintOptions) error {
func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Writer, options printers.PrintOptions) error {
for _, psd := range list.Items {
if err := printPersistentVolumeClaim(&psd, w, options); err != nil {
return err
@ -1345,7 +1241,7 @@ func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Wr
return nil
}
func printEvent(event *api.Event, w io.Writer, options PrintOptions) error {
func printEvent(event *api.Event, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, event.InvolvedObject.Name, options.WithKind)
namespace := event.Namespace
@ -1388,7 +1284,7 @@ func printEvent(event *api.Event, w io.Writer, options PrintOptions) error {
}
// Sorts and prints the EventList in a human-friendly format.
func printEventList(list *api.EventList, w io.Writer, options PrintOptions) error {
func printEventList(list *api.EventList, w io.Writer, options printers.PrintOptions) error {
sort.Sort(events.SortableEvents(list.Items))
for i := range list.Items {
if err := printEvent(&list.Items[i], w, options); err != nil {
@ -1398,12 +1294,12 @@ func printEventList(list *api.EventList, w io.Writer, options PrintOptions) erro
return nil
}
func printLimitRange(limitRange *api.LimitRange, w io.Writer, options PrintOptions) error {
func printLimitRange(limitRange *api.LimitRange, w io.Writer, options printers.PrintOptions) error {
return printObjectMeta(limitRange.ObjectMeta, w, options, true)
}
// Prints the LimitRangeList in a human-friendly format.
func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options PrintOptions) error {
func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printLimitRange(&list.Items[i], w, options); err != nil {
return err
@ -1413,7 +1309,7 @@ func printLimitRangeList(list *api.LimitRangeList, w io.Writer, options PrintOpt
}
// printObjectMeta prints the object metadata of a given resource.
func printObjectMeta(meta metav1.ObjectMeta, w io.Writer, options PrintOptions, namespaced bool) error {
func printObjectMeta(meta metav1.ObjectMeta, w io.Writer, options printers.PrintOptions, namespaced bool) error {
name := formatResourceName(options.Kind, meta.Name, options.WithKind)
if namespaced && options.WithNamespace {
@ -1436,12 +1332,12 @@ func printObjectMeta(meta metav1.ObjectMeta, w io.Writer, options PrintOptions,
return err
}
func printResourceQuota(resourceQuota *api.ResourceQuota, w io.Writer, options PrintOptions) error {
func printResourceQuota(resourceQuota *api.ResourceQuota, w io.Writer, options printers.PrintOptions) error {
return printObjectMeta(resourceQuota.ObjectMeta, w, options, true)
}
// Prints the ResourceQuotaList in a human-friendly format.
func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, options PrintOptions) error {
func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printResourceQuota(&list.Items[i], w, options); err != nil {
return err
@ -1450,12 +1346,12 @@ func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, options Pr
return nil
}
func printRole(role *rbac.Role, w io.Writer, options PrintOptions) error {
func printRole(role *rbac.Role, w io.Writer, options printers.PrintOptions) error {
return printObjectMeta(role.ObjectMeta, w, options, true)
}
// Prints the Role in a human-friendly format.
func printRoleList(list *rbac.RoleList, w io.Writer, options PrintOptions) error {
func printRoleList(list *rbac.RoleList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printRole(&list.Items[i], w, options); err != nil {
return err
@ -1464,7 +1360,7 @@ func printRoleList(list *rbac.RoleList, w io.Writer, options PrintOptions) error
return nil
}
func printRoleBinding(roleBinding *rbac.RoleBinding, w io.Writer, options PrintOptions) error {
func printRoleBinding(roleBinding *rbac.RoleBinding, w io.Writer, options printers.PrintOptions) error {
meta := roleBinding.ObjectMeta
name := formatResourceName(options.Kind, meta.Name, options.WithKind)
@ -1503,7 +1399,7 @@ func printRoleBinding(roleBinding *rbac.RoleBinding, w io.Writer, options PrintO
}
// Prints the RoleBinding in a human-friendly format.
func printRoleBindingList(list *rbac.RoleBindingList, w io.Writer, options PrintOptions) error {
func printRoleBindingList(list *rbac.RoleBindingList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printRoleBinding(&list.Items[i], w, options); err != nil {
return err
@ -1512,7 +1408,7 @@ func printRoleBindingList(list *rbac.RoleBindingList, w io.Writer, options Print
return nil
}
func printClusterRole(clusterRole *rbac.ClusterRole, w io.Writer, options PrintOptions) error {
func printClusterRole(clusterRole *rbac.ClusterRole, w io.Writer, options printers.PrintOptions) error {
if options.WithNamespace {
return fmt.Errorf("clusterRole is not namespaced")
}
@ -1520,7 +1416,7 @@ func printClusterRole(clusterRole *rbac.ClusterRole, w io.Writer, options PrintO
}
// Prints the ClusterRole in a human-friendly format.
func printClusterRoleList(list *rbac.ClusterRoleList, w io.Writer, options PrintOptions) error {
func printClusterRoleList(list *rbac.ClusterRoleList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printClusterRole(&list.Items[i], w, options); err != nil {
return err
@ -1529,7 +1425,7 @@ func printClusterRoleList(list *rbac.ClusterRoleList, w io.Writer, options Print
return nil
}
func printClusterRoleBinding(clusterRoleBinding *rbac.ClusterRoleBinding, w io.Writer, options PrintOptions) error {
func printClusterRoleBinding(clusterRoleBinding *rbac.ClusterRoleBinding, w io.Writer, options printers.PrintOptions) error {
meta := clusterRoleBinding.ObjectMeta
name := formatResourceName(options.Kind, meta.Name, options.WithKind)
@ -1566,7 +1462,7 @@ func printClusterRoleBinding(clusterRoleBinding *rbac.ClusterRoleBinding, w io.W
}
// Prints the ClusterRoleBinding in a human-friendly format.
func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer, options PrintOptions) error {
func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printClusterRoleBinding(&list.Items[i], w, options); err != nil {
return err
@ -1575,7 +1471,7 @@ func printClusterRoleBindingList(list *rbac.ClusterRoleBindingList, w io.Writer,
return nil
}
func printCertificateSigningRequest(csr *certificates.CertificateSigningRequest, w io.Writer, options PrintOptions) error {
func printCertificateSigningRequest(csr *certificates.CertificateSigningRequest, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, csr.Name, options.WithKind)
meta := csr.ObjectMeta
@ -1627,7 +1523,7 @@ func extractCSRStatus(csr *certificates.CertificateSigningRequest) (string, erro
return status, nil
}
func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, w io.Writer, options PrintOptions) error {
func printCertificateSigningRequestList(list *certificates.CertificateSigningRequestList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printCertificateSigningRequest(&list.Items[i], w, options); err != nil {
return err
@ -1636,7 +1532,7 @@ func printCertificateSigningRequestList(list *certificates.CertificateSigningReq
return nil
}
func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintOptions) error {
func printComponentStatus(item *api.ComponentStatus, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, item.Name, options.WithKind)
if options.WithNamespace {
@ -1668,7 +1564,7 @@ func printComponentStatus(item *api.ComponentStatus, w io.Writer, options PrintO
return err
}
func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, options PrintOptions) error {
func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printComponentStatus(&item, w, options); err != nil {
return err
@ -1678,7 +1574,7 @@ func printComponentStatusList(list *api.ComponentStatusList, w io.Writer, option
return nil
}
func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, options PrintOptions) error {
func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
versions := make([]string, len(rsrc.Versions))
@ -1693,7 +1589,7 @@ func printThirdPartyResource(rsrc *extensions.ThirdPartyResource, w io.Writer, o
return nil
}
func printThirdPartyResourceList(list *extensions.ThirdPartyResourceList, w io.Writer, options PrintOptions) error {
func printThirdPartyResourceList(list *extensions.ThirdPartyResourceList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printThirdPartyResource(&item, w, options); err != nil {
return err
@ -1710,7 +1606,7 @@ func truncate(str string, maxLen int) string {
return str
}
func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.Writer, options PrintOptions) error {
func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, rsrc.Name, options.WithKind)
l := labels.FormatLabels(rsrc.Labels)
@ -1724,7 +1620,7 @@ func printThirdPartyResourceData(rsrc *extensions.ThirdPartyResourceData, w io.W
return nil
}
func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList, w io.Writer, options PrintOptions) error {
func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printThirdPartyResourceData(&item, w, options); err != nil {
return err
@ -1734,7 +1630,7 @@ func printThirdPartyResourceDataList(list *extensions.ThirdPartyResourceDataList
return nil
}
func printDeployment(deployment *extensions.Deployment, w io.Writer, options PrintOptions) error {
func printDeployment(deployment *extensions.Deployment, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, deployment.Name, options.WithKind)
if options.WithNamespace {
@ -1774,7 +1670,7 @@ func printDeployment(deployment *extensions.Deployment, w io.Writer, options Pri
return err
}
func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options PrintOptions) error {
func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printDeployment(&item, w, options); err != nil {
return err
@ -1843,7 +1739,7 @@ func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.Met
return ret
}
func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error {
func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options printers.PrintOptions) error {
namespace := hpa.Namespace
name := formatResourceName(options.Kind, hpa.Name, options.WithKind)
@ -1882,7 +1778,7 @@ func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io
return err
}
func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, w io.Writer, options PrintOptions) error {
func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printHorizontalPodAutoscaler(&list.Items[i], w, options); err != nil {
return err
@ -1891,7 +1787,7 @@ func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerL
return nil
}
func printConfigMap(configMap *api.ConfigMap, w io.Writer, options PrintOptions) error {
func printConfigMap(configMap *api.ConfigMap, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, configMap.Name, options.WithKind)
namespace := configMap.Namespace
@ -1911,7 +1807,7 @@ func printConfigMap(configMap *api.ConfigMap, w io.Writer, options PrintOptions)
return err
}
func printConfigMapList(list *api.ConfigMapList, w io.Writer, options PrintOptions) error {
func printConfigMapList(list *api.ConfigMapList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printConfigMap(&list.Items[i], w, options); err != nil {
return err
@ -1920,7 +1816,7 @@ func printConfigMapList(list *api.ConfigMapList, w io.Writer, options PrintOptio
return nil
}
func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, options PrintOptions) error {
func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, item.Name, options.WithKind)
_, err := fmt.Fprintf(w, "%s\t%t\t%v\t%s\t%s\t%s\t%s\t%t\t%v\n", name, item.Spec.Privileged,
@ -1929,7 +1825,7 @@ func printPodSecurityPolicy(item *extensions.PodSecurityPolicy, w io.Writer, opt
return err
}
func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Writer, options PrintOptions) error {
func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Writer, options printers.PrintOptions) error {
for _, item := range list.Items {
if err := printPodSecurityPolicy(&item, w, options); err != nil {
return err
@ -1939,7 +1835,7 @@ func printPodSecurityPolicyList(list *extensions.PodSecurityPolicyList, w io.Wri
return nil
}
func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, options PrintOptions) error {
func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, options printers.PrintOptions) error {
name := formatResourceName(options.Kind, networkPolicy.Name, options.WithKind)
namespace := networkPolicy.Namespace
@ -1959,7 +1855,7 @@ func printNetworkPolicy(networkPolicy *extensions.NetworkPolicy, w io.Writer, op
return err
}
func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, options PrintOptions) error {
func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, options printers.PrintOptions) error {
for i := range list.Items {
if err := printNetworkPolicy(&list.Items[i], w, options); err != nil {
return err
@ -1968,7 +1864,7 @@ func printNetworkPolicyList(list *extensions.NetworkPolicyList, w io.Writer, opt
return nil
}
func printStorageClass(sc *storage.StorageClass, w io.Writer, options PrintOptions) error {
func printStorageClass(sc *storage.StorageClass, w io.Writer, options printers.PrintOptions) error {
name := sc.Name
if storageutil.IsDefaultAnnotation(sc.ObjectMeta) {
@ -1989,7 +1885,7 @@ func printStorageClass(sc *storage.StorageClass, w io.Writer, options PrintOptio
return nil
}
func printStorageClassList(scList *storage.StorageClassList, w io.Writer, options PrintOptions) error {
func printStorageClassList(scList *storage.StorageClassList, w io.Writer, options printers.PrintOptions) error {
for _, sc := range scList.Items {
if err := printStorageClass(&sc, w, options); err != nil {
return err
@ -1998,7 +1894,7 @@ func printStorageClassList(scList *storage.StorageClassList, w io.Writer, option
return nil
}
func printStatus(status *metav1.Status, w io.Writer, options PrintOptions) error {
func printStatus(status *metav1.Status, w io.Writer, options printers.PrintOptions) error {
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", status.Status, status.Reason, status.Message); err != nil {
return err
}
@ -2068,149 +1964,6 @@ func layoutContainers(containers []api.Container, w io.Writer) error {
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 {
if t.String() != "*api.ThirdPartyResource" && t.String() != "*api.ThirdPartyResourceList" {
return []string{"LABELS"}
}
}
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)
}
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 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
}
// formatEventSource formats EventSource as a comma separated string excluding Host when empty
func formatEventSource(es api.EventSource) string {
EventSourceString := []string{es.Component}

View File

@ -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)
}
@ -134,12 +136,12 @@ func TestPrinter(t *testing.T) {
}
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)
}
@ -357,7 +359,7 @@ func TestNamePrinter(t *testing.T) {
},
"pod/foo\npod/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{
Typer: api.Scheme,
Decoder: api.Codecs.UniversalDecoder(),
"name": &printers.NamePrinter{
Typer: api.Scheme,
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)
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package kubectl
package internalversion
import (
"reflect"

View File

@ -27,7 +27,6 @@ const (
tabwriterPadding = 3
tabwriterPadChar = ' '
tabwriterFlags = 0
loadBalancerWidth = 16
)
// GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.