vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

View File

@ -0,0 +1,10 @@
{
"Rules": [
{
"SelectorRegexp": "k8s[.]io/kubernetes/pkg/(api$|apis/)",
"ForbiddenPrefixes": [
"k8s.io/kubernetes/pkg/printers"
]
}
]
}

81
vendor/k8s.io/kubernetes/pkg/printers/BUILD generated vendored Normal file
View File

@ -0,0 +1,81 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"common.go",
"customcolumn.go",
"humanreadable.go",
"interface.go",
"json.go",
"jsonpath.go",
"name.go",
"printers.go",
"tabwriter.go",
"template.go",
"versioned.go",
],
importpath = "k8s.io/kubernetes/pkg/printers",
deps = [
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/client-go/util/jsonpath:go_default_library",
],
)
go_test(
name = "go_default_xtest",
srcs = ["customcolumn_test.go"],
importpath = "k8s.io/kubernetes/pkg/printers_test",
deps = [
":go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/printers/internalversion:all-srcs",
"//pkg/printers/storage:all-srcs",
],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["humanreadable_test.go"],
importpath = "k8s.io/kubernetes/pkg/printers",
library = ":go_default_library",
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
],
)

6
vendor/k8s.io/kubernetes/pkg/printers/OWNERS generated vendored Normal file
View File

@ -0,0 +1,6 @@
approvers:
- smarterclayton
- sig-cli-maintainers
reviewers:
- smarterclayton
- sig-cli

41
vendor/k8s.io/kubernetes/pkg/printers/common.go generated vendored 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*365 {
return fmt.Sprintf("%dd", hours/24)
}
return fmt.Sprintf("%dy", int(d.Hours()/24/365))
}

250
vendor/k8s.io/kubernetes/pkg/printers/customcolumn.go generated vendored Normal file
View File

@ -0,0 +1,250 @@
/*
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 (
"bufio"
"bytes"
"fmt"
"io"
"reflect"
"regexp"
"strings"
"text/tabwriter"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/util/jsonpath"
)
const (
columnwidth = 10
tabwidth = 4
padding = 3
padding_character = ' '
flags = 0
)
var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$")
// 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 jsonpath expression:
// {.metadata.name}
func RelaxedJSONPathExpression(pathExpression string) (string, error) {
if len(pathExpression) == 0 {
return pathExpression, nil
}
submatches := jsonRegexp.FindStringSubmatch(pathExpression)
if submatches == nil {
return "", fmt.Errorf("unexpected path string, expected a 'name1.name2' or '.name1.name2' or '{name1.name2}' or '{.name1.name2}'")
}
if len(submatches) != 3 {
return "", fmt.Errorf("unexpected submatch list: %v", submatches)
}
var fieldSpec string
if len(submatches[1]) != 0 {
fieldSpec = submatches[1]
} else {
fieldSpec = submatches[2]
}
return fmt.Sprintf("{.%s}", fieldSpec), nil
}
// NewCustomColumnsPrinterFromSpec creates a custom columns printer from a comma separated list of <header>:<jsonpath-field-spec> pairs.
// e.g. NAME:metadata.name,API_VERSION:apiVersion creates a printer that prints:
//
// NAME API_VERSION
// foo bar
func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder, noHeaders bool) (*CustomColumnsPrinter, error) {
if len(spec) == 0 {
return nil, fmt.Errorf("custom-columns format specified but no custom columns given")
}
parts := strings.Split(spec, ",")
columns := make([]Column, len(parts))
for ix := range parts {
colSpec := strings.Split(parts[ix], ":")
if len(colSpec) != 2 {
return nil, fmt.Errorf("unexpected custom-columns spec: %s, expected <header>:<json-path-expr>", parts[ix])
}
spec, err := RelaxedJSONPathExpression(colSpec[1])
if err != nil {
return nil, err
}
columns[ix] = Column{Header: colSpec[0], FieldSpec: spec}
}
return &CustomColumnsPrinter{Columns: columns, Decoder: decoder, NoHeaders: noHeaders}, nil
}
func splitOnWhitespace(line string) []string {
lineScanner := bufio.NewScanner(bytes.NewBufferString(line))
lineScanner.Split(bufio.ScanWords)
result := []string{}
for lineScanner.Scan() {
result = append(result, lineScanner.Text())
}
return result
}
// NewCustomColumnsPrinterFromTemplate creates a custom columns printer from a template stream. The template is expected
// to consist of two lines, whitespace separated. The first line is the header line, the second line is the jsonpath field spec
// For example, the template below:
// NAME API_VERSION
// {metadata.name} {apiVersion}
func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runtime.Decoder) (*CustomColumnsPrinter, error) {
scanner := bufio.NewScanner(templateReader)
if !scanner.Scan() {
return nil, fmt.Errorf("invalid template, missing header line. Expected format is one line of space separated headers, one line of space separated column specs.")
}
headers := splitOnWhitespace(scanner.Text())
if !scanner.Scan() {
return nil, fmt.Errorf("invalid template, missing spec line. Expected format is one line of space separated headers, one line of space separated column specs.")
}
specs := splitOnWhitespace(scanner.Text())
if len(headers) != len(specs) {
return nil, fmt.Errorf("number of headers (%d) and field specifications (%d) don't match", len(headers), len(specs))
}
columns := make([]Column, len(headers))
for ix := range headers {
spec, err := RelaxedJSONPathExpression(specs[ix])
if err != nil {
return nil, err
}
columns[ix] = Column{
Header: headers[ix],
FieldSpec: spec,
}
}
return &CustomColumnsPrinter{Columns: columns, Decoder: decoder, NoHeaders: false}, nil
}
// Column represents a user specified column
type Column struct {
// The header to print above the column, general style is ALL_CAPS
Header string
// The pointer to the field in the object to print in JSONPath form
// e.g. {.ObjectMeta.Name}, see pkg/util/jsonpath for more details.
FieldSpec string
}
// CustomColumnPrinter is a printer that knows how to print arbitrary columns
// of data from templates specified in the `Columns` array
type CustomColumnsPrinter struct {
Columns []Column
Decoder runtime.Decoder
NoHeaders bool
// lastType records type of resource printed last so that we don't repeat
// header while printing same type of resources.
lastType reflect.Type
}
func (s *CustomColumnsPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
t := reflect.TypeOf(obj)
if !s.NoHeaders && t != s.lastType {
headers := make([]string, len(s.Columns))
for ix := range s.Columns {
headers[ix] = s.Columns[ix].Header
}
fmt.Fprintln(w, strings.Join(headers, "\t"))
s.lastType = t
}
parsers := make([]*jsonpath.JSONPath, len(s.Columns))
for ix := range s.Columns {
parsers[ix] = jsonpath.New(fmt.Sprintf("column%d", ix)).AllowMissingKeys(true)
if err := parsers[ix].Parse(s.Columns[ix].FieldSpec); err != nil {
return err
}
}
if meta.IsListType(obj) {
objs, err := meta.ExtractList(obj)
if err != nil {
return err
}
for ix := range objs {
if err := s.printOneObject(objs[ix], parsers, w); err != nil {
return err
}
}
} else {
if err := s.printOneObject(obj, parsers, w); err != nil {
return err
}
}
return w.Flush()
}
func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jsonpath.JSONPath, out io.Writer) error {
columns := make([]string, len(parsers))
switch u := obj.(type) {
case *runtime.Unknown:
if len(u.Raw) > 0 {
var err error
if obj, err = runtime.Decode(s.Decoder, u.Raw); err != nil {
return fmt.Errorf("can't decode object for printing: %v (%s)", err, u.Raw)
}
}
}
for ix := range parsers {
parser := parsers[ix]
var values [][]reflect.Value
var err error
if unstructured, ok := obj.(runtime.Unstructured); ok {
values, err = parser.FindResults(unstructured.UnstructuredContent())
} else {
values, err = parser.FindResults(reflect.ValueOf(obj).Elem().Interface())
}
if err != nil {
return err
}
valueStrings := []string{}
if len(values) == 0 || len(values[0]) == 0 {
valueStrings = append(valueStrings, "<none>")
}
for arrIx := range values {
for valIx := range values[arrIx] {
valueStrings = append(valueStrings, fmt.Sprintf("%v", values[arrIx][valIx].Interface()))
}
}
columns[ix] = strings.Join(valueStrings, ",")
}
fmt.Fprintln(out, strings.Join(columns, "\t"))
return nil
}
func (s *CustomColumnsPrinter) HandledResources() []string {
return []string{}
}
func (s *CustomColumnsPrinter) IsGeneric() bool {
return true
}

View File

@ -0,0 +1,325 @@
/*
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_test
import (
"bytes"
"reflect"
"strings"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/printers"
)
func TestMassageJSONPath(t *testing.T) {
tests := []struct {
input string
expectedOutput string
expectErr bool
}{
{input: "foo.bar", expectedOutput: "{.foo.bar}"},
{input: "{foo.bar}", expectedOutput: "{.foo.bar}"},
{input: ".foo.bar", expectedOutput: "{.foo.bar}"},
{input: "{.foo.bar}", expectedOutput: "{.foo.bar}"},
{input: "", expectedOutput: ""},
{input: "{foo.bar", expectErr: true},
{input: "foo.bar}", expectErr: true},
{input: "{foo.bar}}", expectErr: true},
{input: "{{foo.bar}", expectErr: true},
}
for _, test := range tests {
output, err := printers.RelaxedJSONPathExpression(test.input)
if err != nil && !test.expectErr {
t.Errorf("unexpected error: %v", err)
continue
}
if test.expectErr {
if err == nil {
t.Error("unexpected non-error")
}
continue
}
if output != test.expectedOutput {
t.Errorf("input: %s, expected: %s, saw: %s", test.input, test.expectedOutput, output)
}
}
}
func TestNewColumnPrinterFromSpec(t *testing.T) {
tests := []struct {
spec string
expectedColumns []printers.Column
expectErr bool
name string
noHeaders bool
}{
{
spec: "",
expectErr: true,
name: "empty",
},
{
spec: "invalid",
expectErr: true,
name: "invalid1",
},
{
spec: "invalid=foobar",
expectErr: true,
name: "invalid2",
},
{
spec: "invalid,foobar:blah",
expectErr: true,
name: "invalid3",
},
{
spec: "NAME:metadata.name,API_VERSION:apiVersion",
name: "ok",
expectedColumns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
},
},
{
spec: "API_VERSION:apiVersion",
name: "no-headers",
noHeaders: true,
},
}
for _, test := range tests {
printer, err := printers.NewCustomColumnsPrinterFromSpec(test.spec, legacyscheme.Codecs.UniversalDecoder(), test.noHeaders)
if test.expectErr {
if err == nil {
t.Errorf("[%s] unexpected non-error", test.name)
}
continue
}
if !test.expectErr && err != nil {
t.Errorf("[%s] unexpected error: %v", test.name, err)
continue
}
if test.noHeaders {
buffer := &bytes.Buffer{}
printer.PrintObj(&api.Pod{}, buffer)
if err != nil {
t.Fatalf("An error occurred printing Pod: %#v", err)
}
if contains(strings.Fields(buffer.String()), "API_VERSION") {
t.Errorf("unexpected header API_VERSION")
}
} else if !reflect.DeepEqual(test.expectedColumns, printer.Columns) {
t.Errorf("[%s]\nexpected:\n%v\nsaw:\n%v\n", test.name, test.expectedColumns, printer.Columns)
}
}
}
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}`
const exampleTemplateTwo = `NAME API_VERSION
{metadata.name} {apiVersion}`
func TestNewColumnPrinterFromTemplate(t *testing.T) {
tests := []struct {
spec string
expectedColumns []printers.Column
expectErr bool
name string
}{
{
spec: "",
expectErr: true,
name: "empty",
},
{
spec: "invalid",
expectErr: true,
name: "invalid1",
},
{
spec: "invalid=foobar",
expectErr: true,
name: "invalid2",
},
{
spec: "invalid,foobar:blah",
expectErr: true,
name: "invalid3",
},
{
spec: exampleTemplateOne,
name: "ok",
expectedColumns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
},
},
{
spec: exampleTemplateTwo,
name: "ok-2",
expectedColumns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
},
},
}
for _, test := range tests {
reader := bytes.NewBufferString(test.spec)
printer, err := printers.NewCustomColumnsPrinterFromTemplate(reader, legacyscheme.Codecs.UniversalDecoder())
if test.expectErr {
if err == nil {
t.Errorf("[%s] unexpected non-error", test.name)
}
continue
}
if !test.expectErr && err != nil {
t.Errorf("[%s] unexpected error: %v", test.name, err)
continue
}
if !reflect.DeepEqual(test.expectedColumns, printer.Columns) {
t.Errorf("[%s]\nexpected:\n%v\nsaw:\n%v\n", test.name, test.expectedColumns, printer.Columns)
}
}
}
func TestColumnPrint(t *testing.T) {
tests := []struct {
columns []printers.Column
obj runtime.Object
expectedOutput string
}{
{
columns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
},
obj: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
expectedOutput: `NAME
foo
`,
},
{
columns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
},
obj: &v1.PodList{
Items: []v1.Pod{
{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
{ObjectMeta: metav1.ObjectMeta{Name: "bar"}},
},
},
expectedOutput: `NAME
foo
bar
`,
},
{
columns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
},
obj: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, TypeMeta: metav1.TypeMeta{APIVersion: "baz"}},
expectedOutput: `NAME API_VERSION
foo baz
`,
},
{
columns: []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "API_VERSION",
FieldSpec: "{.apiVersion}",
},
{
Header: "NOT_FOUND",
FieldSpec: "{.notFound}",
},
},
obj: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, TypeMeta: metav1.TypeMeta{APIVersion: "baz"}},
expectedOutput: `NAME API_VERSION NOT_FOUND
foo baz <none>
`,
},
}
for _, test := range tests {
printer := &printers.CustomColumnsPrinter{
Columns: test.columns,
Decoder: legacyscheme.Codecs.UniversalDecoder(),
}
buffer := &bytes.Buffer{}
if err := printer.PrintObj(test.obj, buffer); err != nil {
t.Errorf("unexpected error: %v", err)
}
if buffer.String() != test.expectedOutput {
t.Errorf("\nexpected:\n'%s'\nsaw\n'%s'\n", test.expectedOutput, buffer.String())
}
}
}

861
vendor/k8s.io/kubernetes/pkg/printers/humanreadable.go generated vendored Normal file
View File

@ -0,0 +1,861 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"bytes"
"fmt"
"io"
"reflect"
"strings"
"text/tabwriter"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
type TablePrinter interface {
PrintTable(obj runtime.Object, options PrintOptions) (*metav1alpha1.Table, error)
}
type PrintHandler interface {
Handler(columns, columnsWithWide []string, printFunc interface{}) error
TableHandler(columns []metav1alpha1.TableColumnDefinition, printFunc interface{}) error
DefaultTableHandler(columns []metav1alpha1.TableColumnDefinition, printFunc interface{}) error
}
var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
type handlerEntry struct {
columnDefinitions []metav1alpha1.TableColumnDefinition
printRows bool
printFunc reflect.Value
args []reflect.Value
}
// HumanReadablePrinter is an implementation of ResourcePrinter which attempts to provide
// more elegant output. It is not threadsafe, but you may call PrintObj repeatedly; headers
// will only be printed if the object type changes. This makes it useful for printing items
// received from watches.
type HumanReadablePrinter struct {
handlerMap map[reflect.Type]*handlerEntry
defaultHandler *handlerEntry
options PrintOptions
lastType interface{}
skipTabWriter bool
encoder runtime.Encoder
decoder runtime.Decoder
}
var _ PrintHandler = &HumanReadablePrinter{}
// NewHumanReadablePrinter creates a HumanReadablePrinter.
// If encoder and decoder are provided, an attempt to convert unstructured types to internal types is made.
func NewHumanReadablePrinter(encoder runtime.Encoder, decoder runtime.Decoder, options PrintOptions) *HumanReadablePrinter {
printer := &HumanReadablePrinter{
handlerMap: make(map[reflect.Type]*handlerEntry),
options: options,
encoder: encoder,
decoder: decoder,
}
return printer
}
// NewTablePrinter creates a HumanReadablePrinter suitable for calling PrintTable().
func NewTablePrinter() *HumanReadablePrinter {
return &HumanReadablePrinter{
handlerMap: make(map[reflect.Type]*handlerEntry),
}
}
// AddTabWriter sets whether the PrintObj function will format with tabwriter (true
// by default).
func (a *HumanReadablePrinter) AddTabWriter(t bool) *HumanReadablePrinter {
a.skipTabWriter = !t
return a
}
func (a *HumanReadablePrinter) With(fns ...func(PrintHandler)) *HumanReadablePrinter {
for _, fn := range fns {
fn(a)
}
return a
}
// GetResourceKind returns the type currently set for a resource
func (h *HumanReadablePrinter) GetResourceKind() string {
return h.options.Kind
}
// EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true
// and "Kind" to the string arg it receives, pre-pending this string
// to the "NAME" column in an output of resources.
func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) {
h.options.WithKind = true
h.options.Kind = kind
}
// EnsurePrintHeaders sets the HumanReadablePrinter option "NoHeaders" to false
// and removes the .lastType that was printed, which forces headers to be
// printed in cases where multiple lists of the same resource are printed
// consecutively, but are separated by non-printer related information.
func (h *HumanReadablePrinter) EnsurePrintHeaders() {
h.options.NoHeaders = false
h.lastType = nil
}
// Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
// See ValidatePrintHandlerFunc for required method signature.
func (h *HumanReadablePrinter) Handler(columns, columnsWithWide []string, printFunc interface{}) error {
var columnDefinitions []metav1alpha1.TableColumnDefinition
for _, column := range columns {
columnDefinitions = append(columnDefinitions, metav1alpha1.TableColumnDefinition{
Name: column,
Type: "string",
})
}
for _, column := range columnsWithWide {
columnDefinitions = append(columnDefinitions, metav1alpha1.TableColumnDefinition{
Name: column,
Type: "string",
Priority: 1,
})
}
printFuncValue := reflect.ValueOf(printFunc)
if err := ValidatePrintHandlerFunc(printFuncValue); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err))
return err
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printFunc: printFuncValue,
}
objType := printFuncValue.Type().In(0)
if _, ok := h.handlerMap[objType]; ok {
err := fmt.Errorf("registered duplicate printer for %v", objType)
utilruntime.HandleError(err)
return err
}
h.handlerMap[objType] = entry
return nil
}
// TableHandler adds a print handler with a given set of columns to HumanReadablePrinter instance.
// See ValidateRowPrintHandlerFunc for required method signature.
func (h *HumanReadablePrinter) TableHandler(columnDefinitions []metav1alpha1.TableColumnDefinition, printFunc interface{}) error {
printFuncValue := reflect.ValueOf(printFunc)
if err := ValidateRowPrintHandlerFunc(printFuncValue); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err))
return err
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printRows: true,
printFunc: printFuncValue,
}
objType := printFuncValue.Type().In(0)
if _, ok := h.handlerMap[objType]; ok {
err := fmt.Errorf("registered duplicate printer for %v", objType)
utilruntime.HandleError(err)
return err
}
h.handlerMap[objType] = entry
return nil
}
// DefaultTableHandler registers a set of columns and a print func that is given a chance to process
// any object without an explicit handler. Only the most recently set print handler is used.
// See ValidateRowPrintHandlerFunc for required method signature.
func (h *HumanReadablePrinter) DefaultTableHandler(columnDefinitions []metav1alpha1.TableColumnDefinition, printFunc interface{}) error {
printFuncValue := reflect.ValueOf(printFunc)
if err := ValidateRowPrintHandlerFunc(printFuncValue); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err))
return err
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printRows: true,
printFunc: printFuncValue,
}
h.defaultHandler = entry
return nil
}
// ValidateRowPrintHandlerFunc validates print handler signature.
// printFunc is the function that will be called to print an object.
// It must be of the following type:
// func printFunc(object ObjectType, options PrintOptions) ([]metav1alpha1.TableRow, error)
// where ObjectType is the type of the object that will be printed, and the first
// return value is an array of rows, with each row containing a number of cells that
// match the number of columns defined for that printer function.
func ValidateRowPrintHandlerFunc(printFunc reflect.Value) error {
if printFunc.Kind() != reflect.Func {
return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
}
funcType := printFunc.Type()
if funcType.NumIn() != 2 || funcType.NumOut() != 2 {
return fmt.Errorf("invalid print handler." +
"Must accept 2 parameters and return 2 value.")
}
if funcType.In(1) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
funcType.Out(0) != reflect.TypeOf((*[]metav1alpha1.TableRow)(nil)).Elem() ||
funcType.Out(1) != reflect.TypeOf((*error)(nil)).Elem() {
return fmt.Errorf("invalid print handler. The expected signature is: "+
"func handler(obj %v, options PrintOptions) ([]metav1alpha1.TableRow, error)", funcType.In(0))
}
return nil
}
// ValidatePrintHandlerFunc validates print handler signature.
// printFunc is the function that will be called to print an object.
// It must be of the following type:
// func printFunc(object ObjectType, w io.Writer, options PrintOptions) error
// where ObjectType is the type of the object that will be printed.
// DEPRECATED: will be replaced with ValidateRowPrintHandlerFunc
func ValidatePrintHandlerFunc(printFunc reflect.Value) error {
if printFunc.Kind() != reflect.Func {
return fmt.Errorf("invalid print handler. %#v is not a function", printFunc)
}
funcType := printFunc.Type()
if funcType.NumIn() != 3 || funcType.NumOut() != 1 {
return fmt.Errorf("invalid print handler." +
"Must accept 3 parameters and return 1 value.")
}
if funcType.In(1) != reflect.TypeOf((*io.Writer)(nil)).Elem() ||
funcType.In(2) != reflect.TypeOf((*PrintOptions)(nil)).Elem() ||
funcType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
return fmt.Errorf("invalid print handler. The expected signature is: "+
"func handler(obj %v, w io.Writer, options PrintOptions) error", funcType.In(0))
}
return nil
}
func (h *HumanReadablePrinter) HandledResources() []string {
keys := make([]string, 0)
for k := range h.handlerMap {
// k.String looks like "*api.PodList" and we want just "pod"
api := strings.Split(k.String(), ".")
resource := api[len(api)-1]
if strings.HasSuffix(resource, "List") {
continue
}
resource = strings.ToLower(resource)
keys = append(keys, resource)
}
return keys
}
func (h *HumanReadablePrinter) AfterPrint(output io.Writer, res string) error {
return nil
}
func (h *HumanReadablePrinter) IsGeneric() bool {
return false
}
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
_, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
return err
}
func printHeader(columnNames []string, w io.Writer) error {
if _, err := fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t")); err != nil {
return err
}
return nil
}
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
// TODO: unify the behavior of PrintObj, which often expects single items and tracks
// headers and filtering, with other printers, that expect list objects. The tracking
// behavior should probably be a higher level wrapper (MultiObjectTablePrinter) that
// calls into the PrintTable method and then displays consistent output.
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
if w, found := output.(*tabwriter.Writer); !found && !h.skipTabWriter {
w = GetNewTabWriter(output)
output = w
defer w.Flush()
}
// display tables following the rules of options
if table, ok := obj.(*metav1alpha1.Table); ok {
if err := DecorateTable(table, h.options); err != nil {
return err
}
return PrintTable(table, output, h.options)
}
// 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.
if h.encoder != nil && h.decoder != nil {
obj, _ = decodeUnknownObject(obj, h.encoder, h.decoder)
}
// print with a registered handler
t := reflect.TypeOf(obj)
if handler := h.handlerMap[t]; handler != nil {
includeHeaders := h.lastType != t && !h.options.NoHeaders
if err := printRowsForHandlerEntry(output, handler, obj, h.options, includeHeaders); err != nil {
return err
}
h.lastType = t
return nil
}
// print with the default handler if set, and use the columns from the last time
if h.defaultHandler != nil {
includeHeaders := h.lastType != h.defaultHandler && !h.options.NoHeaders
if err := printRowsForHandlerEntry(output, h.defaultHandler, obj, h.options, includeHeaders); err != nil {
return err
}
h.lastType = h.defaultHandler
return nil
}
// we failed all reasonable printing efforts, report failure
return fmt.Errorf("error: unknown type %#v", obj)
}
func hasCondition(conditions []metav1alpha1.TableRowCondition, t metav1alpha1.RowConditionType) bool {
for _, condition := range conditions {
if condition.Type == t {
return condition.Status == metav1alpha1.ConditionTrue
}
}
return false
}
// PrintTable prints a table to the provided output respecting the filtering rules for options
// for wide columns and filetred rows. It filters out rows that are Completed. You should call
// DecorateTable if you receive a table from a remote server before calling PrintTable.
func PrintTable(table *metav1alpha1.Table, output io.Writer, options PrintOptions) error {
if !options.NoHeaders {
first := true
for _, column := range table.ColumnDefinitions {
if !options.Wide && column.Priority != 0 {
continue
}
if first {
first = false
} else {
fmt.Fprint(output, "\t")
}
fmt.Fprint(output, strings.ToUpper(column.Name))
}
fmt.Fprintln(output)
}
for _, row := range table.Rows {
if !options.ShowAll && hasCondition(row.Conditions, metav1alpha1.RowCompleted) {
continue
}
first := true
for i, cell := range row.Cells {
column := table.ColumnDefinitions[i]
if !options.Wide && column.Priority != 0 {
continue
}
if first {
first = false
} else {
fmt.Fprint(output, "\t")
}
if cell != nil {
fmt.Fprint(output, cell)
}
}
fmt.Fprintln(output)
}
return nil
}
// DecorateTable takes a table and attempts to add label columns and the
// namespace column. It will fill empty columns with nil (if the object
// does not expose metadata). It returns an error if the table cannot
// be decorated.
func DecorateTable(table *metav1alpha1.Table, options PrintOptions) error {
width := len(table.ColumnDefinitions) + len(options.ColumnLabels)
if options.WithNamespace {
width++
}
if options.ShowLabels {
width++
}
columns := table.ColumnDefinitions
nameColumn := -1
if options.WithKind && len(options.Kind) > 0 {
for i := range columns {
if columns[i].Format == "name" && columns[i].Type == "string" {
nameColumn = i
fmt.Printf("found name column: %d\n", i)
break
}
}
}
if width != len(table.ColumnDefinitions) {
columns = make([]metav1alpha1.TableColumnDefinition, 0, width)
if options.WithNamespace {
columns = append(columns, metav1alpha1.TableColumnDefinition{
Name: "Namespace",
Type: "string",
})
}
columns = append(columns, table.ColumnDefinitions...)
for _, label := range formatLabelHeaders(options.ColumnLabels) {
columns = append(columns, metav1alpha1.TableColumnDefinition{
Name: label,
Type: "string",
})
}
if options.ShowLabels {
columns = append(columns, metav1alpha1.TableColumnDefinition{
Name: "Labels",
Type: "string",
})
}
}
rows := table.Rows
includeLabels := len(options.ColumnLabels) > 0 || options.ShowLabels
if includeLabels || options.WithNamespace || nameColumn != -1 {
for i := range rows {
row := rows[i]
if nameColumn != -1 {
row.Cells[nameColumn] = fmt.Sprintf("%s/%s", options.Kind, row.Cells[nameColumn])
}
var m metav1.Object
if obj := row.Object.Object; obj != nil {
if acc, err := meta.Accessor(obj); err == nil {
m = acc
}
}
// if we can't get an accessor, fill out the appropriate columns with empty spaces
if m == nil {
if options.WithNamespace {
r := make([]interface{}, 1, width)
row.Cells = append(r, row.Cells...)
}
for j := 0; j < width-len(row.Cells); j++ {
row.Cells = append(row.Cells, nil)
}
rows[i] = row
continue
}
if options.WithNamespace {
r := make([]interface{}, 1, width)
r[0] = m.GetNamespace()
row.Cells = append(r, row.Cells...)
}
if includeLabels {
row.Cells = appendLabelCells(row.Cells, m.GetLabels(), options)
}
rows[i] = row
}
}
table.ColumnDefinitions = columns
table.Rows = rows
return nil
}
// PrintTable returns a table for the provided object, using the printer registered for that type. It returns
// a table that includes all of the information requested by options, but will not remove rows or columns. The
// caller is responsible for applying rules related to filtering rows or columns.
func (h *HumanReadablePrinter) PrintTable(obj runtime.Object, options PrintOptions) (*metav1alpha1.Table, error) {
t := reflect.TypeOf(obj)
handler, ok := h.handlerMap[t]
if !ok {
return nil, fmt.Errorf("no table handler registered for this type %v", t)
}
if !handler.printRows {
return h.legacyPrinterToTable(obj, handler)
}
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
results := handler.printFunc.Call(args)
if !results[1].IsNil() {
return nil, results[1].Interface().(error)
}
columns := handler.columnDefinitions
if !options.Wide {
columns = make([]metav1alpha1.TableColumnDefinition, 0, len(handler.columnDefinitions))
for i := range handler.columnDefinitions {
if handler.columnDefinitions[i].Priority != 0 {
continue
}
columns = append(columns, handler.columnDefinitions[i])
}
}
table := &metav1alpha1.Table{
ListMeta: metav1.ListMeta{
ResourceVersion: "",
},
ColumnDefinitions: columns,
Rows: results[0].Interface().([]metav1alpha1.TableRow),
}
if m, err := meta.ListAccessor(obj); err == nil {
table.ResourceVersion = m.GetResourceVersion()
table.SelfLink = m.GetSelfLink()
table.Continue = m.GetContinue()
} else {
if m, err := meta.CommonAccessor(obj); err == nil {
table.ResourceVersion = m.GetResourceVersion()
table.SelfLink = m.GetSelfLink()
}
}
if err := DecorateTable(table, options); err != nil {
return nil, err
}
return table, nil
}
// printRowsForHandlerEntry prints the incremental table output (headers if the current type is
// different from lastType) including all the rows in the object. It returns the current type
// or an error, if any.
func printRowsForHandlerEntry(output io.Writer, handler *handlerEntry, obj runtime.Object, options PrintOptions, includeHeaders bool) error {
var results []reflect.Value
if handler.printRows {
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
results = handler.printFunc.Call(args)
if !results[1].IsNil() {
return results[1].Interface().(error)
}
}
if includeHeaders {
var headers []string
for _, column := range handler.columnDefinitions {
if column.Priority != 0 && !options.Wide {
continue
}
headers = append(headers, strings.ToUpper(column.Name))
}
headers = append(headers, formatLabelHeaders(options.ColumnLabels)...)
// LABELS is always the last column.
headers = append(headers, formatShowLabelsHeader(options.ShowLabels)...)
if options.WithNamespace {
headers = append(withNamespacePrefixColumns, headers...)
}
printHeader(headers, output)
}
if !handler.printRows {
// TODO: this code path is deprecated and will be removed when all handlers are row printers
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(output), reflect.ValueOf(options)}
resultValue := handler.printFunc.Call(args)[0]
if resultValue.IsNil() {
return nil
}
return resultValue.Interface().(error)
}
if results[1].IsNil() {
rows := results[0].Interface().([]metav1alpha1.TableRow)
printRows(output, rows, options)
return nil
}
return results[1].Interface().(error)
}
// printRows writes the provided rows to output.
func printRows(output io.Writer, rows []metav1alpha1.TableRow, options PrintOptions) {
for _, row := range rows {
if options.WithNamespace {
if obj := row.Object.Object; obj != nil {
if m, err := meta.Accessor(obj); err == nil {
fmt.Fprint(output, m.GetNamespace())
}
}
fmt.Fprint(output, "\t")
}
for i, cell := range row.Cells {
if i != 0 {
fmt.Fprint(output, "\t")
} else {
// TODO: remove this once we drop the legacy printers
if options.WithKind && len(options.Kind) > 0 {
fmt.Fprintf(output, "%s/%s", options.Kind, cell)
continue
}
}
fmt.Fprint(output, cell)
}
hasLabels := len(options.ColumnLabels) > 0
if obj := row.Object.Object; obj != nil && (hasLabels || options.ShowLabels) {
if m, err := meta.Accessor(obj); err == nil {
for _, value := range labelValues(m.GetLabels(), options) {
output.Write([]byte("\t"))
output.Write([]byte(value))
}
}
}
output.Write([]byte("\n"))
}
}
// legacyPrinterToTable uses the old printFunc with tabbed writer to generate a table.
// TODO: remove when all legacy printers are removed.
func (h *HumanReadablePrinter) legacyPrinterToTable(obj runtime.Object, handler *handlerEntry) (*metav1alpha1.Table, error) {
printFunc := handler.printFunc
table := &metav1alpha1.Table{
ColumnDefinitions: handler.columnDefinitions,
}
options := PrintOptions{
NoHeaders: true,
Wide: true,
}
buf := &bytes.Buffer{}
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(buf), reflect.ValueOf(options)}
if meta.IsListType(obj) {
// TODO: this uses more memory than it has to, as we refactor printers we should remove the need
// for this.
args[0] = reflect.ValueOf(obj)
resultValue := printFunc.Call(args)[0]
if !resultValue.IsNil() {
return nil, resultValue.Interface().(error)
}
data := buf.Bytes()
i := 0
items, err := meta.ExtractList(obj)
if err != nil {
return nil, err
}
for len(data) > 0 {
cells, remainder := tabbedLineToCells(data, len(table.ColumnDefinitions))
table.Rows = append(table.Rows, metav1alpha1.TableRow{
Cells: cells,
Object: runtime.RawExtension{Object: items[i]},
})
data = remainder
i++
}
} else {
args[0] = reflect.ValueOf(obj)
resultValue := printFunc.Call(args)[0]
if !resultValue.IsNil() {
return nil, resultValue.Interface().(error)
}
data := buf.Bytes()
cells, _ := tabbedLineToCells(data, len(table.ColumnDefinitions))
table.Rows = append(table.Rows, metav1alpha1.TableRow{
Cells: cells,
Object: runtime.RawExtension{Object: obj},
})
}
return table, nil
}
// 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, additionalFields []string, 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
}
for _, field := range additionalFields {
if value, ok := content[field]; ok {
var formattedValue string
switch typedValue := value.(type) {
case []interface{}:
formattedValue = fmt.Sprintf("%d item(s)", len(typedValue))
default:
formattedValue = fmt.Sprintf("%v", value)
}
if _, err := fmt.Fprintf(w, "\t%s", formattedValue); 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) []string {
if showLabels {
return []string{"LABELS"}
}
return nil
}
// labelValues returns a slice of value columns matching the requested print options.
func labelValues(itemLabels map[string]string, opts PrintOptions) []string {
var values []string
for _, key := range opts.ColumnLabels {
values = append(values, itemLabels[key])
}
if opts.ShowLabels {
values = append(values, labels.FormatLabels(itemLabels))
}
return values
}
// appendLabelCells returns a slice of value columns matching the requested print options.
// Intended for use with tables.
func appendLabelCells(values []interface{}, itemLabels map[string]string, opts PrintOptions) []interface{} {
for _, key := range opts.ColumnLabels {
values = append(values, itemLabels[key])
}
if opts.ShowLabels {
values = append(values, labels.FormatLabels(itemLabels))
}
return values
}
// 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
}
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.
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()
}
// check if the object is unstructured. If so, attempt to convert it to a type we can understand.
func decodeUnknownObject(obj runtime.Object, encoder runtime.Encoder, decoder runtime.Decoder) (runtime.Object, error) {
var err error
switch obj.(type) {
case runtime.Unstructured, *runtime.Unknown:
if objBytes, err := runtime.Encode(encoder, obj); err == nil {
if decodedObj, err := runtime.Decode(decoder, objBytes); err == nil {
obj = decodedObj
}
}
}
return obj, err
}
func tabbedLineToCells(data []byte, expected int) ([]interface{}, []byte) {
var remainder []byte
max := bytes.Index(data, []byte("\n"))
if max != -1 {
remainder = data[max+1:]
data = data[:max]
}
cells := make([]interface{}, expected)
for i := 0; i < expected; i++ {
next := bytes.Index(data, []byte("\t"))
if next == -1 {
cells[i] = string(data)
// fill the remainder with empty strings, this indicates a printer bug
for j := i + 1; j < expected; j++ {
cells[j] = ""
}
break
}
cells[i] = string(data[:next])
data = data[next+1:]
}
return cells, remainder
}

View File

@ -0,0 +1,138 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"bytes"
"fmt"
"reflect"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
api "k8s.io/kubernetes/pkg/apis/core"
)
var testNamespaceColumnDefinitions = []metav1alpha1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Status", Type: "string", Description: "The status of the namespace"},
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
}
func testPrintNamespace(obj *api.Namespace, options PrintOptions) ([]metav1alpha1.TableRow, error) {
if options.WithNamespace {
return nil, fmt.Errorf("namespace is not namespaced")
}
row := metav1alpha1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
row.Cells = append(row.Cells, obj.Name, obj.Status.Phase, "<unknow>")
return []metav1alpha1.TableRow{row}, nil
}
func testPrintNamespaceList(list *api.NamespaceList, options PrintOptions) ([]metav1alpha1.TableRow, error) {
rows := make([]metav1alpha1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := testPrintNamespace(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return rows, nil
}
func TestPrintRowsForHandlerEntry(t *testing.T) {
printFunc := reflect.ValueOf(testPrintNamespace)
testCase := map[string]struct {
h *handlerEntry
opt PrintOptions
obj runtime.Object
includeHeader bool
expectOut string
expectErr string
}{
"no tablecolumndefinition and includeheader flase": {
h: &handlerEntry{
columnDefinitions: []metav1alpha1.TableColumnDefinition{},
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
obj: &api.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
},
includeHeader: false,
expectOut: "test\t\t<unknow>\n",
},
"no tablecolumndefinition and includeheader true": {
h: &handlerEntry{
columnDefinitions: []metav1alpha1.TableColumnDefinition{},
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
obj: &api.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
},
includeHeader: true,
expectOut: "\ntest\t\t<unknow>\n",
},
"have tablecolumndefinition and includeheader true": {
h: &handlerEntry{
columnDefinitions: testNamespaceColumnDefinitions,
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
obj: &api.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
},
includeHeader: true,
expectOut: "NAME\tSTATUS\tAGE\ntest\t\t<unknow>\n",
},
"print namespace and withnamespace true, should not print header": {
h: &handlerEntry{
columnDefinitions: testNamespaceColumnDefinitions,
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{
WithNamespace: true,
},
obj: &api.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
},
includeHeader: true,
expectOut: "",
expectErr: "namespace is not namespaced",
},
}
for name, test := range testCase {
buffer := &bytes.Buffer{}
err := printRowsForHandlerEntry(buffer, test.h, test.obj, test.opt, test.includeHeader)
if err != nil {
if err.Error() != test.expectErr {
t.Errorf("[%s]expect:\n %v\n but got:\n %v\n", name, test.expectErr, err)
}
}
if test.expectOut != buffer.String() {
t.Errorf("[%s]expect:\n %v\n but got:\n %v\n", name, test.expectOut, buffer.String())
}
}
}

111
vendor/k8s.io/kubernetes/pkg/printers/interface.go generated vendored Normal file
View File

@ -0,0 +1,111 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
)
// ResourcePrinter is an interface that knows how to print runtime objects.
type ResourcePrinter interface {
// Print receives a runtime object, formats it and prints it to a writer.
PrintObj(runtime.Object, io.Writer) error
HandledResources() []string
//Can be used to print out warning/clarifications if needed
//after all objects were printed
AfterPrint(io.Writer, string) error
// Identify if it is a generic printer
IsGeneric() bool
}
// ResourcePrinterFunc is a function that can print objects
type ResourcePrinterFunc func(runtime.Object, io.Writer) error
// PrintObj implements ResourcePrinter
func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
return fn(obj, w)
}
// TODO: implement HandledResources()
func (fn ResourcePrinterFunc) HandledResources() []string {
return []string{}
}
func (fn ResourcePrinterFunc) AfterPrint(io.Writer, string) error {
return nil
}
func (fn ResourcePrinterFunc) IsGeneric() bool {
return true
}
type PrintOptions struct {
// supported Format types can be found in pkg/printers/printers.go
OutputFormatType string
OutputFormatArgument string
NoHeaders bool
WithNamespace bool
WithKind bool
Wide bool
ShowAll bool
ShowLabels bool
AbsoluteTimestamps bool
Kind string
ColumnLabels []string
SortBy string
// indicates if it is OK to ignore missing keys for rendering an output template.
AllowMissingKeys bool
}
// 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,4 @@
{
"Rules": [
]
}

View File

@ -0,0 +1,125 @@
package(default_visibility = ["//visibility:public"])
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",
],
importpath = "k8s.io/kubernetes/pkg/printers/internalversion",
library = ":go_default_library",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/networking:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/storage: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/pointer:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/yaml:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"describe.go",
"printers.go",
],
importpath = "k8s.io/kubernetes/pkg/printers/internalversion",
deps = [
"//pkg/api/events:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/ref:go_default_library",
"//pkg/api/resource: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/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/helper/qos:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/networking:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/apis/scheduling:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/util:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/fieldpath:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//pkg/util/node:go_default_library",
"//pkg/util/slice:go_default_library",
"//vendor/github.com/fatih/camelcase:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/batch/v1:go_default_library",
"//vendor/k8s.io/api/batch/v1beta1:go_default_library",
"//vendor/k8s.io/api/certificates/v1beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/api/storage/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*
Copyright 2016 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 internalversion
import (
api "k8s.io/kubernetes/pkg/apis/core"
"reflect"
"sort"
"testing"
)
func TestSortableResourceNamesSorting(t *testing.T) {
want := SortableResourceNames{
api.ResourceName(""),
api.ResourceName("42"),
api.ResourceName("bar"),
api.ResourceName("foo"),
api.ResourceName("foo"),
api.ResourceName("foobar"),
}
in := SortableResourceNames{
api.ResourceName("foo"),
api.ResourceName("42"),
api.ResourceName("foobar"),
api.ResourceName("foo"),
api.ResourceName("bar"),
api.ResourceName(""),
}
sort.Sort(in)
if !reflect.DeepEqual(in, want) {
t.Errorf("got %v, want %v", in, want)
}
}

109
vendor/k8s.io/kubernetes/pkg/printers/json.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"bytes"
"encoding/json"
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"github.com/ghodss/yaml"
)
// JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
type JSONPrinter struct {
}
func (p *JSONPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) {
case *runtime.Unknown:
var buf bytes.Buffer
err := json.Indent(&buf, obj.Raw, "", " ")
if err != nil {
return err
}
buf.WriteRune('\n')
_, err = buf.WriteTo(w)
return err
}
data, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
data = append(data, '\n')
_, err = w.Write(data)
return err
}
// TODO: implement HandledResources()
func (p *JSONPrinter) HandledResources() []string {
return []string{}
}
func (p *JSONPrinter) IsGeneric() bool {
return true
}
// YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
// The input object is assumed to be in the internal version of an API and is converted
// to the given version first.
type YAMLPrinter struct {
version string
converter runtime.ObjectConvertor
}
func (p *YAMLPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj prints the data as YAML.
func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) {
case *runtime.Unknown:
data, err := yaml.JSONToYAML(obj.Raw)
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
output, err := yaml.Marshal(obj)
if err != nil {
return err
}
_, err = fmt.Fprint(w, string(output))
return err
}
// TODO: implement HandledResources()
func (p *YAMLPrinter) HandledResources() []string {
return []string{}
}
func (p *YAMLPrinter) IsGeneric() bool {
return true
}

161
vendor/k8s.io/kubernetes/pkg/printers/jsonpath.go generated vendored Normal file
View File

@ -0,0 +1,161 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"encoding/json"
"fmt"
"io"
"reflect"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/util/jsonpath"
)
// exists returns true if it would be possible to call the index function
// with these arguments.
//
// TODO: how to document this for users?
//
// index returns the result of indexing its first argument by the following
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
func exists(item interface{}, indices ...interface{}) bool {
v := reflect.ValueOf(item)
for _, i := range indices {
index := reflect.ValueOf(i)
var isNil bool
if v, isNil = indirect(v); isNil {
return false
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
var x int64
switch index.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x = index.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
default:
return false
}
if x < 0 || x >= int64(v.Len()) {
return false
}
v = v.Index(int(x))
case reflect.Map:
if !index.IsValid() {
index = reflect.Zero(v.Type().Key())
}
if !index.Type().AssignableTo(v.Type().Key()) {
return false
}
if x := v.MapIndex(index); x.IsValid() {
v = x
} else {
v = reflect.Zero(v.Type().Elem())
}
default:
return false
}
}
if _, isNil := indirect(v); isNil {
return false
}
return true
}
// stolen from text/template
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
// We indirect through pointers and empty interfaces (only) because
// non-empty interfaces have methods we might need.
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
break
}
}
return v, false
}
// JSONPathPrinter is an implementation of ResourcePrinter which formats data with jsonpath expression.
type JSONPathPrinter struct {
rawTemplate string
*jsonpath.JSONPath
}
func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
j := jsonpath.New("out")
if err := j.Parse(tmpl); err != nil {
return nil, err
}
return &JSONPathPrinter{tmpl, j}, nil
}
func (j *JSONPathPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the JSONPath Template.
func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
var queryObj interface{} = obj
if meta.IsListType(obj) {
data, err := json.Marshal(obj)
if err != nil {
return err
}
queryObj = map[string]interface{}{}
if err := json.Unmarshal(data, &queryObj); err != nil {
return err
}
}
if unknown, ok := obj.(*runtime.Unknown); ok {
data, err := json.Marshal(unknown)
if err != nil {
return err
}
queryObj = map[string]interface{}{}
if err := json.Unmarshal(data, &queryObj); err != nil {
return err
}
}
if unstructured, ok := obj.(runtime.Unstructured); ok {
queryObj = unstructured.UnstructuredContent()
}
if err := j.JSONPath.Execute(w, queryObj); err != nil {
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
fmt.Fprintf(w, "\tobject given to jsonpath engine was:\n\t\t%#v\n\n", queryObj)
return fmt.Errorf("error executing jsonpath %q: %v\n", j.rawTemplate, err)
}
return nil
}
// TODO: implement HandledResources()
func (p *JSONPathPrinter) HandledResources() []string {
return []string{}
}
func (p *JSONPathPrinter) IsGeneric() bool {
return true
}

93
vendor/k8s.io/kubernetes/pkg/printers/name.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
)
// NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
type NamePrinter struct {
Decoders []runtime.Decoder
Typer runtime.ObjectTyper
Mapper meta.RESTMapper
}
func (p *NamePrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
// and print "resource/name" pair. If the object is a List, print all items in it.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if meta.IsListType(obj) {
items, err := meta.ExtractList(obj)
if err != nil {
return err
}
if errs := runtime.DecodeList(items, p.Decoders...); len(errs) > 0 {
return utilerrors.NewAggregate(errs)
}
for _, obj := range items {
if err := p.PrintObj(obj, w); err != nil {
return err
}
}
return nil
}
name := "<unknown>"
if acc, err := meta.Accessor(obj); err == nil {
if n := acc.GetName(); len(n) > 0 {
name = n
}
}
groupVersionKind := obj.GetObjectKind().GroupVersionKind()
if len(groupVersionKind.Kind) > 0 {
if mappings, err := p.Mapper.RESTMappings(groupVersionKind.GroupKind(), groupVersionKind.Version); err == nil && len(mappings) > 0 {
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
return nil
}
}
if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
for _, gvk := range gvks {
if mappings, err := p.Mapper.RESTMappings(gvk.GroupKind(), gvk.Version); err == nil && len(mappings) > 0 {
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
return nil
}
}
}
fmt.Fprintf(w, "<unknown>/%s\n", name)
return nil
}
// TODO: implement HandledResources()
func (p *NamePrinter) HandledResources() []string {
return []string{}
}
func (p *NamePrinter) IsGeneric() bool {
return true
}

128
vendor/k8s.io/kubernetes/pkg/printers/printers.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"fmt"
"io/ioutil"
"os"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
)
// GetStandardPrinter takes a format type, an optional format argument. It will return
// a printer or an error. The printer is agnostic to schema versions, so you must
// send arguments to PrintObj in the version you wish them to be shown using a
// VersionedPrinter (typically when generic is true).
func GetStandardPrinter(mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options PrintOptions) (ResourcePrinter, error) {
format, formatArgument, allowMissingTemplateKeys := options.OutputFormatType, options.OutputFormatArgument, options.AllowMissingKeys
var printer ResourcePrinter
switch format {
case "json":
printer = &JSONPrinter{}
case "yaml":
printer = &YAMLPrinter{}
case "name":
printer = &NamePrinter{
Typer: typer,
Decoders: decoders,
Mapper: mapper,
}
case "template", "go-template":
if len(formatArgument) == 0 {
return nil, fmt.Errorf("template format specified but no template given")
}
templatePrinter, err := NewTemplatePrinter([]byte(formatArgument))
if err != nil {
return nil, 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, fmt.Errorf("templatefile format specified but no template file given")
}
data, err := ioutil.ReadFile(formatArgument)
if err != nil {
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
templatePrinter, err := NewTemplatePrinter(data)
if err != nil {
return nil, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
}
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = templatePrinter
case "jsonpath":
if len(formatArgument) == 0 {
return nil, fmt.Errorf("jsonpath template format specified but no template given")
}
jsonpathPrinter, err := NewJSONPathPrinter(formatArgument)
if err != nil {
return nil, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
}
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = jsonpathPrinter
case "jsonpath-file":
if len(formatArgument) == 0 {
return nil, fmt.Errorf("jsonpath file format specified but no template file given")
}
data, err := ioutil.ReadFile(formatArgument)
if err != nil {
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
jsonpathPrinter, err := NewJSONPathPrinter(string(data))
if err != nil {
return nil, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
}
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = jsonpathPrinter
case "custom-columns":
var err error
if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, decoders[0], options.NoHeaders); err != nil {
return nil, err
}
case "custom-columns-file":
file, err := os.Open(formatArgument)
if err != nil {
return nil, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
defer file.Close()
if printer, err = NewCustomColumnsPrinterFromTemplate(file, decoders[0]); err != nil {
return nil, err
}
case "wide":
fallthrough
case "":
printer = NewHumanReadablePrinter(encoder, decoders[0], options)
default:
return nil, fmt.Errorf("output format %q not recognized", format)
}
return printer, nil
}

31
vendor/k8s.io/kubernetes/pkg/printers/storage/BUILD generated vendored Normal file
View File

@ -0,0 +1,31 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["storage.go"],
importpath = "k8s.io/kubernetes/pkg/printers/storage",
deps = [
"//pkg/printers:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,32 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package storage
import (
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/kubernetes/pkg/printers"
)
type TableConvertor struct {
printers.TablePrinter
}
func (c TableConvertor) ConvertToTable(ctx genericapirequest.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1alpha1.Table, error) {
return c.TablePrinter.PrintTable(obj, printers.PrintOptions{Wide: true})
}

35
vendor/k8s.io/kubernetes/pkg/printers/tabwriter.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"io"
"text/tabwriter"
)
const (
tabwriterMinWidth = 10
tabwriterWidth = 4
tabwriterPadding = 3
tabwriterPadChar = ' '
tabwriterFlags = 0
)
// GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
}

114
vendor/k8s.io/kubernetes/pkg/printers/template.go generated vendored Normal file
View File

@ -0,0 +1,114 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"encoding/json"
"fmt"
"io"
"text/template"
"k8s.io/apimachinery/pkg/runtime"
)
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
type TemplatePrinter struct {
rawTemplate string
template *template.Template
}
func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
t, err := template.New("output").
Funcs(template.FuncMap{"exists": exists}).
Parse(string(tmpl))
if err != nil {
return nil, err
}
return &TemplatePrinter{
rawTemplate: string(tmpl),
template: t,
}, nil
}
// AllowMissingKeys tells the template engine if missing keys are allowed.
func (p *TemplatePrinter) AllowMissingKeys(allow bool) {
if allow {
p.template.Option("missingkey=default")
} else {
p.template.Option("missingkey=error")
}
}
func (p *TemplatePrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the Go Template.
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
var data []byte
var err error
data, err = json.Marshal(obj)
if err != nil {
return err
}
out := map[string]interface{}{}
if err := json.Unmarshal(data, &out); err != nil {
return err
}
if err = p.safeExecute(w, out); err != nil {
// It is way easier to debug this stuff when it shows up in
// stdout instead of just stdin. So in addition to returning
// a nice error, also print useful stuff with the writer.
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", p.rawTemplate)
fmt.Fprintf(w, "\traw data was:\n\t\t%v\n", string(data))
fmt.Fprintf(w, "\tobject given to template engine was:\n\t\t%+v\n\n", out)
return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
}
return nil
}
// TODO: implement HandledResources()
func (p *TemplatePrinter) HandledResources() []string {
return []string{}
}
func (p *TemplatePrinter) IsGeneric() bool {
return true
}
// safeExecute tries to execute the template, but catches panics and returns an error
// should the template engine panic.
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
var panicErr error
// Sorry for the double anonymous function. There's probably a clever way
// to do this that has the defer'd func setting the value to be returned, but
// that would be even less obvious.
retErr := func() error {
defer func() {
if x := recover(); x != nil {
panicErr = fmt.Errorf("caught panic: %+v", x)
}
}()
return p.template.Execute(w, obj)
}()
if panicErr != nil {
return panicErr
}
return retErr
}

67
vendor/k8s.io/kubernetes/pkg/printers/versioned.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// VersionedPrinter takes runtime objects and ensures they are converted to a given API version
// prior to being passed to a nested printer.
type VersionedPrinter struct {
printer ResourcePrinter
converter runtime.ObjectConvertor
versions []schema.GroupVersion
}
// NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...schema.GroupVersion) ResourcePrinter {
return &VersionedPrinter{
printer: printer,
converter: converter,
versions: versions,
}
}
func (p *VersionedPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj implements ResourcePrinter
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if len(p.versions) == 0 {
return fmt.Errorf("no version specified, object cannot be converted")
}
converted, err := p.converter.ConvertToVersion(obj, schema.GroupVersions(p.versions))
if err != nil {
return err
}
return p.printer.PrintObj(converted, w)
}
// TODO: implement HandledResources()
func (p *VersionedPrinter) HandledResources() []string {
return []string{}
}
func (p *VersionedPrinter) IsGeneric() bool {
return p.printer.IsGeneric()
}