-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add kn route list command #202
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
## kn route | ||
|
||
Route command group | ||
|
||
### Synopsis | ||
|
||
Route command group | ||
|
||
### Options | ||
|
||
``` | ||
-h, --help help for route | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--config string config file (default is $HOME/.kn/config.yaml) | ||
--kubeconfig string kubectl config file (default is $HOME/.kube/config) | ||
``` | ||
|
||
### SEE ALSO | ||
|
||
* [kn](kn.md) - Knative client | ||
* [kn route list](kn_route_list.md) - List available routes. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
## kn route list | ||
|
||
List available routes. | ||
|
||
### Synopsis | ||
|
||
List available routes. | ||
|
||
``` | ||
kn route list NAME [flags] | ||
``` | ||
|
||
### Examples | ||
|
||
``` | ||
|
||
# List all routes | ||
kn route list | ||
|
||
# List route 'web' in namespace 'dev' | ||
kn route list web -n dev | ||
|
||
# List all routes in yaml format | ||
kn route list -o yaml | ||
``` | ||
|
||
### Options | ||
|
||
``` | ||
--all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace. | ||
--allow-missing-template-keys If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true) | ||
-h, --help help for list | ||
-n, --namespace string List the requested object(s) in given namespace. | ||
-o, --output string Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file. | ||
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--config string config file (default is $HOME/.kn/config.yaml) | ||
--kubeconfig string kubectl config file (default is $HOME/.kube/config) | ||
``` | ||
|
||
### SEE ALSO | ||
|
||
* [kn route](kn_route.md) - Route command group | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// 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 route | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/knative/client/pkg/kn/commands" | ||
hprinters "github.com/knative/client/pkg/printers" | ||
servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1" | ||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
// RouteListHandlers adds print handlers for route list command | ||
func RouteListHandlers(h hprinters.PrintHandler) { | ||
kRouteColumnDefinitions := []metav1beta1.TableColumnDefinition{ | ||
{Name: "Name", Type: "string", Description: "Name of the Knative route."}, | ||
{Name: "URL", Type: "string", Description: "URL of the Knative route."}, | ||
{Name: "Age", Type: "string", Description: "Age of the Knative route."}, | ||
{Name: "Conditions", Type: "string", Description: "Conditions describing statuses of route components."}, | ||
{Name: "Traffic", Type: "integer", Description: "Traffic configured for route."}, | ||
} | ||
h.TableHandler(kRouteColumnDefinitions, printRoute) | ||
h.TableHandler(kRouteColumnDefinitions, printKRouteList) | ||
} | ||
|
||
// printKRouteList populates the Knative route list table rows | ||
func printKRouteList(kRouteList *servingv1alpha1.RouteList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { | ||
rows := make([]metav1beta1.TableRow, 0, len(kRouteList.Items)) | ||
for _, ksvc := range kRouteList.Items { | ||
r, err := printRoute(&ksvc, options) | ||
if err != nil { | ||
return nil, err | ||
} | ||
rows = append(rows, r...) | ||
} | ||
return rows, nil | ||
} | ||
|
||
// printRoute populates the Knative route table rows | ||
func printRoute(route *servingv1alpha1.Route, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { | ||
name := route.Name | ||
url := route.Status.URL | ||
age := commands.TranslateTimestampSince(route.CreationTimestamp) | ||
conditions := commands.ConditionsValue(route.Status.Conditions) | ||
traffic := calculateTraffic(route.Status.Traffic) | ||
row := metav1beta1.TableRow{ | ||
Object: runtime.RawExtension{Object: route}, | ||
} | ||
row.Cells = append(row.Cells, | ||
name, | ||
url, | ||
age, | ||
conditions, | ||
traffic) | ||
return []metav1beta1.TableRow{row}, nil | ||
} | ||
|
||
func calculateTraffic(targets []servingv1alpha1.TrafficTarget) string { | ||
var traffic string | ||
for _, target := range targets { | ||
if len(traffic) > 0 { | ||
traffic = fmt.Sprintf("%s, %d%% -> %s", traffic, target.Percent, target.RevisionName) | ||
} else { | ||
traffic = fmt.Sprintf("%d%% -> %s", target.Percent, target.RevisionName) | ||
} | ||
} | ||
return traffic | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// 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 route | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/knative/client/pkg/kn/commands" | ||
"github.com/spf13/cobra" | ||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/fields" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
) | ||
|
||
// NewrouteListCommand represents 'kn route list' command | ||
func NewRouteListCommand(p *commands.KnParams) *cobra.Command { | ||
routeListFlags := NewRouteListFlags() | ||
routeListCommand := &cobra.Command{ | ||
Use: "list NAME", | ||
Short: "List available routes.", | ||
Example: ` | ||
# List all routes | ||
kn route list | ||
|
||
# List route 'web' in namespace 'dev' | ||
kn route list web -n dev | ||
|
||
# List all routes in yaml format | ||
kn route list -o yaml`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
client, err := p.ServingFactory() | ||
if err != nil { | ||
return err | ||
} | ||
namespace, err := p.GetNamespace(cmd) | ||
if err != nil { | ||
return err | ||
} | ||
var listOptions v1.ListOptions | ||
switch len(args) { | ||
case 0: | ||
listOptions = v1.ListOptions{} | ||
case 1: | ||
listOptions.FieldSelector = fields.Set(map[string]string{"metadata.name": args[0]}).String() | ||
default: | ||
return fmt.Errorf("'kn route list' accepts maximum 1 argument.") | ||
} | ||
route, err := client.Routes(namespace).List(listOptions) | ||
if err != nil { | ||
return err | ||
} | ||
if len(route.Items) == 0 { | ||
fmt.Fprintf(cmd.OutOrStdout(), "No resources found.\n") | ||
return nil | ||
} | ||
route.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{ | ||
Group: "knative.dev", | ||
Version: "v1alpha1", | ||
Kind: "route", | ||
}) | ||
printer, err := routeListFlags.ToPrinter() | ||
if err != nil { | ||
return err | ||
} | ||
err = printer.PrintObj(route, cmd.OutOrStdout()) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
}, | ||
} | ||
commands.AddNamespaceFlags(routeListCommand.Flags(), true) | ||
routeListFlags.AddFlags(routeListCommand) | ||
return routeListCommand | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// 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 route | ||
|
||
import ( | ||
"github.com/knative/client/pkg/kn/commands" | ||
hprinters "github.com/knative/client/pkg/printers" | ||
"github.com/spf13/cobra" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
) | ||
|
||
// RouteListFlags composes common printer flag structs | ||
// used in the 'kn route list' command. | ||
type RouteListFlags struct { | ||
GenericPrintFlags *genericclioptions.PrintFlags | ||
HumanReadableFlags *commands.HumanPrintFlags | ||
} | ||
|
||
// AllowedFormats is the list of formats in which data can be displayed | ||
func (f *RouteListFlags) AllowedFormats() []string { | ||
formats := f.GenericPrintFlags.AllowedFormats() | ||
formats = append(formats, f.HumanReadableFlags.AllowedFormats()...) | ||
return formats | ||
} | ||
|
||
// ToPrinter attempts to find a composed set of RouteListFlags suitable for | ||
// returning a printer based on current flag values. | ||
func (f *RouteListFlags) 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(RouteListHandlers) | ||
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 *RouteListFlags) AddFlags(cmd *cobra.Command) { | ||
f.GenericPrintFlags.AddFlags(cmd) | ||
f.HumanReadableFlags.AddFlags(cmd) | ||
} | ||
|
||
// NewRouteListFlags returns flags associated with humanreadable, | ||
// template, and "name" printing, with default values set. | ||
func NewRouteListFlags() *RouteListFlags { | ||
return &RouteListFlags{ | ||
GenericPrintFlags: genericclioptions.NewPrintFlags(""), | ||
HumanReadableFlags: commands.NewHumanPrintFlags(), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// 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 route | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/knative/client/pkg/kn/commands" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
) | ||
|
||
func TestRoutListFlags(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i dont think we need this test. it's too close to implementation so it doesnt add confidence that this object is correct. additionally route list flags object is used in the command test, so it gets tested there indirectly in a more resilient manner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added this file's test, as without tests should I be testing this in some other way? |
||
testObject := createMockRouteMeta("foo") | ||
knParams := &commands.KnParams{} | ||
cmd, _, buf := commands.CreateTestKnCommand(NewRouteCommand(knParams), knParams) | ||
routeListFlags := NewRouteListFlags() | ||
routeListFlags.AddFlags(cmd) | ||
printer, err := routeListFlags.ToPrinter() | ||
if genericclioptions.IsNoCompatiblePrinterError(err) { | ||
t.Fatalf("Expected to match human readable printer.") | ||
} | ||
if err != nil { | ||
t.Fatalf("Failed to find a proper printer.") | ||
} | ||
err = printer.PrintObj(testObject, buf) | ||
if err != nil { | ||
t.Fatalf("Failed to print the object.") | ||
} | ||
actualFormats := routeListFlags.AllowedFormats() | ||
expectedFormats := []string{"json", "yaml", "name", "go-template", "go-template-file", "template", "templatefile", "jsonpath", "jsonpath-file"} | ||
if reflect.DeepEqual(actualFormats, expectedFormats) { | ||
t.Fatalf("Expecting allowed formats:\n%s\nFound:\n%s\n", expectedFormats, actualFormats) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems that we keep on overriding traffic string in a loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cppforlife: yup but with an update only if there is traffic split available
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
im still confused, should it be
traffic += ...
instead since there could be multiple targets?