diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 2c50157649..6a5df9d492 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -53,6 +53,10 @@ | ✨ | `kn source list` output now has client custom GVK set as `{Group: client.knative.dev, Version: v1alpha1, Kind: SourceList}` | https://github.com/knative/client/pull/980[#980] + +| 🎁 +| Manage knative eventing channels +| https://github.com/knative/client/pull/967[#967] |=== ## v0.16.0 (2020-07-14) diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md index 2769819451..affc0162ac 100644 --- a/docs/cmd/kn.md +++ b/docs/cmd/kn.md @@ -20,6 +20,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou ### SEE ALSO * [kn broker](kn_broker.md) - Manage message broker +* [kn channel](kn_channel.md) - Manage event channels * [kn completion](kn_completion.md) - Output shell completion code * [kn options](kn_options.md) - Print the list of flags inherited by all commands * [kn plugin](kn_plugin.md) - Manage kn plugins diff --git a/docs/cmd/kn_channel.md b/docs/cmd/kn_channel.md new file mode 100644 index 0000000000..41e69096ad --- /dev/null +++ b/docs/cmd/kn_channel.md @@ -0,0 +1,34 @@ +## kn channel + +Manage event channels + +### Synopsis + +Manage event channels + +``` +kn channel COMMAND +``` + +### Options + +``` + -h, --help help for channel +``` + +### Options inherited from parent commands + +``` + --config string kn configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn](kn.md) - kn manages Knative Serving and Eventing resources +* [kn channel create](kn_channel_create.md) - Create an event channel +* [kn channel delete](kn_channel_delete.md) - Delete a channel +* [kn channel describe](kn_channel_describe.md) - Show details of a channel +* [kn channel list](kn_channel_list.md) - List channels + diff --git a/docs/cmd/kn_channel_create.md b/docs/cmd/kn_channel_create.md new file mode 100644 index 0000000000..c709efe7be --- /dev/null +++ b/docs/cmd/kn_channel_create.md @@ -0,0 +1,48 @@ +## kn channel create + +Create an event channel + +### Synopsis + +Create an event channel + +``` +kn channel create NAME +``` + +### Examples + +``` + + # Create a channel 'pipe' with default setting for channel configuration + kn channel create pipe + + # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc' + kn channel create imc1 --type imc + # same as above without using inbuilt alias but providing explicit GVK + kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel + + # Create a channel 'k1' of type KafkaChannel + kn channel create k1 --type messaging.knative.dev:v1alpha1:KafkaChannel +``` + +### Options + +``` + -h, --help help for create + -n, --namespace string Specify the namespace to operate in. + --type string Override channel type to create, in the format '--type Group:Version:Kind'. If flag is not specified, it uses default messaging layer settings for channel type, cluster wide or specific namespace. You can configure aliases for channel types in kn config and refer the aliases with this flag. You can also refer inbuilt channel type InMemoryChannel using an alias 'imc' like '--type imc'. Examples: '--type messaging.knative.dev:v1alpha1:KafkaChannel' for specifying explicit Group:Version:Kind. +``` + +### Options inherited from parent commands + +``` + --config string kn configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn channel](kn_channel.md) - Manage event channels + diff --git a/docs/cmd/kn_channel_delete.md b/docs/cmd/kn_channel_delete.md new file mode 100644 index 0000000000..78e8110ee0 --- /dev/null +++ b/docs/cmd/kn_channel_delete.md @@ -0,0 +1,39 @@ +## kn channel delete + +Delete a channel + +### Synopsis + +Delete a channel + +``` +kn channel delete NAME +``` + +### Examples + +``` + + # Delete a channel 'pipe' + kn channel delete pipe +``` + +### Options + +``` + -h, --help help for delete + -n, --namespace string Specify the namespace to operate in. +``` + +### Options inherited from parent commands + +``` + --config string kn configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn channel](kn_channel.md) - Manage event channels + diff --git a/docs/cmd/kn_channel_describe.md b/docs/cmd/kn_channel_describe.md new file mode 100644 index 0000000000..88df50d168 --- /dev/null +++ b/docs/cmd/kn_channel_describe.md @@ -0,0 +1,43 @@ +## kn channel describe + +Show details of a channel + +### Synopsis + +Show details of a channel + +``` +kn channel describe NAME +``` + +### Examples + +``` + + # Describe a channel 'pipe' + kn channel describe pipe +``` + +### 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 describe + -n, --namespace string Specify the namespace to operate in. + -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]. + -v, --verbose More output. +``` + +### Options inherited from parent commands + +``` + --config string kn configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn channel](kn_channel.md) - Manage event channels + diff --git a/docs/cmd/kn_channel_list.md b/docs/cmd/kn_channel_list.md new file mode 100644 index 0000000000..646f663f34 --- /dev/null +++ b/docs/cmd/kn_channel_list.md @@ -0,0 +1,47 @@ +## kn channel list + +List channels + +### Synopsis + +List channels + +``` +kn channel list +``` + +### Examples + +``` + + # List all channels + kn channel list + + # List channels in YAML format + kn channel ping 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 configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn channel](kn_channel.md) - Manage event channels + diff --git a/lib/test/channel.go b/lib/test/channel.go new file mode 100644 index 0000000000..5eedeb6c78 --- /dev/null +++ b/lib/test/channel.go @@ -0,0 +1,55 @@ +// Copyright 2020 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 test + +import ( + "time" + + "gotest.tools/assert" + + "knative.dev/client/pkg/util" +) + +func ChannelCreate(r *KnRunResultCollector, cname string, args ...string) { + cmd := []string{"channel", "create", cname} + cmd = append(cmd, args...) + out := r.KnTest().Kn().Run(cmd...) + r.AssertNoError(out) + assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "channel", cname, "created")) + // let channel reconcile TODO: fix the wait for channel to become ready + time.Sleep(5 * time.Second) +} + +func ChannelList(r *KnRunResultCollector, args ...string) string { + cmd := []string{"channel", "list"} + cmd = append(cmd, args...) + out := r.KnTest().Kn().Run(cmd...) + r.AssertNoError(out) + return out.Stdout +} + +func ChannelDescribe(r *KnRunResultCollector, cname string, args ...string) string { + cmd := []string{"channel", "describe", cname} + cmd = append(cmd, args...) + out := r.KnTest().Kn().Run(cmd...) + r.AssertNoError(out) + return out.Stdout +} + +func ChannelDelete(r *KnRunResultCollector, cname string) { + out := r.KnTest().Kn().Run("channel", "delete", cname) + r.AssertNoError(out) + assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "channel", cname, "deleted")) +} diff --git a/pkg/errors/factory.go b/pkg/errors/factory.go index 48b076ee55..80f03d4816 100644 --- a/pkg/errors/factory.go +++ b/pkg/errors/factory.go @@ -42,6 +42,10 @@ func isEmptyConfigError(err error) bool { //Retrieves a custom error struct based on the original error APIStatus struct //Returns the original error struct in case it can't identify the kind of APIStatus error func GetError(err error) error { + if err == nil { + return nil + } + switch { case isEmptyConfigError(err): return newNoKubeConfig(err.Error()) diff --git a/pkg/errors/factory_test.go b/pkg/errors/factory_test.go index 991f4c3b31..787f615ced 100644 --- a/pkg/errors/factory_test.go +++ b/pkg/errors/factory_test.go @@ -161,3 +161,7 @@ func TestIsForbiddenError(t *testing.T) { }) } } + +func TestNilError(t *testing.T) { + assert.NilError(t, GetError(nil), nil) +} diff --git a/pkg/kn/commands/channel/channel.go b/pkg/kn/commands/channel/channel.go new file mode 100644 index 0000000000..be324754da --- /dev/null +++ b/pkg/kn/commands/channel/channel.go @@ -0,0 +1,67 @@ +// Copyright © 2020 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 channel + +import ( + "github.com/spf13/cobra" + + "k8s.io/client-go/tools/clientcmd" + clientv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" + + "knative.dev/client/pkg/kn/commands" + messagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1" +) + +// NewChannelCommand to manage event channels +func NewChannelCommand(p *commands.KnParams) *cobra.Command { + channelCmd := &cobra.Command{ + Use: "channel COMMAND", + Short: "Manage event channels", + } + channelCmd.AddCommand(NewChannelCreateCommand(p)) + channelCmd.AddCommand(NewChannelListCommand(p)) + channelCmd.AddCommand(NewChannelDeleteCommand(p)) + channelCmd.AddCommand(NewChannelDescribeCommand(p)) + return channelCmd +} + +var channelClientFactory func(config clientcmd.ClientConfig, namespace string) (messagingv1beta1.KnChannelsClient, error) + +func newChannelClient(p *commands.KnParams, cmd *cobra.Command) (messagingv1beta1.KnChannelsClient, error) { + namespace, err := p.GetNamespace(cmd) + if err != nil { + return nil, err + } + + if channelClientFactory != nil { + config, err := p.GetClientConfig() + if err != nil { + return nil, err + } + return channelClientFactory(config, namespace) + } + + clientConfig, err := p.RestConfig() + if err != nil { + return nil, err + } + + client, err := clientv1beta1.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + return messagingv1beta1.NewKnMessagingClient(client, namespace).ChannelsClient(), nil +} diff --git a/pkg/kn/commands/channel/channel_test.go b/pkg/kn/commands/channel/channel_test.go new file mode 100644 index 0000000000..861c1d9e3c --- /dev/null +++ b/pkg/kn/commands/channel/channel_test.go @@ -0,0 +1,81 @@ +// 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 channel + +import ( + "bytes" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/clientcmd" + "knative.dev/eventing/pkg/apis/messaging/v1beta1" + + "knative.dev/client/pkg/kn/commands" + clientv1beta1 "knative.dev/client/pkg/messaging/v1beta1" +) + +// Helper methods +var blankConfig clientcmd.ClientConfig + +// TODO: Remove that blankConfig hack for tests in favor of overwriting GetConfig() +func init() { + var err error + blankConfig, err = clientcmd.NewClientConfigFromBytes([]byte(`kind: Config +version: v1 +users: +- name: u +clusters: +- name: c + cluster: + server: example.com +contexts: +- name: x + context: + user: u + cluster: c +current-context: x +`)) + if err != nil { + panic(err) + } +} + +func executeChannelCommand(channelClient clientv1beta1.KnChannelsClient, args ...string) (string, error) { + knParams := &commands.KnParams{} + knParams.ClientConfig = blankConfig + + output := new(bytes.Buffer) + knParams.Output = output + + cmd := NewChannelCommand(knParams) + cmd.SetArgs(args) + cmd.SetOutput(output) + + channelClientFactory = func(config clientcmd.ClientConfig, namespace string) (clientv1beta1.KnChannelsClient, error) { + return channelClient, nil + } + defer cleanupChannelMockClient() + + err := cmd.Execute() + + return output.String(), err +} + +func cleanupChannelMockClient() { + channelClientFactory = nil +} + +func createChannel(name string, gvk *schema.GroupVersionKind) *v1beta1.Channel { + return clientv1beta1.NewChannelBuilder(name).Type(gvk).Build() +} diff --git a/pkg/kn/commands/channel/create.go b/pkg/kn/commands/channel/create.go new file mode 100644 index 0000000000..145c9b8f4c --- /dev/null +++ b/pkg/kn/commands/channel/create.go @@ -0,0 +1,85 @@ +// Copyright © 2020 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 channel + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + + knerrors "knative.dev/client/pkg/errors" + "knative.dev/client/pkg/kn/commands" + knflags "knative.dev/client/pkg/kn/flags" + knmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1" +) + +// NewChannelCreateCommand to create event channels +func NewChannelCreateCommand(p *commands.KnParams) *cobra.Command { + var ctypeFlags knflags.ChannelTypeFlags + cmd := &cobra.Command{ + Use: "create NAME", + Short: "Create an event channel", + Example: ` + # Create a channel 'pipe' with default setting for channel configuration + kn channel create pipe + + # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc' + kn channel create imc1 --type imc + # same as above without using inbuilt alias but providing explicit GVK + kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel + + # Create a channel 'k1' of type KafkaChannel + kn channel create k1 --type messaging.knative.dev:v1alpha1:KafkaChannel`, + + RunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) != 1 { + return errors.New("'kn channel create' requires the channel name given as single argument") + } + name := args[0] + + namespace, err := p.GetNamespace(cmd) + if err != nil { + return err + } + + client, err := newChannelClient(p, cmd) + if err != nil { + return err + } + + cb := knmessagingv1beta1.NewChannelBuilder(name) + + if cmd.Flag("type").Changed { + gvk, err := ctypeFlags.Parse() + if err != nil { + return err + } + cb.Type(gvk) + } + + err = client.CreateChannel(cb.Build()) + if err != nil { + return knerrors.GetError(err) + } + + fmt.Fprintf(cmd.OutOrStdout(), "Channel '%s' created in namespace '%s'.\n", name, namespace) + return nil + }, + } + commands.AddNamespaceFlags(cmd.Flags(), false) + ctypeFlags.Add(cmd.Flags()) + return cmd +} diff --git a/pkg/kn/commands/channel/create_test.go b/pkg/kn/commands/channel/create_test.go new file mode 100644 index 0000000000..8c6a13d897 --- /dev/null +++ b/pkg/kn/commands/channel/create_test.go @@ -0,0 +1,61 @@ +// Copyright © 2020 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 channel + +import ( + "testing" + + "gotest.tools/assert" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/client/pkg/messaging/v1beta1" + + "knative.dev/client/pkg/util" +) + +func TestCreateChannelErrorCase(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + _, err := executeChannelCommand(cClient, "create") + assert.Error(t, err, "'kn channel create' requires the channel name given as single argument") + cRecorder.Validate() +} + +func TestCreateChannelErrorCaseTypeFormat(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + _, err := executeChannelCommand(cClient, "create", "pipe", "--type", "foo::bar") + assert.Error(t, err, "Error: incorrect value 'foo::bar' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config") + cRecorder.Validate() +} + +func TestCreateChannelDefaultChannel(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + cRecorder.CreateChannel(createChannel("pipe", nil), nil) + out, err := executeChannelCommand(cClient, "create", "pipe") + assert.NilError(t, err, "channel should be created") + assert.Assert(t, util.ContainsAll(out, "created", "pipe", "default")) + cRecorder.Validate() +} + +func TestCreateChannelWithTypeFlagInMemoryChannel(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + cRecorder.CreateChannel(createChannel("pipe", &schema.GroupVersionKind{"messaging.knative.dev", "v1beta1", "InMemoryChannel"}), nil) + out, err := executeChannelCommand(cClient, "create", "pipe", "--type", "imcv1beta1") + assert.NilError(t, err, "channel should be created") + assert.Assert(t, util.ContainsAll(out, "created", "pipe", "default")) + cRecorder.Validate() +} diff --git a/pkg/kn/commands/channel/delete.go b/pkg/kn/commands/channel/delete.go new file mode 100644 index 0000000000..b52bd5ccbd --- /dev/null +++ b/pkg/kn/commands/channel/delete.go @@ -0,0 +1,55 @@ +// Copyright © 2020 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 channel + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + "knative.dev/client/pkg/kn/commands" +) + +// NewChannelDeleteCommand is for deleting a Channel +func NewChannelDeleteCommand(p *commands.KnParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete NAME", + Short: "Delete a channel", + Example: ` + # Delete a channel 'pipe' + kn channel delete pipe`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("'kn channel delete' requires the channel name as single argument") + } + name := args[0] + + channelClient, err := newChannelClient(p, cmd) + if err != nil { + return err + } + + err = channelClient.DeleteChannel(name) + if err != nil { + return err + } + + fmt.Fprintf(cmd.OutOrStdout(), "Channel '%s' deleted in namespace '%s'.\n", name, channelClient.Namespace()) + return nil + }, + } + commands.AddNamespaceFlags(cmd.Flags(), false) + return cmd +} diff --git a/pkg/kn/commands/channel/delete_test.go b/pkg/kn/commands/channel/delete_test.go new file mode 100644 index 0000000000..0edb6b1d68 --- /dev/null +++ b/pkg/kn/commands/channel/delete_test.go @@ -0,0 +1,52 @@ +// Copyright © 2020 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 channel + +import ( + "errors" + "testing" + + "gotest.tools/assert" + + "knative.dev/client/pkg/messaging/v1beta1" + "knative.dev/client/pkg/util" +) + +func TestDeleteChannelErrorCase(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t, "test") + cRecorder := cClient.Recorder() + _, err := executeChannelCommand(cClient, "delete") + assert.Error(t, err, "'kn channel delete' requires the channel name as single argument") + cRecorder.Validate() +} + +func TestDeleteWithError(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t, "test") + cRecorder := cClient.Recorder() + cRecorder.DeleteChannel("pipe", errors.New("not found")) + _, err := executeChannelCommand(cClient, "delete", "pipe") + assert.ErrorContains(t, err, "not found") + cRecorder.Validate() +} + +func TestChannelDelete(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t, "test") + cRecorder := cClient.Recorder() + cRecorder.DeleteChannel("pipe", nil) + out, err := executeChannelCommand(cClient, "delete", "pipe") + assert.NilError(t, err) + assert.Assert(t, util.ContainsAll(out, "deleted", "pipe", "test")) + cRecorder.Validate() +} diff --git a/pkg/kn/commands/channel/describe.go b/pkg/kn/commands/channel/describe.go new file mode 100644 index 0000000000..747507b501 --- /dev/null +++ b/pkg/kn/commands/channel/describe.go @@ -0,0 +1,105 @@ +// Copyright © 2020 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 channel + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + + "k8s.io/cli-runtime/pkg/genericclioptions" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + + knerrors "knative.dev/client/pkg/errors" + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/printers" +) + +// NewChannelDescribeCommand returns a new command for describe a channel object +func NewChannelDescribeCommand(p *commands.KnParams) *cobra.Command { + + // For machine readable output + machineReadablePrintFlags := genericclioptions.NewPrintFlags("") + + cmd := &cobra.Command{ + Use: "describe NAME", + Short: "Show details of a channel", + Example: ` + # Describe a channel 'pipe' + kn channel describe pipe`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("'kn channel describe' requires the channel name given as single argument") + } + name := args[0] + + client, err := newChannelClient(p, cmd) + if err != nil { + return err + } + + channel, err := client.GetChannel(name) + if err != nil { + return knerrors.GetError(err) + } + + out := cmd.OutOrStdout() + + if machineReadablePrintFlags.OutputFlagSpecified() { + printer, err := machineReadablePrintFlags.ToPrinter() + if err != nil { + return err + } + return printer.PrintObj(channel, out) + } + + dw := printers.NewPrefixWriter(out) + + printDetails, err := cmd.Flags().GetBool("verbose") + if err != nil { + return err + } + + writeChannel(dw, channel, printDetails) + dw.WriteLine() + if err := dw.Flush(); err != nil { + return err + } + + // Condition info + commands.WriteConditions(dw, channel.Status.Conditions, printDetails) + if err := dw.Flush(); err != nil { + return err + } + + return nil + }, + } + flags := cmd.Flags() + commands.AddNamespaceFlags(flags, false) + flags.BoolP("verbose", "v", false, "More output.") + machineReadablePrintFlags.AddFlags(cmd) + return cmd +} + +func writeChannel(dw printers.PrefixWriter, channel *messagingv1beta1.Channel, printDetails bool) { + commands.WriteMetadata(dw, &channel.ObjectMeta, printDetails) + ctype := fmt.Sprintf("%s (%s)", channel.Spec.ChannelTemplate.Kind, channel.Spec.ChannelTemplate.APIVersion) + dw.WriteAttribute("Type", ctype) + if channel.Status.Address != nil { + dw.WriteAttribute("URL", channel.Status.Address.URL.String()) + } +} diff --git a/pkg/kn/commands/channel/describe_test.go b/pkg/kn/commands/channel/describe_test.go new file mode 100644 index 0000000000..5466b92ac7 --- /dev/null +++ b/pkg/kn/commands/channel/describe_test.go @@ -0,0 +1,53 @@ +// Copyright © 2020 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 channel + +import ( + "errors" + "testing" + + "gotest.tools/assert" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/client/pkg/messaging/v1beta1" + + "knative.dev/client/pkg/util" +) + +func TestDescribeChannelErrorCase(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + _, err := executeChannelCommand(cClient, "describe") + assert.Error(t, err, "'kn channel describe' requires the channel name given as single argument") + cRecorder.Validate() +} + +func TestDescribeChannelErrorCaseNotFound(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + cRecorder.GetChannel("pipe", nil, errors.New("not found")) + _, err := executeChannelCommand(cClient, "describe", "pipe") + assert.Error(t, err, "not found") + cRecorder.Validate() +} + +func TestDescribeChannel(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + cRecorder.GetChannel("pipe", createChannel("pipe", &schema.GroupVersionKind{"messaging.knative.dev", "v1beta1", "InMemoryChannel"}), nil) + out, err := executeChannelCommand(cClient, "describe", "pipe") + assert.NilError(t, err, "channel should be described") + assert.Assert(t, util.ContainsAll(out, "messaging.knative.dev", "v1beta1", "InMemoryChannel", "pipe")) + cRecorder.Validate() +} diff --git a/pkg/kn/commands/channel/flags.go b/pkg/kn/commands/channel/flags.go new file mode 100644 index 0000000000..254731296c --- /dev/null +++ b/pkg/kn/commands/channel/flags.go @@ -0,0 +1,122 @@ +// Copyright © 2020 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 channel + +import ( + "sort" + + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/client/pkg/kn/commands" + hprinters "knative.dev/client/pkg/printers" + + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// ListHandlers handles printing human readable table for `kn channel list` command's output +func ListHandlers(h hprinters.PrintHandler) { + channelColumnDefinitions := []metav1beta1.TableColumnDefinition{ + {Name: "Namespace", Type: "string", Description: "Namespace of the Channel", Priority: 0}, + {Name: "Name", Type: "string", Description: "Name of the Channel", Priority: 1}, + {Name: "Type", Type: "string", Description: "Type of the Channel", Priority: 1}, + {Name: "URL", Type: "string", Description: "URL of the Channel", Priority: 1}, + {Name: "Age", Type: "string", Description: "Age of the Channel", Priority: 1}, + {Name: "Ready", Type: "string", Description: "Ready state of the Channel", Priority: 1}, + {Name: "Reason", Type: "string", Description: "Reason for non ready channel", Priority: 1}, + } + h.TableHandler(channelColumnDefinitions, printChannel) + h.TableHandler(channelColumnDefinitions, printChannelList) +} + +// printChannel populates a single row of Channel list +func printChannel(channel *messagingv1beta1.Channel, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { + row := metav1beta1.TableRow{ + Object: runtime.RawExtension{Object: channel}, + } + + name := channel.Name + ctype := channel.Spec.ChannelTemplate.Kind + url := "" + if channel.Status.Address != nil { + url = channel.Status.Address.URL.String() + } + age := commands.TranslateTimestampSince(channel.CreationTimestamp) + ready := commands.ReadyCondition(channel.Status.Conditions) + reason := commands.NonReadyConditionReason(channel.Status.Conditions) + + if options.AllNamespaces { + row.Cells = append(row.Cells, channel.Namespace) + } + + row.Cells = append(row.Cells, name, ctype, url, age, ready, reason) + return []metav1beta1.TableRow{row}, nil +} + +// printChannelList populates the Channel list table rows +func printChannelList(channelList *messagingv1beta1.ChannelList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { + if options.AllNamespaces { + return printChannelListWithNamespace(channelList, options) + } + + rows := make([]metav1beta1.TableRow, 0, len(channelList.Items)) + + sort.SliceStable(channelList.Items, func(i, j int) bool { + return channelList.Items[i].GetName() < channelList.Items[j].GetName() + }) + + for _, item := range channelList.Items { + row, err := printChannel(&item, options) + if err != nil { + return nil, err + } + + rows = append(rows, row...) + } + return rows, nil +} + +// printChannelListWithNamespace populates the knative service table rows with namespace column +func printChannelListWithNamespace(channelList *messagingv1beta1.ChannelList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { + rows := make([]metav1beta1.TableRow, 0, len(channelList.Items)) + + // temporary slice for sorting services in non-default namespace + var others []metav1beta1.TableRow + + for _, channel := range channelList.Items { + // Fill in with services in `default` namespace at first + if channel.Namespace == "default" { + r, err := printChannel(&channel, options) + if err != nil { + return nil, err + } + rows = append(rows, r...) + continue + } + // put other services in temporary slice + r, err := printChannel(&channel, 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 +} diff --git a/pkg/kn/commands/channel/list.go b/pkg/kn/commands/channel/list.go new file mode 100644 index 0000000000..0d4466dbeb --- /dev/null +++ b/pkg/kn/commands/channel/list.go @@ -0,0 +1,73 @@ +// Copyright © 2020 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 channel + +import ( + "fmt" + + "github.com/spf13/cobra" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/kn/commands/flags" +) + +// NewChannelListCommand is for listing channel objects +func NewChannelListCommand(p *commands.KnParams) *cobra.Command { + listFlags := flags.NewListPrintFlags(ListHandlers) + + listCommand := &cobra.Command{ + Use: "list", + Short: "List channels", + Example: ` + # List all channels + kn channel list + + # List channels in YAML format + kn channel ping list -o yaml`, + + RunE: func(cmd *cobra.Command, args []string) (err error) { + // TODO: filter list by given channel name + + client, err := newChannelClient(p, cmd) + if err != nil { + return err + } + + channelList, err := client.ListChannel() + if err != nil { + return err + } + + if channelList == nil || len(channelList.Items) == 0 { + fmt.Fprintf(cmd.OutOrStdout(), "No channels found.\n") + return nil + } + + if client.Namespace() == "" { + listFlags.EnsureWithNamespace() + } + + err = listFlags.Print(channelList, cmd.OutOrStdout()) + if err != nil { + return err + } + + return nil + }, + } + commands.AddNamespaceFlags(listCommand.Flags(), true) + listFlags.AddFlags(listCommand) + return listCommand +} diff --git a/pkg/kn/commands/channel/list_test.go b/pkg/kn/commands/channel/list_test.go new file mode 100644 index 0000000000..79d8ca83a2 --- /dev/null +++ b/pkg/kn/commands/channel/list_test.go @@ -0,0 +1,52 @@ +// Copyright © 2020 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 channel + +import ( + "testing" + + "gotest.tools/assert" + "k8s.io/apimachinery/pkg/runtime/schema" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + + v1beta1 "knative.dev/client/pkg/messaging/v1beta1" + + "knative.dev/client/pkg/util" +) + +func TestChannelListNoChannelsFound(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + cRecorder.ListChannel(nil, nil) + out, err := executeChannelCommand(cClient, "list") + assert.NilError(t, err) + assert.Check(t, util.ContainsAll(out, "No channels found")) + cRecorder.Validate() +} + +func TestChannelList(t *testing.T) { + cClient := v1beta1.NewMockKnChannelsClient(t) + cRecorder := cClient.Recorder() + clist := &messagingv1beta1.ChannelList{} + clist.Items = []messagingv1beta1.Channel{ + *createChannel("c0", &schema.GroupVersionKind{"messaging.knative.dev", "v1beta1", "InMemoryChannel"}), + *createChannel("c1", &schema.GroupVersionKind{"messaging.knative.dev", "v1beta1", "InMemoryChannel"}), + } + cRecorder.ListChannel(clist, nil) + out, err := executeChannelCommand(cClient, "list") + assert.NilError(t, err) + assert.Check(t, util.ContainsAll(out, "c0", "c1")) + cRecorder.Validate() +} diff --git a/pkg/kn/commands/types.go b/pkg/kn/commands/types.go index 4c57cf3a4d..6e46164a6a 100644 --- a/pkg/kn/commands/types.go +++ b/pkg/kn/commands/types.go @@ -24,6 +24,7 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" + messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" sourcesv1alpha2client "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2" servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1" @@ -33,18 +34,20 @@ import ( clientdynamic "knative.dev/client/pkg/dynamic" knerrors "knative.dev/client/pkg/errors" clienteventingv1beta1 "knative.dev/client/pkg/eventing/v1beta1" + clientmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1" clientservingv1 "knative.dev/client/pkg/serving/v1" ) // KnParams for creating commands. Useful for inserting mocks for testing. type KnParams struct { - Output io.Writer - KubeCfgPath string - ClientConfig clientcmd.ClientConfig - NewServingClient func(namespace string) (clientservingv1.KnServingClient, error) - NewSourcesClient func(namespace string) (v1alpha2.KnSourcesClient, error) - NewEventingClient func(namespace string) (clienteventingv1beta1.KnEventingClient, error) - NewDynamicClient func(namespace string) (clientdynamic.KnDynamicClient, error) + Output io.Writer + KubeCfgPath string + ClientConfig clientcmd.ClientConfig + NewServingClient func(namespace string) (clientservingv1.KnServingClient, error) + NewSourcesClient func(namespace string) (v1alpha2.KnSourcesClient, error) + NewEventingClient func(namespace string) (clienteventingv1beta1.KnEventingClient, error) + NewMessagingClient func(namespace string) (clientmessagingv1beta1.KnMessagingClient, error) + NewDynamicClient func(namespace string) (clientdynamic.KnDynamicClient, error) // General global options LogHTTP bool @@ -66,6 +69,10 @@ func (params *KnParams) Initialize() { params.NewEventingClient = params.newEventingClient } + if params.NewMessagingClient == nil { + params.NewMessagingClient = params.newMessagingClient + } + if params.NewDynamicClient == nil { params.NewDynamicClient = params.newDynamicClient } @@ -101,6 +108,16 @@ func (params *KnParams) newEventingClient(namespace string) (clienteventingv1bet return clienteventingv1beta1.NewKnEventingClient(client, namespace), nil } +func (params *KnParams) newMessagingClient(namespace string) (clientmessagingv1beta1.KnMessagingClient, error) { + restConfig, err := params.RestConfig() + if err != nil { + return nil, err + } + + client, _ := messagingv1beta1.NewForConfig(restConfig) + return clientmessagingv1beta1.NewKnMessagingClient(client, namespace), nil +} + func (params *KnParams) newDynamicClient(namespace string) (clientdynamic.KnDynamicClient, error) { restConfig, err := params.RestConfig() if err != nil { diff --git a/pkg/kn/commands/types_test.go b/pkg/kn/commands/types_test.go index e83a52f427..118f2179ea 100644 --- a/pkg/kn/commands/types_test.go +++ b/pkg/kn/commands/types_test.go @@ -242,3 +242,53 @@ func TestNewDynamicClient(t *testing.T) { } } } + +func TestNewMessagingClient(t *testing.T) { + basic, err := clientcmd.NewClientConfigFromBytes([]byte(BASIC_KUBECONFIG)) + namespace := "test" + if err != nil { + t.Error(err) + } + for i, tc := range []configTestCase{ + { + clientcmd.NewDefaultClientConfig(clientcmdapi.Config{}, &clientcmd.ConfigOverrides{}), + "no kubeconfig has been provided, please use a valid configuration to connect to the cluster", + false, + }, + { + basic, + "", + false, + }, + { // Test that the cast to wrap the http client in a logger works + basic, + "", + true, + }, + } { + p := &KnParams{ + ClientConfig: tc.clientConfig, + LogHTTP: tc.logHttp, + } + + msgClient, err := p.newMessagingClient(namespace) + + switch len(tc.expectedErrString) { + case 0: + if err != nil { + t.Errorf("%d: unexpected error: %s", i, err.Error()) + } + default: + if err == nil { + t.Errorf("%d: wrong error detected: %s (expected) != %s (actual)", i, tc.expectedErrString, err) + } + if !strings.Contains(err.Error(), tc.expectedErrString) { + t.Errorf("%d: wrong error detected: %s (expected) != %s (actual)", i, tc.expectedErrString, err.Error()) + } + } + + if msgClient != nil { + assert.Assert(t, msgClient.ChannelsClient().Namespace() == namespace) + } + } +} diff --git a/pkg/kn/config/config.go b/pkg/kn/config/config.go index 22e1fe3980..2a20a62148 100644 --- a/pkg/kn/config/config.go +++ b/pkg/kn/config/config.go @@ -43,6 +43,9 @@ type config struct { // sinkMappings is a list of sink mapping sinkMappings []SinkMapping + + // channelTypeMappings is a list of channel type mapping + channelTypeMappings []ChannelTypeMapping } // ConfigFile returns the config file which is either the default XDG conform @@ -84,6 +87,10 @@ func (c *config) SinkMappings() []SinkMapping { return c.sinkMappings } +func (c *config) ChannelTypeMappings() []ChannelTypeMapping { + return c.channelTypeMappings +} + // Config used for flag binding var globalConfig = config{} @@ -143,6 +150,12 @@ func BootstrapConfig() error { // Deserialize sink mappings if configured err = parseSinkMappings() + if err != nil { + return err + } + + // Deserialize channel type mappings if configured + err = parseChannelTypeMappings() return err } @@ -243,6 +256,18 @@ func parseSinkMappings() error { return nil } +// parse channel type mappings and store them in the global configuration +func parseChannelTypeMappings() error { + if viper.IsSet(keyChannelTypeMappings) { + err := viper.UnmarshalKey(keyChannelTypeMappings, &globalConfig.channelTypeMappings) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error while parsing channel type mappings in configuration file %s", + viper.ConfigFileUsed())) + } + } + return nil +} + // Prepare the default config file for the usage message func defaultConfigFileForUsageMessage() string { if runtime.GOOS == "windows" { diff --git a/pkg/kn/config/config_test.go b/pkg/kn/config/config_test.go index 53e5037c44..a0e7badc3f 100644 --- a/pkg/kn/config/config_test.go +++ b/pkg/kn/config/config_test.go @@ -37,6 +37,11 @@ eventing: resource: services group: core version: v1 + channel-type-mappings: + - alias: kafka + kind: KafkaChannel + group: messaging.knative.dev + version: v1alpha1 ` configFile, cleanup := setupConfig(t, configYaml) @@ -55,6 +60,13 @@ eventing: Group: "core", Version: "v1", }) + assert.Equal(t, len(GlobalConfig.ChannelTypeMappings()), 1) + assert.DeepEqual(t, (GlobalConfig.ChannelTypeMappings())[0], ChannelTypeMapping{ + Alias: "kafka", + Kind: "KafkaChannel", + Group: "messaging.knative.dev", + Version: "v1alpha1", + }) } func TestBootstrapConfigWithoutConfigFile(t *testing.T) { diff --git a/pkg/kn/config/testing.go b/pkg/kn/config/testing.go index 0ea521a77b..f7b2a05825 100644 --- a/pkg/kn/config/testing.go +++ b/pkg/kn/config/testing.go @@ -22,12 +22,14 @@ type TestConfig struct { TestConfigFile string TestLookupPluginsInPath bool TestSinkMappings []SinkMapping + TestChannelTypeMappings []ChannelTypeMapping } // Ensure that TestConfig implements the configuration interface var _ Config = &TestConfig{} -func (t TestConfig) PluginsDir() string { return t.TestPluginsDir } -func (t TestConfig) ConfigFile() string { return t.TestConfigFile } -func (t TestConfig) LookupPluginsInPath() bool { return t.TestLookupPluginsInPath } -func (t TestConfig) SinkMappings() []SinkMapping { return t.TestSinkMappings } +func (t TestConfig) PluginsDir() string { return t.TestPluginsDir } +func (t TestConfig) ConfigFile() string { return t.TestConfigFile } +func (t TestConfig) LookupPluginsInPath() bool { return t.TestLookupPluginsInPath } +func (t TestConfig) SinkMappings() []SinkMapping { return t.TestSinkMappings } +func (t TestConfig) ChannelTypeMappings() []ChannelTypeMapping { return t.TestChannelTypeMappings } diff --git a/pkg/kn/config/testing_test.go b/pkg/kn/config/testing_test.go index 5acf22b149..d18441aedf 100644 --- a/pkg/kn/config/testing_test.go +++ b/pkg/kn/config/testing_test.go @@ -28,10 +28,12 @@ func TestTestConfig(t *testing.T) { TestConfigFile: "configFile", TestLookupPluginsInPath: true, TestSinkMappings: nil, + TestChannelTypeMappings: nil, } assert.Equal(t, cfg.PluginsDir(), "pluginsDir") assert.Equal(t, cfg.ConfigFile(), "configFile") assert.Assert(t, cfg.LookupPluginsInPath()) assert.Assert(t, cfg.SinkMappings() == nil) + assert.Assert(t, cfg.ChannelTypeMappings() == nil) } diff --git a/pkg/kn/config/types.go b/pkg/kn/config/types.go index 281e1f8f85..0253ff7107 100644 --- a/pkg/kn/config/types.go +++ b/pkg/kn/config/types.go @@ -31,6 +31,9 @@ type Config interface { // SinkMappings returns additional mappings for sink prefixes to resources SinkMappings() []SinkMapping + + // ChannelTypeMappings returns additional mappings for channel type aliases + ChannelTypeMappings() []ChannelTypeMapping } // SinkMappings is the struct of sink prefix config in kn config @@ -49,11 +52,28 @@ type SinkMapping struct { Version string } +// ChannelTypeMapping is the struct of ChannelType alias config in kn config +type ChannelTypeMapping struct { + + // Alias is the mapping alias (like "kafka") + Alias string + + // Kind is the name for the mapped resource kind (like "KafkaChannel") + Kind string + + // Group is the API group for the mapped resource kind (like "messaging.knative.dev") + Group string + + // Version is the API version for the mapped resource kind (like "v1alpha1") + Version string +} + // config Keys for looking up in viper const ( keyPluginsDirectory = "plugins.directory" keyPluginsLookupInPath = "plugins.path-lookup" keySinkMappings = "eventing.sink-mappings" + keyChannelTypeMappings = "eventing.channel-type-mappings" ) // legacy config keys, deprecated diff --git a/pkg/kn/flags/channel_types.go b/pkg/kn/flags/channel_types.go new file mode 100644 index 0000000000..4a5c726a41 --- /dev/null +++ b/pkg/kn/flags/channel_types.go @@ -0,0 +1,81 @@ +// Copyright © 2020 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 flags + +import ( + "fmt" + "strings" + + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/runtime/schema" + + "knative.dev/client/pkg/kn/config" +) + +type ChannelTypeFlags struct { + ctype string +} + +func (i *ChannelTypeFlags) Add(f *pflag.FlagSet) { + f.StringVar(&i.ctype, + "type", + "", + "Override channel type to create, in the format '--type Group:Version:Kind'. "+ + "If flag is not specified, it uses default messaging layer settings for channel type, cluster wide or specific namespace. "+ + "You can configure aliases for channel types in kn config and refer the aliases with this flag. "+ + "You can also refer inbuilt channel type InMemoryChannel using an alias 'imc' like '--type imc'. "+ + "Examples: '--type messaging.knative.dev:v1alpha1:KafkaChannel' for specifying explicit Group:Version:Kind.") + + for _, p := range config.GlobalConfig.ChannelTypeMappings() { + //user configration might override the default configuration + ctypeMappings[p.Alias] = schema.GroupVersionKind{ + Kind: p.Kind, + Group: p.Group, + Version: p.Version, + } + } +} + +// ctypeMappings maps aliases used for channel types to their GroupVersionKind +var ctypeMappings = map[string]schema.GroupVersionKind{ + "imcv1beta1": { + Group: "messaging.knative.dev", + Version: "v1beta1", + Kind: "InMemoryChannel", + }, + "imc": { + Group: "messaging.knative.dev", + Version: "v1", + Kind: "InMemoryChannel", + }, +} + +func (i *ChannelTypeFlags) Parse() (*schema.GroupVersionKind, error) { + parts := strings.Split(i.ctype, ":") + switch len(parts) { + case 1: + if typ, ok := ctypeMappings[i.ctype]; ok { + return &typ, nil + } + return nil, fmt.Errorf("Error: unknown channel type alias: '%s'", i.ctype) + case 3: + if parts[0] == "" || parts[1] == "" || parts[2] == "" { + return nil, fmt.Errorf("Error: incorrect value '%s' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", i.ctype) + } + return &schema.GroupVersionKind{Group: parts[0], Version: parts[1], Kind: parts[2]}, nil + default: + return nil, fmt.Errorf("Error: incorrect value '%s' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", i.ctype) + } +} diff --git a/pkg/kn/flags/channel_types_test.go b/pkg/kn/flags/channel_types_test.go new file mode 100644 index 0000000000..443901949e --- /dev/null +++ b/pkg/kn/flags/channel_types_test.go @@ -0,0 +1,84 @@ +// Copyright 2020 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 flags + +import ( + "testing" + + "github.com/spf13/pflag" + "gotest.tools/assert" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type channelTypeFlagsTestCase struct { + name string + arg string + expectedGVK *schema.GroupVersionKind + expectedErrText string +} + +func TestChannelTypesFlags(t *testing.T) { + cases := []*channelTypeFlagsTestCase{ + { + "inbuilt alias 'imcv1beta1' case", + "imcv1beta1", + &schema.GroupVersionKind{Group: "messaging.knative.dev", Kind: "InMemoryChannel", Version: "v1beta1"}, + "", + }, + { + "inbuilt alias 'imc' case", + "imc", + &schema.GroupVersionKind{Group: "messaging.knative.dev", Kind: "InMemoryChannel", Version: "v1"}, + "", + }, + { + "explicit GVK case", + "messaging.knative.dev:v1alpha1:KafkaChannel", + &schema.GroupVersionKind{Group: "messaging.knative.dev", Kind: "KafkaChannel", Version: "v1alpha1"}, + "", + }, + { + "error case unknown alias", + "natss", + nil, + "Error: unknown channel type alias: 'natss'", + }, + { + "error case incorrect gvk format, missing version", + "foo::bar", + nil, + "Error: incorrect value 'foo::bar' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", + }, + { + "error case incorrect gvk format, additional field", + "foo:bar:baz:bat", + nil, + "Error: incorrect value 'foo:bar:baz:bat' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", + }, + } + + for _, c := range cases { + f := &ChannelTypeFlags{} + flagset := &pflag.FlagSet{} + f.Add(flagset) + flagset.Set("type", c.arg) + gvk, err := f.Parse() + if c.expectedErrText != "" { + assert.Equal(t, err.Error(), c.expectedErrText) + } else { + assert.Equal(t, *gvk, *c.expectedGVK) + } + } +} diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go index 12ddef6780..59b0b32b53 100644 --- a/pkg/kn/root/root.go +++ b/pkg/kn/root/root.go @@ -27,6 +27,7 @@ import ( "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands/broker" + "knative.dev/client/pkg/kn/commands/channel" "knative.dev/client/pkg/kn/commands/completion" "knative.dev/client/pkg/kn/commands/options" "knative.dev/client/pkg/kn/commands/plugin" @@ -93,6 +94,7 @@ func NewRootCommand(helpFuncs *template.FuncMap) (*cobra.Command, error) { source.NewSourceCommand(p), broker.NewBrokerCommand(p), trigger.NewTriggerCommand(p), + channel.NewChannelCommand(p), }, }, { diff --git a/pkg/messaging/v1beta1/channels_client.go b/pkg/messaging/v1beta1/channels_client.go new file mode 100644 index 0000000000..1de3f7190d --- /dev/null +++ b/pkg/messaging/v1beta1/channels_client.go @@ -0,0 +1,147 @@ +// Copyright © 2020 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/eventing/pkg/apis/messaging/v1beta1" + clientv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" + + knerrors "knative.dev/client/pkg/errors" +) + +// KnChannelsClient for interacting with Channels +type KnChannelsClient interface { + + // GetChannel returns a Channel by its name + GetChannel(name string) (*v1beta1.Channel, error) + + // CreteChannel creates a Channel with given spec + CreateChannel(channel *v1beta1.Channel) error + + // DeleteChannel deletes a Channel by its name + DeleteChannel(name string) error + + // ListChannel lists all Channels + ListChannel() (*v1beta1.ChannelList, error) + + // Namespace returns the namespace for this channel client + Namespace() string +} + +// channelsClient struct holds the client interface and namespace +type channelsClient struct { + client clientv1beta1.ChannelInterface + namespace string +} + +// newKnChannelsClient returns kn channels client +func newKnChannelsClient(client clientv1beta1.ChannelInterface, namespace string) KnChannelsClient { + return &channelsClient{ + client: client, + namespace: namespace, + } +} + +// Get the namespace for which this client is created +func (c *channelsClient) Namespace() string { + return c.namespace +} + +// GetChannel gets Channel by its name +func (c *channelsClient) GetChannel(name string) (*v1beta1.Channel, error) { + channel, err := c.client.Get(name, metav1.GetOptions{}) + if err != nil { + return nil, knerrors.GetError(err) + } + err = updateMessagingGVK(channel) + if err != nil { + return nil, err + } + return channel, nil +} + +// CreateChannel creates Channel with given spec +func (c *channelsClient) CreateChannel(channel *v1beta1.Channel) error { + _, err := c.client.Create(channel) + return knerrors.GetError(err) +} + +// DeleteChannel deletes Channel by its name +func (c *channelsClient) DeleteChannel(name string) error { + return knerrors.GetError(c.client.Delete(name, &metav1.DeleteOptions{})) +} + +// ListChannel lists channels in configured namespace +func (c *channelsClient) ListChannel() (*v1beta1.ChannelList, error) { + channelList, err := c.client.List(metav1.ListOptions{}) + if err != nil { + return nil, knerrors.GetError(err) + } + + return updateChannelListGVK(channelList) +} + +func updateChannelListGVK(channelList *v1beta1.ChannelList) (*v1beta1.ChannelList, error) { + channelListNew := channelList.DeepCopy() + err := updateMessagingGVK(channelListNew) + if err != nil { + return nil, err + } + + channelListNew.Items = make([]v1beta1.Channel, len(channelList.Items)) + for idx, channel := range channelList.Items { + channelClone := channel.DeepCopy() + err := updateMessagingGVK(channelClone) + if err != nil { + return nil, err + } + channelListNew.Items[idx] = *channelClone + } + return channelListNew, nil +} + +// ChannelBuilder is for building the Channel object +type ChannelBuilder struct { + channel *v1beta1.Channel +} + +// NewChannelBuilder for building Channel object +func NewChannelBuilder(name string) *ChannelBuilder { + return &ChannelBuilder{channel: &v1beta1.Channel{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + }} +} + +// Type sets the type of the channel to create +func (c *ChannelBuilder) Type(gvk *schema.GroupVersionKind) *ChannelBuilder { + if gvk == nil { + return c + } + + spec := &v1beta1.ChannelTemplateSpec{} + spec.Kind = gvk.Kind + spec.APIVersion = gvk.GroupVersion().String() + c.channel.Spec.ChannelTemplate = spec + return c +} + +// Build returns the Channel object from the builder +func (c *ChannelBuilder) Build() *v1beta1.Channel { + return c.channel +} diff --git a/pkg/messaging/v1beta1/channels_client_mock.go b/pkg/messaging/v1beta1/channels_client_mock.go new file mode 100644 index 0000000000..1f0f2331f8 --- /dev/null +++ b/pkg/messaging/v1beta1/channels_client_mock.go @@ -0,0 +1,108 @@ +// Copyright © 2020 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 v1beta1 + +import ( + "testing" + + "knative.dev/eventing/pkg/apis/messaging/v1beta1" + + "knative.dev/client/pkg/util/mock" +) + +type MockKnChannelsClient struct { + t *testing.T + recorder *ChannelsRecorder + namespace string +} + +// NewMockKnChannelsClient returns a new mock instance which you need to record for +func NewMockKnChannelsClient(t *testing.T, ns ...string) *MockKnChannelsClient { + namespace := "default" + if len(ns) > 0 { + namespace = ns[0] + } + return &MockKnChannelsClient{ + t: t, + recorder: &ChannelsRecorder{mock.NewRecorder(t, namespace)}, + } +} + +// Ensure that the interface is implemented +var _ KnChannelsClient = &MockKnChannelsClient{} + +// recorder for service +type ChannelsRecorder struct { + r *mock.Recorder +} + +// Recorder returns the recorder for registering API calls +func (c *MockKnChannelsClient) Recorder() *ChannelsRecorder { + return c.recorder +} + +// Namespace of this client +func (c *MockKnChannelsClient) Namespace() string { + return c.recorder.r.Namespace() +} + +// CreateChannel records a call for CreateChannel with the expected error +func (sr *ChannelsRecorder) CreateChannel(channels interface{}, err error) { + sr.r.Add("CreateChannel", []interface{}{channels}, []interface{}{err}) +} + +// CreateChannel performs a previously recorded action, failing if non has been registered +func (c *MockKnChannelsClient) CreateChannel(channels *v1beta1.Channel) error { + call := c.recorder.r.VerifyCall("CreateChannel", channels) + return mock.ErrorOrNil(call.Result[0]) +} + +// GetChannel records a call for GetChannel with the expected object or error. Either channels or err should be nil +func (sr *ChannelsRecorder) GetChannel(name interface{}, channels *v1beta1.Channel, err error) { + sr.r.Add("GetChannel", []interface{}{name}, []interface{}{channels, err}) +} + +// GetChannel performs a previously recorded action, failing if non has been registered +func (c *MockKnChannelsClient) GetChannel(name string) (*v1beta1.Channel, error) { + call := c.recorder.r.VerifyCall("GetChannel", name) + return call.Result[0].(*v1beta1.Channel), mock.ErrorOrNil(call.Result[1]) +} + +// DeleteChannel records a call for DeleteChannel with the expected error (nil if none) +func (sr *ChannelsRecorder) DeleteChannel(name interface{}, err error) { + sr.r.Add("DeleteChannel", []interface{}{name}, []interface{}{err}) +} + +// DeleteChannel performs a previously recorded action, failing if non has been registered +func (c *MockKnChannelsClient) DeleteChannel(name string) error { + call := c.recorder.r.VerifyCall("DeleteChannel", name) + return mock.ErrorOrNil(call.Result[0]) +} + +// ListChannel records a call for ListChannel with the expected error (nil if none) +func (sr *ChannelsRecorder) ListChannel(channelsList *v1beta1.ChannelList, err error) { + sr.r.Add("ListChannel", []interface{}{}, []interface{}{channelsList, err}) +} + +// ListChannel performs a previously recorded action, failing if non has been registered +func (c *MockKnChannelsClient) ListChannel() (*v1beta1.ChannelList, error) { + call := c.recorder.r.VerifyCall("ListChannel") + return call.Result[0].(*v1beta1.ChannelList), mock.ErrorOrNil(call.Result[1]) +} + +// Validates validates whether every recorded action has been called +func (sr *ChannelsRecorder) Validate() { + sr.r.CheckThatAllRecordedMethodsHaveBeenCalled() +} diff --git a/pkg/messaging/v1beta1/client.go b/pkg/messaging/v1beta1/client.go new file mode 100644 index 0000000000..196a5bf624 --- /dev/null +++ b/pkg/messaging/v1beta1/client.go @@ -0,0 +1,55 @@ +// Copyright © 2020 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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + clientv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" + + "knative.dev/client/pkg/util" +) + +// KnMessagingClient to Eventing Messaging. All methods are relative to +// the namespace specificied during construction +type KnMessagingClient interface { + // Get the Channels client + ChannelsClient() KnChannelsClient +} + +// messagingClient holds Messaging client interface and namespace +type messagingClient struct { + client clientv1beta1.MessagingV1beta1Interface + namespace string +} + +// NewKnMessagingClient for managing all eventing messaging types +func NewKnMessagingClient(client clientv1beta1.MessagingV1beta1Interface, namespace string) KnMessagingClient { + return &messagingClient{ + client: client, + namespace: namespace, + } +} + +// ChannelsClient for working with Channels +func (c *messagingClient) ChannelsClient() KnChannelsClient { + return newKnChannelsClient(c.client.Channels(c.namespace), c.namespace) +} + +// update GVK of object +func updateMessagingGVK(obj runtime.Object) error { + return util.UpdateGroupVersionKindWithScheme(obj, messagingv1beta1.SchemeGroupVersion, scheme.Scheme) +} diff --git a/test/e2e/channels_test.go b/test/e2e/channels_test.go new file mode 100644 index 0000000000..bebea23eaf --- /dev/null +++ b/test/e2e/channels_test.go @@ -0,0 +1,104 @@ +// Copyright 2020 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. + +// +build e2e +// +build !serving + +package e2e + +import ( + "io/ioutil" + "os" + "testing" + + "gotest.tools/assert" + + "knative.dev/client/lib/test" + "knative.dev/client/pkg/util" +) + +const ( + knChannelTypesConfigContent string = ` +eventing: + channel-type-mappings: + - alias: imcbeta + kind: InMemoryChannel + group: messaging.knative.dev + version: v1beta1` +) + +type channelTypeAliasTestConfig struct { + knConfigDir string + knConfigPath string +} + +func (tc *channelTypeAliasTestConfig) setup() error { + var err error + tc.knConfigDir, err = ioutil.TempDir("", "kn-channel-config") + if err != nil { + return err + } + tc.knConfigPath, err = test.CreateFile("config.yaml", knChannelTypesConfigContent, tc.knConfigDir, test.FileModeReadWrite) + if err != nil { + return err + } + return nil +} + +func (tc *channelTypeAliasTestConfig) teardown() { + os.RemoveAll(tc.knConfigDir) +} + +func TestChannels(t *testing.T) { + t.Parallel() + it, err := test.NewKnTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, it.Teardown()) + }() + + r := test.NewKnRunResultCollector(t, it) + defer r.DumpIfFailed() + + tc := channelTypeAliasTestConfig{} + assert.NilError(t, tc.setup()) + defer tc.teardown() + + t.Log("Create a channel with default messaging layer settings") + test.ChannelCreate(r, "c0") + + t.Log("Create a channel with explicit GVK on the command line") + test.ChannelCreate(r, "c1", "--type", "messaging.knative.dev:v1beta1:InMemoryChannel") + + t.Log("Create a channel with an alias from kn config: ", tc.knConfigPath) + test.ChannelCreate(r, "c2", "--type", "imcbeta", "--config", tc.knConfigPath) + + t.Log("List channels") + listout := test.ChannelList(r) + assert.Check(t, util.ContainsAll(listout, "NAME", "TYPE", "URL", "AGE", "READY", "REASON")) + assert.Check(t, util.ContainsAll(listout, "c0", "c1", "c2")) + + t.Log("List channels in YAML format") + listout = test.ChannelList(r, "-o", "yaml") + assert.Check(t, util.ContainsAllIgnoreCase(listout, "apiVersion", "items", "c0", "c2", "kind", "ChannelList")) + + t.Log("Describe a channel") + descout := test.ChannelDescribe(r, "c0") + assert.Check(t, util.ContainsAllIgnoreCase(descout, "Name", "c0", "Namespace", "Annotations", "Age", "Type", "URL", "Conditions")) + + t.Log("Delete channels") + test.ChannelDelete(r, "c0") + test.ChannelDelete(r, "c1") + test.ChannelDelete(r, "c2") +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.go new file mode 100644 index 0000000000..4538453f83 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ChannelsGetter has a method to return a ChannelInterface. +// A group's client should implement this interface. +type ChannelsGetter interface { + Channels(namespace string) ChannelInterface +} + +// ChannelInterface has methods to work with Channel resources. +type ChannelInterface interface { + Create(*v1beta1.Channel) (*v1beta1.Channel, error) + Update(*v1beta1.Channel) (*v1beta1.Channel, error) + UpdateStatus(*v1beta1.Channel) (*v1beta1.Channel, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.Channel, error) + List(opts v1.ListOptions) (*v1beta1.ChannelList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Channel, err error) + ChannelExpansion +} + +// channels implements ChannelInterface +type channels struct { + client rest.Interface + ns string +} + +// newChannels returns a Channels +func newChannels(c *MessagingV1beta1Client, namespace string) *channels { + return &channels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the channel, and returns the corresponding channel object, and an error if there is any. +func (c *channels) Get(name string, options v1.GetOptions) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Channels that match those selectors. +func (c *channels) List(opts v1.ListOptions) (result *v1beta1.ChannelList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.ChannelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested channels. +func (c *channels) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a channel and creates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Create(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("channels"). + Body(channel). + Do(). + Into(result) + return +} + +// Update takes the representation of a channel and updates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Update(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("channels"). + Name(channel.Name). + Body(channel). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *channels) UpdateStatus(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("channels"). + Name(channel.Name). + SubResource("status"). + Body(channel). + Do(). + Into(result) + return +} + +// Delete takes name of the channel and deletes it. Returns an error if one occurs. +func (c *channels) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("channels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *channels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched channel. +func (c *channels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("channels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/doc.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/doc.go new file mode 100644 index 0000000000..b641cb3730 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1beta1 diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/generated_expansion.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/generated_expansion.go new file mode 100644 index 0000000000..219ca637ac --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/generated_expansion.go @@ -0,0 +1,25 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +type ChannelExpansion interface{} + +type InMemoryChannelExpansion interface{} + +type SubscriptionExpansion interface{} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.go new file mode 100644 index 0000000000..cc3541fe8e --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// InMemoryChannelsGetter has a method to return a InMemoryChannelInterface. +// A group's client should implement this interface. +type InMemoryChannelsGetter interface { + InMemoryChannels(namespace string) InMemoryChannelInterface +} + +// InMemoryChannelInterface has methods to work with InMemoryChannel resources. +type InMemoryChannelInterface interface { + Create(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + Update(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + UpdateStatus(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.InMemoryChannel, error) + List(opts v1.ListOptions) (*v1beta1.InMemoryChannelList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.InMemoryChannel, err error) + InMemoryChannelExpansion +} + +// inMemoryChannels implements InMemoryChannelInterface +type inMemoryChannels struct { + client rest.Interface + ns string +} + +// newInMemoryChannels returns a InMemoryChannels +func newInMemoryChannels(c *MessagingV1beta1Client, namespace string) *inMemoryChannels { + return &inMemoryChannels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the inMemoryChannel, and returns the corresponding inMemoryChannel object, and an error if there is any. +func (c *inMemoryChannels) Get(name string, options v1.GetOptions) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of InMemoryChannels that match those selectors. +func (c *inMemoryChannels) List(opts v1.ListOptions) (result *v1beta1.InMemoryChannelList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.InMemoryChannelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("inmemorychannels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested inMemoryChannels. +func (c *inMemoryChannels) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("inmemorychannels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a inMemoryChannel and creates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *inMemoryChannels) Create(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("inmemorychannels"). + Body(inMemoryChannel). + Do(). + Into(result) + return +} + +// Update takes the representation of a inMemoryChannel and updates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *inMemoryChannels) Update(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(inMemoryChannel.Name). + Body(inMemoryChannel). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *inMemoryChannels) UpdateStatus(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(inMemoryChannel.Name). + SubResource("status"). + Body(inMemoryChannel). + Do(). + Into(result) + return +} + +// Delete takes name of the inMemoryChannel and deletes it. Returns an error if one occurs. +func (c *inMemoryChannels) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *inMemoryChannels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("inmemorychannels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched inMemoryChannel. +func (c *inMemoryChannels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("inmemorychannels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_client.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_client.go new file mode 100644 index 0000000000..f1199efa9e --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_client.go @@ -0,0 +1,99 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + rest "k8s.io/client-go/rest" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type MessagingV1beta1Interface interface { + RESTClient() rest.Interface + ChannelsGetter + InMemoryChannelsGetter + SubscriptionsGetter +} + +// MessagingV1beta1Client is used to interact with features provided by the messaging.knative.dev group. +type MessagingV1beta1Client struct { + restClient rest.Interface +} + +func (c *MessagingV1beta1Client) Channels(namespace string) ChannelInterface { + return newChannels(c, namespace) +} + +func (c *MessagingV1beta1Client) InMemoryChannels(namespace string) InMemoryChannelInterface { + return newInMemoryChannels(c, namespace) +} + +func (c *MessagingV1beta1Client) Subscriptions(namespace string) SubscriptionInterface { + return newSubscriptions(c, namespace) +} + +// NewForConfig creates a new MessagingV1beta1Client for the given config. +func NewForConfig(c *rest.Config) (*MessagingV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &MessagingV1beta1Client{client}, nil +} + +// NewForConfigOrDie creates a new MessagingV1beta1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *MessagingV1beta1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new MessagingV1beta1Client for the given RESTClient. +func New(c rest.Interface) *MessagingV1beta1Client { + return &MessagingV1beta1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *MessagingV1beta1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.go new file mode 100644 index 0000000000..a610b08522 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// SubscriptionsGetter has a method to return a SubscriptionInterface. +// A group's client should implement this interface. +type SubscriptionsGetter interface { + Subscriptions(namespace string) SubscriptionInterface +} + +// SubscriptionInterface has methods to work with Subscription resources. +type SubscriptionInterface interface { + Create(*v1beta1.Subscription) (*v1beta1.Subscription, error) + Update(*v1beta1.Subscription) (*v1beta1.Subscription, error) + UpdateStatus(*v1beta1.Subscription) (*v1beta1.Subscription, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.Subscription, error) + List(opts v1.ListOptions) (*v1beta1.SubscriptionList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Subscription, err error) + SubscriptionExpansion +} + +// subscriptions implements SubscriptionInterface +type subscriptions struct { + client rest.Interface + ns string +} + +// newSubscriptions returns a Subscriptions +func newSubscriptions(c *MessagingV1beta1Client, namespace string) *subscriptions { + return &subscriptions{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the subscription, and returns the corresponding subscription object, and an error if there is any. +func (c *subscriptions) Get(name string, options v1.GetOptions) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Subscriptions that match those selectors. +func (c *subscriptions) List(opts v1.ListOptions) (result *v1beta1.SubscriptionList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.SubscriptionList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested subscriptions. +func (c *subscriptions) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a subscription and creates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Create(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Post(). + Namespace(c.ns). + Resource("subscriptions"). + Body(subscription). + Do(). + Into(result) + return +} + +// Update takes the representation of a subscription and updates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Update(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Put(). + Namespace(c.ns). + Resource("subscriptions"). + Name(subscription.Name). + Body(subscription). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *subscriptions) UpdateStatus(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Put(). + Namespace(c.ns). + Resource("subscriptions"). + Name(subscription.Name). + SubResource("status"). + Body(subscription). + Do(). + Into(result) + return +} + +// Delete takes name of the subscription and deletes it. Returns an error if one occurs. +func (c *subscriptions) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *subscriptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched subscription. +func (c *subscriptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("subscriptions"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e22112483a..3cb3b48806 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -656,6 +656,7 @@ knative.dev/eventing/pkg/apis/sources/v1beta1 knative.dev/eventing/pkg/client/clientset/versioned/scheme knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1 knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake +knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1 knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2 knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha2/fake knative.dev/eventing/pkg/logging