Skip to content

Commit

Permalink
Add kn source apiserver list command
Browse files Browse the repository at this point in the history
  • Loading branch information
navidshaikh committed Dec 17, 2019
1 parent 3a6b05d commit 6ae5812
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/cmd/kn_source_apiserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ kn source apiserver [flags]
* [kn source apiserver create](kn_source_apiserver_create.md) - Create an ApiServer source.
* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete an ApiServer source.
* [kn source apiserver describe](kn_source_apiserver_describe.md) - Describe an ApiServer source.
* [kn source apiserver list](kn_source_apiserver_list.md) - List ApiServer sources.
* [kn source apiserver update](kn_source_apiserver_update.md) - Update an ApiServer source.

4 changes: 2 additions & 2 deletions docs/cmd/kn_source_apiserver_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM

```
-h, --help help for create
--mode string The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
--mode string The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
"Resource" send the full resource. (default "Ref")
-n, --namespace string Specify the namespace to operate in.
--resource strings Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
Expand Down
44 changes: 44 additions & 0 deletions docs/cmd/kn_source_apiserver_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## kn source apiserver list

List ApiServer sources.

### Synopsis

List ApiServer sources.

```
kn source apiserver list [flags]
```

### Examples

```
# List all ApiServer sources in YAML format
kn source apiserver list -o yaml
```

### Options

```
-A, --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 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 apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group

4 changes: 2 additions & 2 deletions docs/cmd/kn_source_apiserver_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAM

```
-h, --help help for update
--mode string The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
--mode string The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
"Resource" send the full resource. (default "Ref")
-n, --namespace string Specify the namespace to operate in.
--resource strings Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
Expand Down
33 changes: 33 additions & 0 deletions pkg/eventing/sources/v1alpha1/apiserver_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type KnAPIServerSourcesClient interface {
// Delete an ApiServerSource by name
DeleteAPIServerSource(name string) error

// List ApiServerSource
// TODO: Support list configs like in service list
ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error)

// Get namespace for this client
Namespace() string
}
Expand Down Expand Up @@ -98,6 +102,35 @@ func (c *apiServerSourcesClient) Namespace() string {
return c.namespace
}

// ListAPIServerSource returns the available ApiServer type sources
func (c *apiServerSourcesClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
sourceList, err := c.client.List(metav1.ListOptions{})
if err != nil {
return nil, err
}

return updateAPIServerSourceListGVK(sourceList)
}

func updateAPIServerSourceListGVK(sourceList *v1alpha1.ApiServerSourceList) (*v1alpha1.ApiServerSourceList, error) {
sourceListNew := sourceList.DeepCopy()
err := updateSourceGVK(sourceListNew)
if err != nil {
return nil, err
}

sourceListNew.Items = make([]v1alpha1.ApiServerSource, len(sourceList.Items))
for idx, source := range sourceList.Items {
sourceClone := source.DeepCopy()
err := updateSourceGVK(sourceClone)
if err != nil {
return nil, err
}
sourceListNew.Items[idx] = *sourceClone
}
return sourceListNew, nil
}

// APIServerSourceBuilder is for building the source
type APIServerSourceBuilder struct {
apiServerSource *v1alpha1.ApiServerSource
Expand Down
11 changes: 11 additions & 0 deletions pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ func (c *MockKnAPIServerSourceClient) DeleteAPIServerSource(name string) error {
return mock.ErrorOrNil(call.Result[0])
}

// ListAPIServerSource records a call for ListAPIServerSource with the expected error (nil if none)
func (sr *APIServerSourcesRecorder) ListAPIServerSource(apiJobSourceList *v1alpha1.ApiServerSourceList, err error) {
sr.r.Add("ListAPIServerSource", []interface{}{}, []interface{}{apiJobSourceList, err})
}

// ListAPIServerSource performs a previously recorded action, failing if non has been registered
func (c *MockKnAPIServerSourceClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
call := c.recorder.r.VerifyCall("ListAPIServerSource")
return call.Result[0].(*v1alpha1.ApiServerSourceList), mock.ErrorOrNil(call.Result[1])
}

// Validate validates whether every recorded action has been called
func (sr *APIServerSourcesRecorder) Validate() {
sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
Expand Down
14 changes: 14 additions & 0 deletions pkg/eventing/sources/v1alpha1/apiserver_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ func TestUpdateApiServerSource(t *testing.T) {
assert.ErrorContains(t, err, "errorSource")
}

func TestListAPIServerSource(t *testing.T) {
sourcesServer, client := setupAPIServerSourcesClient(t)

sourcesServer.AddReactor("list", "apiserversources",
func(a client_testing.Action) (bool, runtime.Object, error) {
cJSource := newAPIServerSource("testsource", "Event")
return true, &v1alpha1.ApiServerSourceList{Items: []v1alpha1.ApiServerSource{*cJSource}}, nil
})

sourceList, err := client.ListAPIServerSource()
assert.NilError(t, err)
assert.Equal(t, len(sourceList.Items), 1)
}

func newAPIServerSource(name, resource string) *v1alpha1.ApiServerSource {
b := NewAPIServerSourceBuilder(name).ServiceAccount("testsa").Mode("Ref")
b.Sink(&v1beta1.Destination{
Expand Down
1 change: 1 addition & 0 deletions pkg/kn/commands/source/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func NewAPIServerCommand(p *commands.KnParams) *cobra.Command {
apiServerSourceCmd.AddCommand(NewAPIServerUpdateCommand(p))
apiServerSourceCmd.AddCommand(NewAPIServerDescribeCommand(p))
apiServerSourceCmd.AddCommand(NewAPIServerDeleteCommand(p))
apiServerSourceCmd.AddCommand(NewAPIServerListCommand(p))
return apiServerSourceCmd
}

Expand Down
116 changes: 114 additions & 2 deletions pkg/kn/commands/source/apiserver/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@
package apiserver

import (
"fmt"
"sort"
"strconv"
"strings"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
"knative.dev/client/pkg/kn/commands"
"knative.dev/eventing/pkg/apis/sources/v1alpha1"

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

const (
Expand Down Expand Up @@ -77,8 +84,8 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
cmd.Flags().StringVar(&f.Mode,
"mode",
"Ref",
`The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
`The mode the receive adapter controller runs under:,
"Ref" sends only the reference to the resource,
"Resource" send the full resource.`)
cmd.Flags().StringSliceVar(&f.Resources,
"resource",
Expand All @@ -87,3 +94,108 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
"APIVersion" and "isControler" can be omitted.
"APIVersion" is "v1" by default, "isController" is "false" by default.`)
}

// APIServerSourceListHandlers handles printing human readable table for `kn source apiserver list` command's output
func APIServerSourceListHandlers(h hprinters.PrintHandler) {
sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
{Name: "Namespace", Type: "string", Description: "Namespace of the ApiServer source", Priority: 0},
{Name: "Name", Type: "string", Description: "Name of the ApiServer source", Priority: 1},
{Name: "Resources", Type: "string", Description: "Event resources configured for the ApiServer source", Priority: 1},
{Name: "Sink", Type: "string", Description: "Sink of the ApiServer source", Priority: 1},
{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
{Name: "Ready", Type: "string", Description: "Ready state of the ApiServer source", Priority: 1},
{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
}
h.TableHandler(sourceColumnDefinitions, printSource)
h.TableHandler(sourceColumnDefinitions, printSourceList)
}

// printSource populates a single row of source apiserver list table
func printSource(source *v1alpha1.ApiServerSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
row := metav1beta1.TableRow{
Object: runtime.RawExtension{Object: source},
}

name := source.Name
conditions := commands.ConditionsValue(source.Status.Conditions)
ready := commands.ReadyCondition(source.Status.Conditions)
reason := strings.TrimSpace(commands.NonReadyConditionReason(source.Status.Conditions))
var resources []string
for _, resource := range source.Spec.Resources {
resources = append(resources, fmt.Sprintf("%s:%s:%s", resource.Kind, resource.APIVersion, strconv.FormatBool(resource.Controller)))
}

var sink string
if source.Spec.Sink != nil {
if source.Spec.Sink.Ref != nil {
if source.Spec.Sink.Ref.Kind == "Service" {
sink = fmt.Sprintf("svc:%s", source.Spec.Sink.Ref.Name)
} else {
sink = fmt.Sprintf("%s:%s", source.Spec.Sink.Ref.Kind, source.Spec.Sink.Ref.Name)
}
}
}

if options.AllNamespaces {
row.Cells = append(row.Cells, source.Namespace)
}

row.Cells = append(row.Cells, name, strings.Join(resources[:], ","), sink, conditions, ready, reason)
return []metav1beta1.TableRow{row}, nil
}

// printSourceList populates the source apiserver list table rows
func printSourceList(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
if options.AllNamespaces {
return printSourceListWithNamespace(sourceList, options)
}

rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))

sort.SliceStable(sourceList.Items, func(i, j int) bool {
return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
})

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

rows = append(rows, row...)
}
return rows, nil
}

// printSourceListWithNamespace populates the knative service table rows with namespace column
func printSourceListWithNamespace(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))

// temporary slice for sorting services in non-default namespace
others := []metav1beta1.TableRow{}

for _, source := range sourceList.Items {
// Fill in with services in `default` namespace at first
if source.Namespace == "default" {
r, err := printSource(&source, options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
continue
}
// put other services in temporary slice
r, err := printSource(&source, options)
if err != nil {
return nil, err
}
others = append(others, r...)
}

// sort other services list alphabetically by namespace
sort.SliceStable(others, func(i, j int) bool {
return others[i].Cells[0].(string) < others[j].Cells[0].(string)
})

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

import (
"fmt"

"github.com/spf13/cobra"
"knative.dev/client/pkg/kn/commands"
"knative.dev/client/pkg/kn/commands/flags"
)

// NewAPIServerListCommand is for listing ApiServer source COs
func NewAPIServerListCommand(p *commands.KnParams) *cobra.Command {
listFlags := flags.NewListFlags(APIServerSourceListHandlers)

listCommand := &cobra.Command{
Use: "list",
Short: "List ApiServer sources.",
Example: `
# List all ApiServer sources in YAML format
kn source apiserver list -o yaml`,

RunE: func(cmd *cobra.Command, args []string) (err error) {
// TODO: filter list by given source name

apiSourceClient, err := newAPIServerSourceClient(p, cmd)
if err != nil {
return err
}

sourceList, err := apiSourceClient.ListAPIServerSource()
if err != nil {
return err
}

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

if apiSourceClient.Namespace() == "" {
listFlags.EnsureWithNamespace()
}

printer, err := listFlags.ToPrinter()
if err != nil {
return nil
}

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

return nil
},
}
commands.AddNamespaceFlags(listCommand.Flags(), true)
listFlags.AddFlags(listCommand)
return listCommand
}
Loading

0 comments on commit 6ae5812

Please sign in to comment.