Skip to content

Commit

Permalink
feat: kn source list-types (builtin types)
Browse files Browse the repository at this point in the history
 - Only lists the builtin source types
 - Uses client-go dynamic client for listing CRDs
 - Adds DyanmicClient interface to KnParams
 - Adds printing options
  • Loading branch information
navidshaikh committed Dec 6, 2019
1 parent 556f457 commit be1e0a8
Show file tree
Hide file tree
Showing 14 changed files with 480 additions and 61 deletions.
1 change: 1 addition & 0 deletions docs/cmd/kn.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ Manage your Knative building blocks:
* [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 source](kn_source.md) - Event Source command group
* [kn version](kn_version.md) - Prints the client version

31 changes: 31 additions & 0 deletions docs/cmd/kn_source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## kn source

Event Source command group

### Synopsis

Event Source command group

```
kn source [flags]
```

### Options

```
-h, --help help for source
```

### Options inherited from parent commands

```
--config string kn config file (default is $HOME/.kn/config.yaml)
--kubeconfig string kubectl config file (default is $HOME/.kube/config)
--log-http log http traffic
```

### SEE ALSO

* [kn](kn.md) - Knative client
* [kn source list-types](kn_source_list-types.md) - List available source types

35 changes: 35 additions & 0 deletions docs/cmd/kn_source_list-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## kn source list-types

List available source types

### Synopsis

List available source types

```
kn source list-types [flags]
```

### Options

```
--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-types
-n, --namespace string Specify the namespace to operate in.
--no-headers When using the default output format, don't print headers (default: print headers).
-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 kn config file (default is $HOME/.kn/config.yaml)
--kubeconfig string kubectl config file (default is $HOME/.kube/config)
--log-http log http traffic
```

### SEE ALSO

* [kn source](kn_source.md) - Event Source command group

2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ require (
// Fix for `[` in help messages and shell completion code
// See https://github.com/spf13/cobra/pull/899
replace github.com/spf13/cobra => github.com/chmouel/cobra v0.0.0-20191021105835-a78788917390

go 1.13
86 changes: 86 additions & 0 deletions pkg/dynamic/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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 rest

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)

// KnRESTClient to client-go REST client. All methods are relative to the
// namespace specified during construction
type KnDynamicClient interface {
// Namespace in which this client is operating for
Namespace() string

// ListCRDs returns list of CRDs with their type and name
ListCRDs(options metav1.ListOptions) (*unstructured.UnstructuredList, error)

// ListSourceCRDs returns list of eventing sources CRDs
ListSourcesTypes() (*unstructured.UnstructuredList, error)
}

// KnRESTClient is a combination of client-go REST client interface and namespace
type knDynamicClient struct {
client dynamic.Interface
namespace string
}

// CRDKindName holds Kind and Name of a CRD
type CRDKindName struct {
Kind, Name string
}

// NewKnRESTClient is to invoke Eventing Sources Client API to create object
func NewDynamicClient(client dynamic.Interface, namespace string) KnDynamicClient {
return &knDynamicClient{
client: client,
namespace: namespace,
}
}

// Return the client's namespace
func (c *knDynamicClient) Namespace() string {
return c.namespace
}

// TODO(navidshaikh): Use ListConfigs here instead of ListOptions
// ListCRDs returns list of installed CRDs in the cluster and filters based on the given options
func (c *knDynamicClient) ListCRDs(options metav1.ListOptions) (*unstructured.UnstructuredList, error) {
// TODO (navidshaikh): We should populate this in a better way
gvr := schema.GroupVersionResource{
"apiextensions.k8s.io",
"v1beta1",
"customresourcedefinitions",
}

uList, err := c.client.Resource(gvr).List(options)
if err != nil {
return nil, err
}

return uList, nil
}

// ListSourcesTypes returns installed knative eventing sources CRDs
func (c *knDynamicClient) ListSourcesTypes() (*unstructured.UnstructuredList, error) {
options := metav1.ListOptions{}
sourcesLabels := labels.Set{"duck.knative.dev/source": "true"}
options.LabelSelector = sourcesLabels.String()
return c.ListCRDs(options)
}
2 changes: 1 addition & 1 deletion pkg/eventing/sources/v1alpha1/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ type knSourcesClient struct {
// NewKnSourcesClient is to invoke Eventing Sources Client API to create object
func NewKnSourcesClient(client client_v1alpha1.SourcesV1alpha1Interface, namespace string) KnSourcesClient {
return &knSourcesClient{
namespace: namespace,
client: client,
namespace: namespace,
}
}

Expand Down
80 changes: 80 additions & 0 deletions pkg/kn/commands/source/human_readable_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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 source

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
hprinters "knative.dev/client/pkg/printers"
)

