mirror of https://github.com/knative/client.git
Adds service get command (#90)
* Adds service get command replaces service list command * Updates go.mod and vendors/* * Adds message if no services found in requested namespace * Adds tests for service get
This commit is contained in:
parent
6582e8239a
commit
bd7d57fa09
2
go.mod
2
go.mod
|
|
@ -16,7 +16,7 @@ require (
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.6 // indirect
|
github.com/json-iterator/go v1.1.6 // indirect
|
||||||
github.com/knative/build v0.5.0 // indirect
|
github.com/knative/build v0.5.0 // indirect
|
||||||
github.com/knative/pkg v0.0.0-20190329155329-916205998db9 // indirect
|
github.com/knative/pkg v0.0.0-20190329155329-916205998db9
|
||||||
github.com/knative/serving v0.5.2
|
github.com/knative/serving v0.5.2
|
||||||
github.com/knative/test-infra v0.0.0-20190509163238-a721698dbe49
|
github.com/knative/test-infra v0.0.0-20190509163238-a721698dbe49
|
||||||
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect
|
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright © 2019 The Knative 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 commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
hprinters "github.com/knative/client/pkg/printers"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HumanPrintFlags provides default flags necessary for printing.
|
||||||
|
// Given the following flag values, a printer can be requested that knows
|
||||||
|
// how to handle printing based on these values.
|
||||||
|
type HumanPrintFlags struct {
|
||||||
|
//TODO: Add more flags as required
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowedFormats returns more customized formating options
|
||||||
|
func (f *HumanPrintFlags) AllowedFormats() []string {
|
||||||
|
// TODO: Add more formats eg: wide
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPrinter receives returns a printer capable of
|
||||||
|
// handling human-readable output.
|
||||||
|
func (f *HumanPrintFlags) ToPrinter() (hprinters.ResourcePrinter, error) {
|
||||||
|
p := hprinters.NewTablePrinter(hprinters.PrintOptions{})
|
||||||
|
// Add the column definitions and respective functions
|
||||||
|
ServiceGetHandlers(p)
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFlags receives a *cobra.Command reference and binds
|
||||||
|
// flags related to human-readable printing to it
|
||||||
|
func (f *HumanPrintFlags) AddFlags(c *cobra.Command) {
|
||||||
|
//TODO: Add more flags as required
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHumanPrintFlags returns flags associated with
|
||||||
|
// human-readable printing, with default values set.
|
||||||
|
func NewHumanPrintFlags() *HumanPrintFlags {
|
||||||
|
return &HumanPrintFlags{}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ func NewServiceCommand(p *KnParams) *cobra.Command {
|
||||||
Use: "service",
|
Use: "service",
|
||||||
Short: "Service command group",
|
Short: "Service command group",
|
||||||
}
|
}
|
||||||
serviceCmd.AddCommand(NewServiceListCommand(p))
|
serviceCmd.AddCommand(NewServiceGetCommand(p))
|
||||||
serviceCmd.AddCommand(NewServiceDescribeCommand(p))
|
serviceCmd.AddCommand(NewServiceDescribeCommand(p))
|
||||||
serviceCmd.AddCommand(NewServiceCreateCommand(p))
|
serviceCmd.AddCommand(NewServiceCreateCommand(p))
|
||||||
serviceCmd.AddCommand(NewServiceDeleteCommand(p))
|
serviceCmd.AddCommand(NewServiceDeleteCommand(p))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright © 2018 The Knative Authors
|
// Copyright © 2019 The Knative Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
@ -15,21 +15,20 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var serviceListPrintFlags *genericclioptions.PrintFlags
|
// NewServiceGetCommand represents 'kn service get' command
|
||||||
|
func NewServiceGetCommand(p *KnParams) *cobra.Command {
|
||||||
|
serviceGetFlags := NewServiceGetFlags()
|
||||||
|
|
||||||
// listCmd represents the list command
|
serviceGetCommand := &cobra.Command{
|
||||||
func NewServiceListCommand(p *KnParams) *cobra.Command {
|
Use: "get",
|
||||||
serviceListPrintFlags := genericclioptions.NewPrintFlags("").WithDefaultOutput(
|
Short: "Get available services.",
|
||||||
"jsonpath={range .items[*]}{.metadata.name}{\"\\n\"}{end}")
|
|
||||||
serviceListCommand := &cobra.Command{
|
|
||||||
Use: "list",
|
|
||||||
Short: "List available services.",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
client, err := p.ServingFactory()
|
client, err := p.ServingFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -43,15 +42,20 @@ func NewServiceListCommand(p *KnParams) *cobra.Command {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if len(service.Items) == 0 {
|
||||||
printer, err := serviceListPrintFlags.ToPrinter()
|
fmt.Fprintf(cmd.OutOrStdout(), "No resources found.\n")
|
||||||
if err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
service.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
|
service.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
|
||||||
Group: "knative.dev",
|
Group: "knative.dev",
|
||||||
Version: "v1alpha1",
|
Version: "v1alpha1",
|
||||||
Kind: "Service"})
|
Kind: "Service"})
|
||||||
|
|
||||||
|
printer, err := serviceGetFlags.ToPrinter()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = printer.PrintObj(service, cmd.OutOrStdout())
|
err = printer.PrintObj(service, cmd.OutOrStdout())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -59,7 +63,7 @@ func NewServiceListCommand(p *KnParams) *cobra.Command {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
AddNamespaceFlags(serviceListCommand.Flags(), true)
|
AddNamespaceFlags(serviceGetCommand.Flags(), true)
|
||||||
serviceListPrintFlags.AddFlags(serviceListCommand)
|
serviceGetFlags.AddFlags(serviceGetCommand)
|
||||||
return serviceListCommand
|
return serviceGetCommand
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Copyright © 2019 The Knative 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 im
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
hprinters "github.com/knative/client/pkg/printers"
|
||||||
|
duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1"
|
||||||
|
servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/duration"
|
||||||
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceGetFlags composes common printer flag structs
|
||||||
|
// used in the Get command.
|
||||||
|
type ServiceGetFlags struct {
|
||||||
|
GenericPrintFlags *genericclioptions.PrintFlags
|
||||||
|
HumanReadableFlags *HumanPrintFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowedFormats is the list of formats in which data can be displayed
|
||||||
|
func (f *ServiceGetFlags) AllowedFormats() []string {
|
||||||
|
formats := f.GenericPrintFlags.AllowedFormats()
|
||||||
|
formats = append(formats, f.HumanReadableFlags.AllowedFormats()...)
|
||||||
|
return formats
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPrinter attempts to find a composed set of ServiceGetFlags suitable for
|
||||||
|
// returning a printer based on current flag values.
|
||||||
|
func (f *ServiceGetFlags) ToPrinter() (hprinters.ResourcePrinter, error) {
|
||||||
|
// if there are flags specified for generic printing
|
||||||
|
if f.GenericPrintFlags.OutputFlagSpecified() {
|
||||||
|
p, err := f.GenericPrintFlags.ToPrinter()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
// if no flags specified, use the table printing
|
||||||
|
p, err := f.HumanReadableFlags.ToPrinter()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFlags receives a *cobra.Command reference and binds
|
||||||
|
// flags related to humanreadable and template printing.
|
||||||
|
func (f *ServiceGetFlags) AddFlags(cmd *cobra.Command) {
|
||||||
|
f.GenericPrintFlags.AddFlags(cmd)
|
||||||
|
f.HumanReadableFlags.AddFlags(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetPrintFlags returns flags associated with humanreadable,
|
||||||
|
// template, and "name" printing, with default values set.
|
||||||
|
func NewServiceGetFlags() *ServiceGetFlags {
|
||||||
|
return &ServiceGetFlags{
|
||||||
|
GenericPrintFlags: genericclioptions.NewPrintFlags(""),
|
||||||
|
HumanReadableFlags: NewHumanPrintFlags(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceGetHandlers adds print handlers for service get command
|
||||||
|
func ServiceGetHandlers(h hprinters.PrintHandler) {
|
||||||
|
kServiceColumnDefinitions := []metav1beta1.TableColumnDefinition{
|
||||||
|
{Name: "Name", Type: "string", Description: "Name of the knative service."},
|
||||||
|
{Name: "Domain", Type: "string", Description: "Domain name of the knative service."},
|
||||||
|
//{Name: "LastCreatedRevision", Type: "string", Description: "Name of last revision created."},
|
||||||
|
//{Name: "LastReadyRevision", Type: "string", Description: "Name of last ready revision."},
|
||||||
|
{Name: "Generation", Type: "integer", Description: "Sequence number of 'Generation' of the service that was last processed by the controller."},
|
||||||
|
{Name: "Age", Type: "string", Description: "Age of the service."},
|
||||||
|
{Name: "Conditions", Type: "string", Description: "Conditions describing statuses of service components."},
|
||||||
|
{Name: "Ready", Type: "string", Description: "Ready condition status of the service."},
|
||||||
|
{Name: "Reason", Type: "string", Description: "Reason for non-ready condition of the service."},
|
||||||
|
}
|
||||||
|
h.TableHandler(kServiceColumnDefinitions, printKService)
|
||||||
|
h.TableHandler(kServiceColumnDefinitions, printKServiceList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// conditionsValue returns the True conditions count among total conditions
|
||||||
|
func conditionsValue(conditions duckv1alpha1.Conditions) string {
|
||||||
|
var ok int
|
||||||
|
for _, condition := range conditions {
|
||||||
|
if condition.Status == "True" {
|
||||||
|
ok++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d OK / %d", ok, len(conditions))
|
||||||
|
}
|
||||||
|
|
||||||
|
// readyCondition returns status of resource's Ready type condition
|
||||||
|
func readyCondition(conditions duckv1alpha1.Conditions) string {
|
||||||
|
for _, condition := range conditions {
|
||||||
|
if condition.Type == duckv1alpha1.ConditionReady {
|
||||||
|
return string(condition.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func nonReadyConditionReason(conditions duckv1alpha1.Conditions) string {
|
||||||
|
for _, condition := range conditions {
|
||||||
|
if condition.Type == duckv1alpha1.ConditionReady {
|
||||||
|
if string(condition.Status) == "True" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if condition.Message != "" {
|
||||||
|
return fmt.Sprintf("%s : %s", condition.Reason, condition.Message)
|
||||||
|
}
|
||||||
|
return string(condition.Reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// translateTimestampSince returns the elapsed time since timestamp in
|
||||||
|
// human-readable approximation.
|
||||||
|
func translateTimestampSince(timestamp metav1.Time) string {
|
||||||
|
if timestamp.IsZero() {
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
return duration.HumanDuration(time.Since(timestamp.Time))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printKServiceList populates the knative service list table rows
|
||||||
|
func printKServiceList(kServiceList *servingv1alpha1.ServiceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||||
|
rows := make([]metav1beta1.TableRow, 0, len(kServiceList.Items))
|
||||||
|
for _, ksvc := range kServiceList.Items {
|
||||||
|
r, err := printKService(&ksvc, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rows = append(rows, r...)
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// printKService populates the knative service table rows
|
||||||
|
func printKService(kService *servingv1alpha1.Service, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||||
|
name := kService.Name
|
||||||
|
domain := kService.Status.Domain
|
||||||
|
//lastCreatedRevision := kService.Status.LatestCreatedRevisionName
|
||||||
|
//lastReadyRevision := kService.Status.LatestReadyRevisionName
|
||||||
|
generation := kService.Status.ObservedGeneration
|
||||||
|
age := translateTimestampSince(kService.CreationTimestamp)
|
||||||
|
conditions := conditionsValue(kService.Status.Conditions)
|
||||||
|
ready := readyCondition(kService.Status.Conditions)
|
||||||
|
reason := nonReadyConditionReason(kService.Status.Conditions)
|
||||||
|
|
||||||
|
row := metav1beta1.TableRow{
|
||||||
|
Object: runtime.RawExtension{Object: kService},
|
||||||
|
}
|
||||||
|
row.Cells = append(row.Cells,
|
||||||
|
name,
|
||||||
|
domain,
|
||||||
|
//lastCreatedRevision,
|
||||||
|
//lastReadyRevision,
|
||||||
|
generation,
|
||||||
|
age,
|
||||||
|
conditions,
|
||||||
|
ready,
|
||||||
|
reason)
|
||||||
|
return []metav1beta1.TableRow{row}, nil
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
//servinglib "github.com/knative/client/pkg/serving"
|
||||||
|
duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1"
|
||||||
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
|
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
|
||||||
serving "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
|
serving "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
|
||||||
"github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake"
|
"github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake"
|
||||||
|
|
@ -27,7 +29,7 @@ import (
|
||||||
client_testing "k8s.io/client-go/testing"
|
client_testing "k8s.io/client-go/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fakeList(args []string, response *v1alpha1.ServiceList) (action client_testing.Action, output []string, err error) {
|
func fakeGet(args []string, response *v1alpha1.ServiceList) (action client_testing.Action, output []string, err error) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
fakeServing := &fake.FakeServingV1alpha1{&client_testing.Fake{}}
|
fakeServing := &fake.FakeServingV1alpha1{&client_testing.Fake{}}
|
||||||
cmd := NewKnCommand(KnParams{
|
cmd := NewKnCommand(KnParams{
|
||||||
|
|
@ -48,58 +50,67 @@ func fakeList(args []string, response *v1alpha1.ServiceList) (action client_test
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListEmpty(t *testing.T) {
|
func TestGetEmpty(t *testing.T) {
|
||||||
action, output, err := fakeList([]string{"service", "list"}, &v1alpha1.ServiceList{})
|
action, output, err := fakeGet([]string{"service", "get"}, &v1alpha1.ServiceList{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, s := range output {
|
|
||||||
if s != "" {
|
|
||||||
t.Errorf("Bad output line %v", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if action == nil {
|
if action == nil {
|
||||||
t.Errorf("No action")
|
t.Errorf("No action")
|
||||||
} else if !action.Matches("list", "services") {
|
} else if !action.Matches("list", "services") {
|
||||||
t.Errorf("Bad action %v", action)
|
t.Errorf("Bad action %v", action)
|
||||||
|
} else if output[0] != "No resources found." {
|
||||||
|
t.Errorf("Bad output %s", output[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var serviceType = metav1.TypeMeta{
|
|
||||||
Kind: "service",
|
|
||||||
APIVersion: "serving.knative.dev/v1alpha1",
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListDefaultOutput(t *testing.T) {
|
func TestListDefaultOutput(t *testing.T) {
|
||||||
action, output, err := fakeList([]string{"service", "list"}, &v1alpha1.ServiceList{
|
service1 := createMockServiceWithParams(t, "foo", "foo.default.example.com", 1)
|
||||||
Items: []v1alpha1.Service{
|
service2 := createMockServiceWithParams(t, "bar", "bar.default.example.com", 2)
|
||||||
v1alpha1.Service{
|
serviceList := &v1alpha1.ServiceList{Items: []v1alpha1.Service{*service1, *service2}}
|
||||||
TypeMeta: serviceType,
|
action, output, err := fakeGet([]string{"service", "get"}, serviceList)
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
v1alpha1.Service{
|
|
||||||
TypeMeta: serviceType,
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
expected := []string{"foo", "bar", ""}
|
|
||||||
for i, s := range output {
|
|
||||||
if s != expected[i] {
|
|
||||||
t.Errorf("Bad output line %v expected %v", s, expected[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if action == nil {
|
if action == nil {
|
||||||
t.Errorf("No action")
|
t.Errorf("No action")
|
||||||
} else if !action.Matches("list", "services") {
|
} else if !action.Matches("list", "services") {
|
||||||
t.Errorf("Bad action %v", action)
|
t.Errorf("Bad action %v", action)
|
||||||
}
|
}
|
||||||
|
testContains(t, output[0], []string{"NAME", "DOMAIN", "GENERATION", "AGE", "CONDITIONS", "READY", "REASON"}, "column header")
|
||||||
|
testContains(t, output[1], []string{"foo", "foo.default.example.com", "1"}, "value")
|
||||||
|
testContains(t, output[2], []string{"bar", "bar.default.example.com", "2"}, "value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testContains(t *testing.T, output string, sub []string, element string) {
|
||||||
|
for _, each := range sub {
|
||||||
|
if !strings.Contains(output, each) {
|
||||||
|
t.Errorf("Missing %s: %s", element, each)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMockServiceWithParams(t *testing.T, name, domain string, generation int64) *v1alpha1.Service {
|
||||||
|
service := &v1alpha1.Service{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "Service",
|
||||||
|
APIVersion: "knative.dev/v1alpha1",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: v1alpha1.ServiceSpec{
|
||||||
|
RunLatest: &v1alpha1.RunLatestType{},
|
||||||
|
},
|
||||||
|
Status: v1alpha1.ServiceStatus{
|
||||||
|
Status: duckv1alpha1.Status{
|
||||||
|
ObservedGeneration: generation},
|
||||||
|
RouteStatusFields: v1alpha1.RouteStatusFields{
|
||||||
|
Domain: domain,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return service
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 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 duration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShortHumanDuration returns a succint representation of the provided duration
|
||||||
|
// with limited precision for consumption by humans.
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HumanDuration returns a succint representation of the provided duration
|
||||||
|
// with limited precision for consumption by humans. It provides ~2-3 significant
|
||||||
|
// figures of duration.
|
||||||
|
func HumanDuration(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*2 {
|
||||||
|
return fmt.Sprintf("%ds", seconds)
|
||||||
|
}
|
||||||
|
minutes := int(d / time.Minute)
|
||||||
|
if minutes < 10 {
|
||||||
|
s := int(d/time.Second) % 60
|
||||||
|
if s == 0 {
|
||||||
|
return fmt.Sprintf("%dm", minutes)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dm%ds", minutes, s)
|
||||||
|
} else if minutes < 60*3 {
|
||||||
|
return fmt.Sprintf("%dm", minutes)
|
||||||
|
}
|
||||||
|
hours := int(d / time.Hour)
|
||||||
|
if hours < 8 {
|
||||||
|
m := int(d/time.Minute) % 60
|
||||||
|
if m == 0 {
|
||||||
|
return fmt.Sprintf("%dh", hours)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dh%dm", hours, m)
|
||||||
|
} else if hours < 48 {
|
||||||
|
return fmt.Sprintf("%dh", hours)
|
||||||
|
} else if hours < 24*8 {
|
||||||
|
h := hours % 24
|
||||||
|
if h == 0 {
|
||||||
|
return fmt.Sprintf("%dd", hours/24)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dd%dh", hours/24, h)
|
||||||
|
} else if hours < 24*365*2 {
|
||||||
|
return fmt.Sprintf("%dd", hours/24)
|
||||||
|
} else if hours < 24*365*8 {
|
||||||
|
return fmt.Sprintf("%dy%dd", hours/24/365, (hours/24)%365)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%dy", int(hours/24/365))
|
||||||
|
}
|
||||||
|
|
@ -63,11 +63,11 @@ github.com/json-iterator/go
|
||||||
github.com/knative/build/pkg/apis/build/v1alpha1
|
github.com/knative/build/pkg/apis/build/v1alpha1
|
||||||
github.com/knative/build/pkg/apis/build
|
github.com/knative/build/pkg/apis/build
|
||||||
# github.com/knative/pkg v0.0.0-20190329155329-916205998db9
|
# github.com/knative/pkg v0.0.0-20190329155329-916205998db9
|
||||||
github.com/knative/pkg/apis
|
|
||||||
github.com/knative/pkg/apis/duck/v1alpha1
|
github.com/knative/pkg/apis/duck/v1alpha1
|
||||||
|
github.com/knative/pkg/apis
|
||||||
|
github.com/knative/pkg/apis/duck
|
||||||
github.com/knative/pkg/kmeta
|
github.com/knative/pkg/kmeta
|
||||||
github.com/knative/pkg/kmp
|
github.com/knative/pkg/kmp
|
||||||
github.com/knative/pkg/apis/duck
|
|
||||||
github.com/knative/pkg/configmap
|
github.com/knative/pkg/configmap
|
||||||
# github.com/knative/serving v0.5.2
|
# github.com/knative/serving v0.5.2
|
||||||
github.com/knative/serving/pkg/apis/serving/v1alpha1
|
github.com/knative/serving/pkg/apis/serving/v1alpha1
|
||||||
|
|
@ -195,10 +195,11 @@ k8s.io/api/storage/v1beta1
|
||||||
# k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc
|
# k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc
|
||||||
k8s.io/apimachinery/pkg/api/resource
|
k8s.io/apimachinery/pkg/api/resource
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1
|
k8s.io/apimachinery/pkg/apis/meta/v1
|
||||||
k8s.io/apimachinery/pkg/runtime/schema
|
|
||||||
k8s.io/apimachinery/pkg/api/meta
|
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1beta1
|
k8s.io/apimachinery/pkg/apis/meta/v1beta1
|
||||||
k8s.io/apimachinery/pkg/runtime
|
k8s.io/apimachinery/pkg/runtime
|
||||||
|
k8s.io/apimachinery/pkg/runtime/schema
|
||||||
|
k8s.io/apimachinery/pkg/util/duration
|
||||||
|
k8s.io/apimachinery/pkg/api/meta
|
||||||
k8s.io/apimachinery/pkg/util/runtime
|
k8s.io/apimachinery/pkg/util/runtime
|
||||||
k8s.io/apimachinery/pkg/api/equality
|
k8s.io/apimachinery/pkg/api/equality
|
||||||
k8s.io/apimachinery/pkg/api/validation
|
k8s.io/apimachinery/pkg/api/validation
|
||||||
|
|
@ -213,12 +214,12 @@ k8s.io/apimachinery/pkg/conversion
|
||||||
k8s.io/apimachinery/pkg/fields
|
k8s.io/apimachinery/pkg/fields
|
||||||
k8s.io/apimachinery/pkg/labels
|
k8s.io/apimachinery/pkg/labels
|
||||||
k8s.io/apimachinery/pkg/selection
|
k8s.io/apimachinery/pkg/selection
|
||||||
|
k8s.io/apimachinery/pkg/conversion/queryparams
|
||||||
|
k8s.io/apimachinery/pkg/util/errors
|
||||||
k8s.io/apimachinery/pkg/util/json
|
k8s.io/apimachinery/pkg/util/json
|
||||||
|
k8s.io/apimachinery/pkg/util/naming
|
||||||
k8s.io/apimachinery/pkg/util/net
|
k8s.io/apimachinery/pkg/util/net
|
||||||
k8s.io/apimachinery/pkg/util/yaml
|
k8s.io/apimachinery/pkg/util/yaml
|
||||||
k8s.io/apimachinery/pkg/util/errors
|
|
||||||
k8s.io/apimachinery/pkg/conversion/queryparams
|
|
||||||
k8s.io/apimachinery/pkg/util/naming
|
|
||||||
k8s.io/apimachinery/pkg/apis/meta/v1/validation
|
k8s.io/apimachinery/pkg/apis/meta/v1/validation
|
||||||
k8s.io/apimachinery/pkg/util/validation/field
|
k8s.io/apimachinery/pkg/util/validation/field
|
||||||
k8s.io/apimachinery/pkg/runtime/serializer/json
|
k8s.io/apimachinery/pkg/runtime/serializer/json
|
||||||
|
|
@ -256,6 +257,7 @@ k8s.io/client-go/util/jsonpath
|
||||||
k8s.io/client-go/tools/auth
|
k8s.io/client-go/tools/auth
|
||||||
k8s.io/client-go/tools/clientcmd/api/latest
|
k8s.io/client-go/tools/clientcmd/api/latest
|
||||||
k8s.io/client-go/testing
|
k8s.io/client-go/testing
|
||||||
|
k8s.io/client-go/dynamic
|
||||||
k8s.io/client-go/tools/cache
|
k8s.io/client-go/tools/cache
|
||||||
k8s.io/client-go/pkg/version
|
k8s.io/client-go/pkg/version
|
||||||
k8s.io/client-go/plugin/pkg/client/auth/exec
|
k8s.io/client-go/plugin/pkg/client/auth/exec
|
||||||
|
|
@ -267,7 +269,6 @@ k8s.io/client-go/util/flowcontrol
|
||||||
k8s.io/client-go/kubernetes/scheme
|
k8s.io/client-go/kubernetes/scheme
|
||||||
k8s.io/client-go/third_party/forked/golang/template
|
k8s.io/client-go/third_party/forked/golang/template
|
||||||
k8s.io/client-go/tools/clientcmd/api/v1
|
k8s.io/client-go/tools/clientcmd/api/v1
|
||||||
k8s.io/client-go/dynamic
|
|
||||||
k8s.io/client-go/tools/pager
|
k8s.io/client-go/tools/pager
|
||||||
k8s.io/client-go/util/buffer
|
k8s.io/client-go/util/buffer
|
||||||
k8s.io/client-go/util/retry
|
k8s.io/client-go/util/retry
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue