Skip to content

Commit

Permalink
Adds kn route list command (#202)
Browse files Browse the repository at this point in the history
- Accepts an argument name for listing particular route
- Enables the machine readable output flags
- Updates docs for kn route command group
- Adds unit tests for route command group and route list
- Adds integration tests for route list in basic workflow test
- Updates tests and getting namespace
- Adds more unit tests for code in pkg/kn/commands/route/list_flags.go
- Adds route list command in smoke tests
- Updates vendor/modules.txt
- Clean up imports
- Addresses review comments
 - replaces knative to Knative
 - uses reflect.DeepEqual for slice comparison
 - removes few code comments
 - removes irrelevant tests modifications from the PR
  • Loading branch information
navidshaikh authored and knative-prow-robot committed Jul 2, 2019
1 parent e431ba2 commit aac0ec2
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/cmd/kn.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Eventing: Manage event subscriptions and channels. Connect up event sources.

* [kn completion](kn_completion.md) - Output shell completion code (default Bash)
* [kn revision](kn_revision.md) - Revision command group
* [kn route](kn_route.md) - Route command group
* [kn service](kn_service.md) - Service command group
* [kn version](kn_version.md) - Prints the client version

26 changes: 26 additions & 0 deletions docs/cmd/kn_route.md
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.

48 changes: 48 additions & 0 deletions docs/cmd/kn_route_list.md
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

82 changes: 82 additions & 0 deletions pkg/kn/commands/route/human_readable_flags.go
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
}
87 changes: 87 additions & 0 deletions pkg/kn/commands/route/list.go
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
}
71 changes: 71 additions & 0 deletions pkg/kn/commands/route/list_flags.go
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(),
}
}
47 changes: 47 additions & 0 deletions pkg/kn/commands/route/list_flags_test.go
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) {
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)
}
}
Loading

0 comments on commit aac0ec2

Please sign in to comment.