var sourceTypeDescription = map[string]string{
"ApiServerSource": "Kubernetes API Server events source",
"ContainerSource": "Container events source",
"CronJobSource": "CronJob events source",
}

func getSourceTypeDescription(kind string) string {
return sourceTypeDescription[kind]
}

func SourceListTypesHandlers(h hprinters.PrintHandler) {
sourceTypesColumnDefinitions := []metav1beta1.TableColumnDefinition{
{Name: "Type", Type: "string", Description: "Kind / Type of the source type", Priority: 1},
{Name: "Name", Type: "string", Description: "Name of the source type", Priority: 1},
{Name: "Description", Type: "string", Description: "Description of the source type", Priority: 1},
}
h.TableHandler(sourceTypesColumnDefinitions, printSourceTypes)
h.TableHandler(sourceTypesColumnDefinitions, printSourceTypesList)
}

// printSourceTypes populates a single row of source types list table
func printSourceTypes(sourceType unstructured.Unstructured, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
name := sourceType.GetName()
content := sourceType.UnstructuredContent()
kind, found, err := unstructured.NestedString(content, "spec", "names", "kind")
if err != nil {
return nil, err
}

if !found {
return nil, fmt.Errorf("can't find kind of CRD for %s", name)
}

row := metav1beta1.TableRow{
Object: runtime.RawExtension{Object: &sourceType},
}

row.Cells = append(row.Cells, kind, name, getSourceTypeDescription(kind))
return []metav1beta1.TableRow{row}, nil
}

// printSourceTypesList populates the source types list table rows
func printSourceTypesList(sourceTypesList *unstructured.UnstructuredList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
rows := make([]metav1beta1.TableRow, 0, len(sourceTypesList.Items))

for _, item := range sourceTypesList.Items {
row, err := printSourceTypes(item, options)
if err != nil {
return nil, err
}

rows = append(rows, row...)
}
return rows, nil
}
68 changes: 68 additions & 0 deletions pkg/kn/commands/source/list_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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 source

import (
"fmt"

"github.com/spf13/cobra"

"knative.dev/client/pkg/kn/commands"
)

func NewListTypesCommand(p *commands.KnParams) *cobra.Command {
sourceListTypesFlags := NewSourceListTypesFlags()
listTypesCommand := &cobra.Command{
Use: "list-types",
Short: "List available source types",
RunE: func(cmd *cobra.Command, args []string) error {
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}

dynamicClient, err := p.NewDynamicClient(namespace)
if err != nil {
return err
}

sourceListTypes, err := dynamicClient.ListSourcesTypes()
if err != nil {
return err
}

if len(sourceListTypes.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No sources found.\n")
return nil
}

printer, err := sourceListTypesFlags.ToPrinter()
if err != nil {
return nil
}
//TODO(navidshaikh): Sort the list

err = printer.PrintObj(sourceListTypes, cmd.OutOrStdout())
if err != nil {
return err
}

return nil
},
}
commands.AddNamespaceFlags(listTypesCommand.Flags(), false)
sourceListTypesFlags.AddFlags(listTypesCommand)
return listTypesCommand
}
71 changes: 71 additions & 0 deletions pkg/kn/commands/source/list_types_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 source

import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"knative.dev/client/pkg/kn/commands"
hprinters "knative.dev/client/pkg/printers"
)

// SourceListTypesFlags composes common printer flag structs
// used in the 'kn source list-types' command.
type SourceListTypesFlags struct {
GenericPrintFlags *genericclioptions.PrintFlags
HumanReadableFlags *commands.HumanPrintFlags
}

// AllowedFormats is the list of formats in which data can be displayed
func (f *SourceListTypesFlags) AllowedFormats() []string {
formats := f.GenericPrintFlags.AllowedFormats()
formats = append(formats, f.HumanReadableFlags.AllowedFormats()...)
return formats
}

// ToPrinter attempts to find a composed set of SourceListTypesFlags suitable for
// returning a printer based on current flag values.
func (f *SourceListTypesFlags) 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
}

p, err := f.HumanReadableFlags.ToPrinter(SourceListTypesHandlers)
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 *SourceListTypesFlags) AddFlags(cmd *cobra.Command) {
f.GenericPrintFlags.AddFlags(cmd)
f.HumanReadableFlags.AddFlags(cmd)
}

// NewSourceListTypesFlags returns flags associated with humanreadable,
// template, and "name" printing, with default values set.
func NewSourceListTypesFlags() *SourceListTypesFlags {
return &SourceListTypesFlags{
GenericPrintFlags: genericclioptions.NewPrintFlags(""),
HumanReadableFlags: commands.NewHumanPrintFlags(),
}
}
Loading

0 comments on commit be1e0a8

Please sign in to comment.