diff --git a/docs/cmd/kn_source.md b/docs/cmd/kn_source.md index 559c972036..60aa5102f5 100644 --- a/docs/cmd/kn_source.md +++ b/docs/cmd/kn_source.md @@ -28,6 +28,7 @@ kn source [flags] * [kn](kn.md) - Knative client * [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source binding](kn_source_binding.md) - Sink binding command group * [kn source cronjob](kn_source_cronjob.md) - CronJob source command group * [kn source list-types](kn_source_list-types.md) - List available source types diff --git a/docs/cmd/kn_source_binding.md b/docs/cmd/kn_source_binding.md new file mode 100644 index 0000000000..e07a93f0f8 --- /dev/null +++ b/docs/cmd/kn_source_binding.md @@ -0,0 +1,35 @@ +## kn source binding + +Sink binding command group + +### Synopsis + +Sink binding command group + +``` +kn source binding [flags] +``` + +### Options + +``` + -h, --help help for binding +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source](kn_source.md) - Event source command group +* [kn source binding create](kn_source_binding_create.md) - Create a sink binding. +* [kn source binding delete](kn_source_binding_delete.md) - Delete a sink binding. +* [kn source binding describe](kn_source_binding_describe.md) - Describe a sink binding. +* [kn source binding list](kn_source_binding_list.md) - List sink bindings. +* [kn source binding update](kn_source_binding_update.md) - Update a sink binding. + diff --git a/docs/cmd/kn_source_binding_create.md b/docs/cmd/kn_source_binding_create.md new file mode 100644 index 0000000000..d4c73913d4 --- /dev/null +++ b/docs/cmd/kn_source_binding_create.md @@ -0,0 +1,42 @@ +## kn source binding create + +Create a sink binding. + +### Synopsis + +Create a sink binding. + +``` +kn source binding create NAME --subject SCHEDULE --sink SINK --ce-override KEY=VALUE [flags] +``` + +### Examples + +``` + + # Create a sink binding which connects a deployment 'myapp' with a Knative service 'mysvc' + kn source binding create my-binding --subject Deployemnt:apps/v1:myapp --sink svc:mysvc +``` + +### Options + +``` + --ce-override stringArray Cloud Event overrides to apply before sending event to sink in the format '--ce-override key=value'. --ce-override can be provide multiple times + -h, --help help for create + -n, --namespace string Specify the namespace to operate in. + -s, --sink string Addressable sink for events + --subject string Subject which emits cloud events. This argument takes format kind:apiVersion:name for named resources or kind:apiVersion:labelKey1=value1,labelKey2=value2 for matching via a label selector +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source binding](kn_source_binding.md) - Sink binding command group + diff --git a/docs/cmd/kn_source_binding_delete.md b/docs/cmd/kn_source_binding_delete.md new file mode 100644 index 0000000000..a21bd8ff98 --- /dev/null +++ b/docs/cmd/kn_source_binding_delete.md @@ -0,0 +1,39 @@ +## kn source binding delete + +Delete a sink binding. + +### Synopsis + +Delete a sink binding. + +``` +kn source binding delete NAME [flags] +``` + +### Examples + +``` + + # Delete a sink binding with name 'my-binding' + kn source binding delete my-binding +``` + +### Options + +``` + -h, --help help for delete + -n, --namespace string Specify the namespace to operate in. +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source binding](kn_source_binding.md) - Sink binding command group + diff --git a/docs/cmd/kn_source_binding_describe.md b/docs/cmd/kn_source_binding_describe.md new file mode 100644 index 0000000000..81376581c8 --- /dev/null +++ b/docs/cmd/kn_source_binding_describe.md @@ -0,0 +1,40 @@ +## kn source binding describe + +Describe a sink binding. + +### Synopsis + +Describe a sink binding. + +``` +kn source binding describe NAME [flags] +``` + +### Examples + +``` + + # Describe a sink binding with name 'mysinkbinding' + kn source binding describe mysinkbinding +``` + +### Options + +``` + -h, --help help for describe + -n, --namespace string Specify the namespace to operate in. + -v, --verbose More output. +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source binding](kn_source_binding.md) - Sink binding command group + diff --git a/docs/cmd/kn_source_binding_list.md b/docs/cmd/kn_source_binding_list.md new file mode 100644 index 0000000000..3ff71b2e48 --- /dev/null +++ b/docs/cmd/kn_source_binding_list.md @@ -0,0 +1,44 @@ +## kn source binding list + +List sink bindings. + +### Synopsis + +List sink bindings. + +``` +kn source binding list [flags] +``` + +### Examples + +``` + + # List all sink binding in YAML format + kn source binding list -o yaml +``` + +### Options + +``` + -A, --all-namespaces If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace. + --allow-missing-template-keys If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true) + -h, --help help for list + -n, --namespace string Specify the namespace to operate in. + --no-headers When using the default output format, don't print headers (default: print headers). + -o, --output string Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file. + --template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source binding](kn_source_binding.md) - Sink binding command group + diff --git a/docs/cmd/kn_source_binding_update.md b/docs/cmd/kn_source_binding_update.md new file mode 100644 index 0000000000..199a5c8260 --- /dev/null +++ b/docs/cmd/kn_source_binding_update.md @@ -0,0 +1,42 @@ +## kn source binding update + +Update a sink binding. + +### Synopsis + +Update a sink binding. + +``` +kn source binding update NAME --subject SCHEDULE --sink SINK --ce-override OVERRIDE [flags] +``` + +### Examples + +``` + + # Update the subject of a sink binding 'my-binding' to a new cronjob with label selector 'app=ping' + kn source binding update my-binding --subject cronjob:batch/v1beta1:app=ping" +``` + +### Options + +``` + --ce-override stringArray Cloud Event overrides to apply before sending event to sink in the format '--ce-override key=value'. --ce-override can be provide multiple times + -h, --help help for update + -n, --namespace string Specify the namespace to operate in. + -s, --sink string Addressable sink for events + --subject string Subject which emits cloud events. This argument takes format kind:apiVersion:name for named resources or kind:apiVersion:labelKey1=value1,labelKey2=value2 for matching via a label selector +``` + +### Options inherited from parent commands + +``` + --config string kn config file (default is $HOME/.kn/config.yaml) + --kubeconfig string kubectl config file (default is $HOME/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn source binding](kn_source_binding.md) - Sink binding command group + diff --git a/docs/cmd/kn_source_cronjob_describe.md b/docs/cmd/kn_source_cronjob_describe.md index fe57faf9fc..241caeca82 100644 --- a/docs/cmd/kn_source_cronjob_describe.md +++ b/docs/cmd/kn_source_cronjob_describe.md @@ -14,8 +14,8 @@ kn source cronjob describe NAME [flags] ``` - # Describe a cronjob source with name 'my-cron-trigger' - kn source cronjob describe my-cron-trigger + # Describe a cronjob source with name 'mycronjob' + kn source cronjob describe mycronjob ``` ### Options diff --git a/pkg/eventing/legacysources/v1alpha1/apiserver_client_test.go b/pkg/eventing/legacysources/v1alpha1/apiserver_client_test.go index 53c98d83d6..ab3cb8df3e 100644 --- a/pkg/eventing/legacysources/v1alpha1/apiserver_client_test.go +++ b/pkg/eventing/legacysources/v1alpha1/apiserver_client_test.go @@ -134,8 +134,9 @@ func newAPIServerSource(name, resource string) *v1alpha1.ApiServerSource { b := NewAPIServerSourceBuilder(name).ServiceAccount("testsa").Mode("Ref") b.Sink(&v1beta1.Destination{ Ref: &v1.ObjectReference{ - Kind: "Service", - Name: "foosvc", + Kind: "Service", + Name: "foosvc", + Namespace: "default", }}) if resource != "" { diff --git a/pkg/eventing/legacysources/v1alpha1/cronjob_client_test.go b/pkg/eventing/legacysources/v1alpha1/cronjob_client_test.go index b5f661c9c5..9cbc3bcf70 100644 --- a/pkg/eventing/legacysources/v1alpha1/cronjob_client_test.go +++ b/pkg/eventing/legacysources/v1alpha1/cronjob_client_test.go @@ -142,8 +142,9 @@ func newCronJobSource(name string, sink string) *v1alpha1.CronJobSource { b.Sink( &v1beta1.Destination{ Ref: &v1.ObjectReference{ - Kind: "Service", - Name: sink, + Kind: "Service", + Name: sink, + Namespace: "default", }, }) } diff --git a/pkg/eventing/v1alpha1/client.go b/pkg/eventing/v1alpha1/client.go index 47437c8d7a..de62a9c5d4 100644 --- a/pkg/eventing/v1alpha1/client.go +++ b/pkg/eventing/v1alpha1/client.go @@ -27,10 +27,6 @@ import ( "knative.dev/client/pkg/util" ) -const ( - nameFieldKey = "metadata.name" -) - // KnEventingClient to Eventing Sources. All methods are relative to the // namespace specified during construction type KnEventingClient interface { diff --git a/pkg/eventing/v1alpha1/client_mock.go b/pkg/eventing/v1alpha1/client_mock.go index 2977abebd5..aaa888d54e 100644 --- a/pkg/eventing/v1alpha1/client_mock.go +++ b/pkg/eventing/v1alpha1/client_mock.go @@ -17,8 +17,9 @@ package v1alpha1 import ( "testing" - "knative.dev/client/pkg/util/mock" "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + + "knative.dev/client/pkg/util/mock" ) // MockKnEventingClient is a combine of test object and recorder diff --git a/pkg/kn/commands/flags/sink.go b/pkg/kn/commands/flags/sink.go index 5aed55f246..5f7e514906 100644 --- a/pkg/kn/commands/flags/sink.go +++ b/pkg/kn/commands/flags/sink.go @@ -81,15 +81,15 @@ func (i *SinkFlags) ResolveSink(knclient kn_dynamic.KnDynamicClient, namespace s return nil, err } - return &duckv1beta1.Destination{ + destination := &duckv1beta1.Destination{ Ref: &v1.ObjectReference{ Kind: obj.GetKind(), APIVersion: obj.GetAPIVersion(), Name: obj.GetName(), Namespace: namespace, }, - }, nil - + } + return destination, nil } // parseSink takes the string given by the user into the prefix and the name of diff --git a/pkg/kn/commands/flags/sink_test.go b/pkg/kn/commands/flags/sink_test.go index 35ea0edee7..d26d9ab1eb 100644 --- a/pkg/kn/commands/flags/sink_test.go +++ b/pkg/kn/commands/flags/sink_test.go @@ -49,20 +49,19 @@ func TestResolve(t *testing.T) { {"svc:mysvc", &duckv1beta1.Destination{ Ref: &v1.ObjectReference{Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1", - Name: "mysvc", - Namespace: "default"}}, ""}, + Namespace: "default", + Name: "mysvc"}}, ""}, {"service:mysvc", &duckv1beta1.Destination{ Ref: &v1.ObjectReference{Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1", - Name: "mysvc", - Namespace: "default"}}, ""}, + Namespace: "default", + Name: "mysvc"}}, ""}, {"svc:absent", nil, "\"absent\" not found"}, {"broker:default", &duckv1beta1.Destination{ Ref: &v1.ObjectReference{Kind: "Broker", APIVersion: "eventing.knative.dev/v1alpha1", - Name: "default", Namespace: "default", - }}, ""}, + Name: "default"}}, ""}, {"http://target.example.com", &duckv1beta1.Destination{ URI: targetExampleCom, }, ""}, diff --git a/pkg/kn/commands/human_readable_flags.go b/pkg/kn/commands/human_readable_flags.go index 811d50ad19..28bc103ee7 100644 --- a/pkg/kn/commands/human_readable_flags.go +++ b/pkg/kn/commands/human_readable_flags.go @@ -67,8 +67,6 @@ func (f *HumanPrintFlags) EnsureWithNamespace() { f.WithNamespace = true } -// Private functions - // conditionsValue returns the True conditions count among total conditions func ConditionsValue(conditions duckv1.Conditions) string { var ok int diff --git a/pkg/kn/commands/source/apiserver/flags.go b/pkg/kn/commands/source/apiserver/flags.go index 2ba9d632e7..98f1cd33f2 100644 --- a/pkg/kn/commands/source/apiserver/flags.go +++ b/pkg/kn/commands/source/apiserver/flags.go @@ -188,6 +188,9 @@ func printSource(source *v1alpha1.ApiServerSource, options hprinters.PrintOption resources = append(resources, fmt.Sprintf("%s:%s:%s", resource.Kind, resource.APIVersion, strconv.FormatBool(resource.Controller))) } + // Not moving to SinkToString() as it references v1beta1.Destination + // This source is going to be moved/removed soon to v1, so no need to move + // it now var sink string if source.Spec.Sink != nil { if source.Spec.Sink.Ref != nil { diff --git a/pkg/kn/commands/source/binding/binding.go b/pkg/kn/commands/source/binding/binding.go new file mode 100644 index 0000000000..827e2bcb7d --- /dev/null +++ b/pkg/kn/commands/source/binding/binding.go @@ -0,0 +1,172 @@ +// 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 binding + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/clientcmd" + "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" + duckv1 "knative.dev/pkg/apis/duck/v1" + duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" + "knative.dev/pkg/tracker" + + "knative.dev/client/pkg/kn/commands" + sources_v1alpha1 "knative.dev/client/pkg/sources/v1alpha1" + "knative.dev/client/pkg/util" +) + +// NewBindingCommand is the root command for all binding related commands +func NewBindingCommand(p *commands.KnParams) *cobra.Command { + bindingCmd := &cobra.Command{ + Use: "binding", + Short: "Sink binding command group", + } + bindingCmd.AddCommand(NewBindingCreateCommand(p)) + bindingCmd.AddCommand(NewBindingUpdateCommand(p)) + bindingCmd.AddCommand(NewBindingDeleteCommand(p)) + bindingCmd.AddCommand(NewBindingListCommand(p)) + bindingCmd.AddCommand(NewBindingDescribeCommand(p)) + return bindingCmd +} + +// This var can be used to inject a factory for fake clients when doing +// tests. +var sinkBindingClientFactory func(config clientcmd.ClientConfig, namespace string) (sources_v1alpha1.KnSinkBindingClient, error) + +func newSinkBindingClient(p *commands.KnParams, cmd *cobra.Command) (sources_v1alpha1.KnSinkBindingClient, error) { + namespace, err := p.GetNamespace(cmd) + if err != nil { + return nil, err + } + + if sinkBindingClientFactory != nil { + config, err := p.GetClientConfig() + if err != nil { + return nil, err + } + return sinkBindingClientFactory(config, namespace) + } + + clientConfig, err := p.RestConfig() + if err != nil { + return nil, err + } + + client, err := v1alpha1.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + return sources_v1alpha1.NewKnSourcesClient(client, namespace).SinkBindingClient(), nil +} + +// Temporary conversions function until we move to duckv1 +func toDuckV1(destination *duckv1beta1.Destination) *duckv1.Destination { + return &duckv1.Destination{ + Ref: destination.Ref, + URI: destination.URI, + } +} + +func toReference(subjectArg string, namespace string) (*tracker.Reference, error) { + parts := strings.SplitN(subjectArg, ":", 3) + if len(parts) < 3 { + return nil, fmt.Errorf("invalid subject argument '%s': not in format kind:api/version:nameOrSelector", subjectArg) + } + kind := parts[0] + gv, err := schema.ParseGroupVersion(parts[1]) + if err != nil { + return nil, err + } + reference := &tracker.Reference{ + APIVersion: gv.String(), + Kind: kind, + Namespace: namespace, + } + if !strings.Contains(parts[2], "=") { + reference.Name = parts[2] + } else { + selector, err := parseSelector(parts[2]) + if err != nil { + return nil, err + } + reference.Selector = &metav1.LabelSelector{MatchLabels: selector} + } + return reference, nil +} + +func parseSelector(labelSelector string) (map[string]string, error) { + selector := map[string]string{} + for _, p := range strings.Split(labelSelector, ",") { + keyValue := strings.SplitN(p, "=", 2) + if len(keyValue) != 2 { + return nil, fmt.Errorf("invalid subject label selector '%s', expected format: key1=value,key2=value", labelSelector) + } + selector[keyValue[0]] = keyValue[1] + } + return selector, nil +} + +// subjectToString converts a reference to a string representation +func subjectToString(ref tracker.Reference) string { + + ret := ref.Kind + ":" + ref.APIVersion + if ref.Name != "" { + return ret + ":" + ref.Name + } + var keyValues []string + selector := ref.Selector + if selector != nil { + for k, v := range selector.MatchLabels { + keyValues = append(keyValues, k+"="+v) + } + return ret + ":" + strings.Join(keyValues, ",") + } + return ret +} + +// sinkToString prepares a sink for list output +// This is kept here until we have moved everything to duckv1 (currently the other sources +// are still on duckv1beta1) +func sinkToString(sink duckv1.Destination) string { + if sink.Ref != nil { + if sink.Ref.Kind == "Service" { + return fmt.Sprintf("svc:%s", sink.Ref.Name) + } else { + return fmt.Sprintf("%s:%s", sink.Ref.Kind, sink.Ref.Name) + } + } + if sink.URI != nil { + return sink.URI.String() + } + return "" +} + +// updateCeOverrides updates the values of the --ce-override flags if given +func updateCeOverrides(bindingFlags bindingUpdateFlags, bindingBuilder *sources_v1alpha1.SinkBindingBuilder) error { + if bindingFlags.ceOverrides != nil { + ceOverrideMap, err := util.MapFromArray(bindingFlags.ceOverrides, "=") + if err != nil { + return err + } + bindingBuilder.AddCloudEventOverrides(ceOverrideMap) + } + return nil +} diff --git a/pkg/kn/commands/source/binding/binding_test.go b/pkg/kn/commands/source/binding/binding_test.go new file mode 100644 index 0000000000..a1d2109ee2 --- /dev/null +++ b/pkg/kn/commands/source/binding/binding_test.go @@ -0,0 +1,108 @@ +// 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 binding + +import ( + "bytes" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/clientcmd" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + v1 "knative.dev/pkg/apis/duck/v1" + + kn_dynamic "knative.dev/client/pkg/dynamic" + "knative.dev/client/pkg/kn/commands" + cl_sources_v1alpha1 "knative.dev/client/pkg/sources/v1alpha1" +) + +// Helper methods +var blankConfig clientcmd.ClientConfig + +// Gvk used in tests +var deploymentGvk = schema.GroupVersionKind{"apps", "v1", "deployment"} + +// TODO: Remove that blankConfig hack for tests in favor of overwriting GetConfig() +// Remove also in service_test.go +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 executeSinkBindingCommand(sinkBindingClient cl_sources_v1alpha1.KnSinkBindingClient, dynamicClient kn_dynamic.KnDynamicClient, args ...string) (string, error) { + knParams := &commands.KnParams{} + knParams.ClientConfig = blankConfig + + output := new(bytes.Buffer) + knParams.Output = output + knParams.NewDynamicClient = func(namespace string) (kn_dynamic.KnDynamicClient, error) { + return dynamicClient, nil + } + + cmd := NewBindingCommand(knParams) + cmd.SetArgs(args) + cmd.SetOutput(output) + + sinkBindingClientFactory = func(config clientcmd.ClientConfig, namespace string) (cl_sources_v1alpha1.KnSinkBindingClient, error) { + return sinkBindingClient, nil + } + defer cleanupSinkBindingClient() + + err := cmd.Execute() + + return output.String(), err +} + +func cleanupSinkBindingClient() { + sinkBindingClientFactory = nil +} + +func createSinkBinding(name, service string, subjectGvk schema.GroupVersionKind, subjectName string, ceOverrides map[string]string) *v1alpha1.SinkBinding { + sink := createServiceSink(service) + builder := cl_sources_v1alpha1.NewSinkBindingBuilder(name). + Namespace("default"). + Sink(&sink). + SubjectGVK(&subjectGvk). + SubjectName(subjectName). + SubjectNamespace("default") + if ceOverrides != nil { + builder.AddCloudEventOverrides(ceOverrides) + } + binding, _ := builder.Build() + return binding +} + +func createServiceSink(service string) v1.Destination { + return v1.Destination{ + Ref: &corev1.ObjectReference{Name: service, Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1", Namespace: "default"}, + } +} diff --git a/pkg/kn/commands/source/binding/create.go b/pkg/kn/commands/source/binding/create.go new file mode 100644 index 0000000000..762ed7e43c --- /dev/null +++ b/pkg/kn/commands/source/binding/create.go @@ -0,0 +1,98 @@ +// 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 binding + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/kn/commands/flags" + v1alpha12 "knative.dev/client/pkg/sources/v1alpha1" +) + +// NewBindingCreateCommand is for creating sink bindings +func NewBindingCreateCommand(p *commands.KnParams) *cobra.Command { + var bindingFlags bindingUpdateFlags + var sinkFlags flags.SinkFlags + + cmd := &cobra.Command{ + Use: "create NAME --subject SCHEDULE --sink SINK --ce-override KEY=VALUE", + Short: "Create a sink binding.", + Example: ` + # Create a sink binding which connects a deployment 'myapp' with a Knative service 'mysvc' + kn source binding create my-binding --subject Deployemnt:apps/v1:myapp --sink svc:mysvc`, + + RunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) != 1 { + return errors.New("requires the name of the sink binding to create as single argument") + + } + name := args[0] + + sinkBindingClient, err := newSinkBindingClient(p, cmd) + if err != nil { + return err + } + + namespace, err := p.GetNamespace(cmd) + if err != nil { + return err + } + dynamicClient, err := p.NewDynamicClient(namespace) + if err != nil { + return err + } + + destination, err := sinkFlags.ResolveSink(dynamicClient, namespace) + if err != nil { + return err + } + + reference, err := toReference(bindingFlags.subject, namespace) + if err != nil { + return err + } + + bindingBuilder := v1alpha12.NewSinkBindingBuilder(name). + Sink(toDuckV1(destination)). + Subject(reference). + Namespace(namespace) + + err = updateCeOverrides(bindingFlags, bindingBuilder) + if err != nil { + return err + } + binding, err := bindingBuilder.Build() + if err != nil { + return err + } + err = sinkBindingClient.CreateSinkBinding(binding) + if err == nil { + fmt.Fprintf(cmd.OutOrStdout(), "Sink binding '%s' created in namespace '%s'.\n", args[0], sinkBindingClient.Namespace()) + } + return err + }, + } + commands.AddNamespaceFlags(cmd.Flags(), false) + bindingFlags.addBindingFlags(cmd) + sinkFlags.Add(cmd) + cmd.MarkFlagRequired("subject") + cmd.MarkFlagRequired("sink") + + return cmd +} diff --git a/pkg/kn/commands/source/binding/create_test.go b/pkg/kn/commands/source/binding/create_test.go new file mode 100644 index 0000000000..d97f2da472 --- /dev/null +++ b/pkg/kn/commands/source/binding/create_test.go @@ -0,0 +1,57 @@ +// 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 binding + +import ( + "testing" + + "gotest.tools/assert" + + dynamic_fake "knative.dev/client/pkg/dynamic/fake" + "knative.dev/client/pkg/sources/v1alpha1" + + "knative.dev/client/pkg/util" +) + +func TestSimpleCreateBinding(t *testing.T) { + mysvc := createService("mysvc") + dynamicClient := dynamic_fake.CreateFakeKnDynamicClient("default", mysvc) + + bindingClient := v1alpha1.NewMockKnSinkBindingClient(t) + bindingRecorder := bindingClient.Recorder() + bindingRecorder.CreateSinkBinding(createSinkBinding("testbinding", "mysvc", deploymentGvk, "mydeploy", map[string]string{"bla": "blub", "foo": "bar"}), nil) + + out, err := executeSinkBindingCommand(bindingClient, dynamicClient, "create", "testbinding", "--sink", "svc:mysvc", "--subject", "deployment:apps/v1:mydeploy", "--ce-override", "bla=blub", "--ce-override", "foo=bar") + assert.NilError(t, err, "Source should have been created") + util.ContainsAll(out, "created", "default", "testbinding") + + bindingRecorder.Validate() +} + +func TestNoSinkError(t *testing.T) { + bindingClient := v1alpha1.NewMockKnSinkBindingClient(t) + dynamicClient := dynamic_fake.CreateFakeKnDynamicClient("default") + + _, err := executeSinkBindingCommand(bindingClient, dynamicClient, "create", "testbinding", "--sink", "svc:mysvc", "--subject", "deployment:apps/v1:app=myapp") + assert.ErrorContains(t, err, "mysvc") + assert.ErrorContains(t, err, "not found") +} + +func TestNoSinkGivenError(t *testing.T) { + out, err := executeSinkBindingCommand(nil, nil, "create", "testbinding", "--subject", "deployment:apps/v1:app=myapp") + assert.ErrorContains(t, err, "sink") + assert.ErrorContains(t, err, "required") + assert.Assert(t, util.ContainsAll(out, "not set", "required")) +} diff --git a/pkg/kn/commands/source/binding/delete.go b/pkg/kn/commands/source/binding/delete.go new file mode 100644 index 0000000000..e4ee97ffd0 --- /dev/null +++ b/pkg/kn/commands/source/binding/delete.go @@ -0,0 +1,55 @@ +// 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 binding + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + "knative.dev/client/pkg/kn/commands" +) + +// NewBindingDeleteCommand is for deleting a sink binding +func NewBindingDeleteCommand(p *commands.KnParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete NAME", + Short: "Delete a sink binding.", + Example: ` + # Delete a sink binding with name 'my-binding' + kn source binding delete my-binding`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("requires the name of the sink binding to delete as single argument") + } + name := args[0] + + bindingClient, err := newSinkBindingClient(p, cmd) + if err != nil { + return err + } + + err = bindingClient.DeleteSinkBinding(name) + if err != nil { + return err + } + + fmt.Fprintf(cmd.OutOrStdout(), "Sink binding '%s' deleted in namespace '%s'.\n", name, bindingClient.Namespace()) + return nil + }, + } + commands.AddNamespaceFlags(cmd.Flags(), false) + return cmd +} diff --git a/pkg/kn/commands/source/binding/delete_test.go b/pkg/kn/commands/source/binding/delete_test.go new file mode 100644 index 0000000000..2bd6acc157 --- /dev/null +++ b/pkg/kn/commands/source/binding/delete_test.go @@ -0,0 +1,53 @@ +// 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 binding + +import ( + "errors" + "testing" + + "gotest.tools/assert" + + "knative.dev/client/pkg/sources/v1alpha1" + "knative.dev/client/pkg/util" +) + +func TestSimpleDelete(t *testing.T) { + + bindingClient := v1alpha1.NewMockKnSinkBindingClient(t, "mynamespace") + + bindingRecorder := bindingClient.Recorder() + bindingRecorder.DeleteSinkBinding("mybinding", nil) + + out, err := executeSinkBindingCommand(bindingClient, nil, "delete", "mybinding") + assert.NilError(t, err) + util.ContainsAll(out, "deleted", "mynamespace", "mybinding", "sink binding") + + bindingRecorder.Validate() +} + +func TestDeleteWithError(t *testing.T) { + + bindingClient := v1alpha1.NewMockKnSinkBindingClient(t, "mynamespace") + + bindingRecorder := bindingClient.Recorder() + bindingRecorder.DeleteSinkBinding("mybinding", errors.New("no such sink binding mybinding")) + + out, err := executeSinkBindingCommand(bindingClient, nil, "delete", "mybinding") + assert.ErrorContains(t, err, "mybinding") + util.ContainsAll(out, "no such", "mybinding") + + bindingRecorder.Validate() +} diff --git a/pkg/kn/commands/source/binding/describe.go b/pkg/kn/commands/source/binding/describe.go new file mode 100644 index 0000000000..46b5016b2d --- /dev/null +++ b/pkg/kn/commands/source/binding/describe.go @@ -0,0 +1,146 @@ +// 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 binding + +import ( + "errors" + "fmt" + "sort" + + "github.com/spf13/cobra" + v1alpha12 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/tracker" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/printers" +) + +// NewBindingDescribeCommand returns a new command for describe a sink binding object +func NewBindingDescribeCommand(p *commands.KnParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "describe NAME", + Short: "Describe a sink binding.", + Example: ` + # Describe a sink binding with name 'mysinkbinding' + kn source binding describe mysinkbinding`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("'kn source binding describe' requires the name of the source as single argument") + } + name := args[0] + + bindingClient, err := newSinkBindingClient(p, cmd) + if err != nil { + return err + } + + binding, err := bindingClient.GetSinkBinding(name) + if err != nil { + return err + } + + out := cmd.OutOrStdout() + dw := printers.NewPrefixWriter(out) + + printDetails, err := cmd.Flags().GetBool("verbose") + if err != nil { + return err + } + + writeSinkBinding(dw, binding, printDetails) + dw.WriteLine() + if err := dw.Flush(); err != nil { + return err + } + + // Condition info + commands.WriteConditions(dw, binding.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.") + + return cmd +} + +func writeSinkBinding(dw printers.PrefixWriter, binding *v1alpha12.SinkBinding, printDetails bool) { + commands.WriteMetadata(dw, &binding.ObjectMeta, printDetails) + writeSubject(dw, binding.Namespace, &binding.Spec.Subject) + writeSink(dw, binding.Namespace, &binding.Spec.Sink) + if binding.Spec.CloudEventOverrides != nil && binding.Spec.CloudEventOverrides.Extensions != nil { + writeCeOverrides(dw, binding.Spec.CloudEventOverrides.Extensions) + } +} + +func writeSink(dw printers.PrefixWriter, namespace string, sink *duckv1.Destination) { + subWriter := dw.WriteAttribute("Sink", "") + if sink.Ref.Namespace != "" && sink.Ref.Namespace != namespace { + subWriter.WriteAttribute("Namespace", sink.Ref.Namespace) + } + subWriter.WriteAttribute("Name", sink.Ref.Name) + ref := sink.Ref + if ref != nil { + subWriter.WriteAttribute("Resource", fmt.Sprintf("%s (%s)", sink.Ref.Kind, sink.Ref.APIVersion)) + } + uri := sink.URI + if uri != nil { + subWriter.WriteAttribute("URI", uri.String()) + } +} + +func writeCeOverrides(dw printers.PrefixWriter, ceOverrides map[string]string) { + subDw := dw.WriteAttribute("CloudEvent Overrides", "") + var keys []string + for k := range ceOverrides { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + subDw.WriteAttribute(k, ceOverrides[k]) + } +} + +func writeSubject(dw printers.PrefixWriter, namespace string, subject *tracker.Reference) { + subjectDw := dw.WriteAttribute("Subject", "") + if subject.Namespace != "" && subject.Namespace != namespace { + subjectDw.WriteAttribute("Namespace", subject.Namespace) + } + if subject.Name != "" { + subjectDw.WriteAttribute("Name", subject.Name) + } + subjectDw.WriteAttribute("Resource", fmt.Sprintf("%s (%s)", subject.Kind, subject.APIVersion)) + if subject.Selector != nil { + matchDw := subjectDw.WriteAttribute("Selector", "") + selector := subject.Selector + if len(selector.MatchLabels) > 0 { + var lKeys []string + for k := range selector.MatchLabels { + lKeys = append(lKeys, k) + } + sort.Strings(lKeys) + for _, k := range lKeys { + matchDw.WriteAttribute(k, selector.MatchLabels[k]) + } + } + // TOOD: Print out selector.MatchExpressions + } +} diff --git a/pkg/kn/commands/source/binding/describe_test.go b/pkg/kn/commands/source/binding/describe_test.go new file mode 100644 index 0000000000..bae5cd2d11 --- /dev/null +++ b/pkg/kn/commands/source/binding/describe_test.go @@ -0,0 +1,113 @@ +// 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 binding + +import ( + "errors" + "strings" + "testing" + + "gotest.tools/assert" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1alpha14 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/apis/duck/v1alpha1" + "knative.dev/pkg/tracker" + + v1alpha13 "knative.dev/client/pkg/sources/v1alpha1" + "knative.dev/client/pkg/util" +) + +func TestSimpleDescribeWitName(t *testing.T) { + bindingClient := v1alpha13.NewMockKnSinkBindingClient(t, "mynamespace") + + bindingRecorder := bindingClient.Recorder() + bindingRecorder.GetSinkBinding("mybinding", getSinkBindingSource("myapp", map[string]string{"foo": "bar"}), nil) + + out, err := executeSinkBindingCommand(bindingClient, nil, "describe", "mybinding") + assert.NilError(t, err) + util.ContainsAll(out, "mybinding", "myapp", "Deployment", "app/v1", "mynamespace", "mysvc", "foo", "bar") + + bindingRecorder.Validate() +} + +func TestSimpleDescribeWithSelector(t *testing.T) { + bindingClient := v1alpha13.NewMockKnSinkBindingClient(t, "mynamespace") + + bindingRecorder := bindingClient.Recorder() + bindingRecorder.GetSinkBinding("mybinding", getSinkBindingSource("app=myapp,type=test", nil), nil) + + out, err := executeSinkBindingCommand(bindingClient, nil, "describe", "mybinding") + assert.NilError(t, err) + util.ContainsAll(out, "mybinding", "app:", "myapp", "type:", "test", "Deployment", "app/v1", "mynamespace", "mysvc") + + bindingRecorder.Validate() +} + +func TestDescribeError(t *testing.T) { + bindingClient := v1alpha13.NewMockKnSinkBindingClient(t, "mynamespace") + + bindingRecorder := bindingClient.Recorder() + bindingRecorder.GetSinkBinding("mybinding", nil, errors.New("no sink binding mybinding found")) + + out, err := executeSinkBindingCommand(bindingClient, nil, "describe", "mybinding") + assert.ErrorContains(t, err, "mybinding") + util.ContainsAll(out, "mybinding") + + bindingRecorder.Validate() +} + +func getSinkBindingSource(nameOrSelector string, ceOverrides map[string]string) *v1alpha14.SinkBinding { + binding := &v1alpha14.SinkBinding{ + TypeMeta: v1.TypeMeta{}, + ObjectMeta: v1.ObjectMeta{ + Name: "mysinkbinding", + }, + Spec: v1alpha14.SinkBindingSpec{ + SourceSpec: duckv1.SourceSpec{ + Sink: duckv1.Destination{ + Ref: &corev1.ObjectReference{ + Kind: "Service", + Namespace: "myservicenamespace", + Name: "mysvc", + }, + }, + }, + BindingSpec: v1alpha1.BindingSpec{ + Subject: tracker.Reference{ + APIVersion: "apps/v1", + Kind: "Deployment", + Namespace: "mynamespace", + }, + }, + }, + Status: v1alpha14.SinkBindingStatus{}, + } + + if strings.Contains(nameOrSelector, "=") { + selector, _ := parseSelector(nameOrSelector) + binding.Spec.Subject.Selector = &v1.LabelSelector{ + MatchLabels: selector, + } + } else { + binding.Spec.Subject.Name = nameOrSelector + } + + if ceOverrides != nil { + binding.Spec.CloudEventOverrides = &duckv1.CloudEventOverrides{Extensions: ceOverrides} + } + return binding +} diff --git a/pkg/kn/commands/source/binding/flags.go b/pkg/kn/commands/source/binding/flags.go new file mode 100644 index 0000000000..12ef776e7b --- /dev/null +++ b/pkg/kn/commands/source/binding/flags.go @@ -0,0 +1,84 @@ +// 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 binding + +import ( + "github.com/spf13/cobra" + 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" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +type bindingUpdateFlags struct { + subject string + ceOverrides []string +} + +func (b *bindingUpdateFlags) addBindingFlags(cmd *cobra.Command) { + cmd.Flags().StringVar(&b.subject, "subject", "", "Subject which emits cloud events. This argument takes format kind:apiVersion:name for named resources or kind:apiVersion:labelKey1=value1,labelKey2=value2 for matching via a label selector") + cmd.Flags().StringArrayVar(&b.ceOverrides, "ce-override", nil, "Cloud Event overrides to apply before sending event to sink in the format '--ce-override key=value'. --ce-override can be provide multiple times") +} + +func BindingListHandlers(h hprinters.PrintHandler) { + sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{ + {Name: "Namespace", Type: "string", Description: "Namespace of the sink binding", Priority: 0}, + {Name: "Name", Type: "string", Description: "Name of sink binding", Priority: 1}, + {Name: "Subject", Type: "string", Description: "Subject part of binding", Priority: 1}, + {Name: "Sink", Type: "string", Description: "Sink part of binding", Priority: 1}, + {Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1}, + {Name: "Ready", Type: "string", Description: "Ready state of the sink binding", Priority: 1}, + {Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1}, + } + h.TableHandler(sourceColumnDefinitions, printSinkBinding) + h.TableHandler(sourceColumnDefinitions, printSinkBindingList) +} + +// printSinkBinding populates a single row of source sink binding list table +func printSinkBinding(binding *v1alpha1.SinkBinding, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { + row := metav1beta1.TableRow{ + Object: runtime.RawExtension{Object: binding}, + } + + name := binding.Name + subject := subjectToString(binding.Spec.Subject) + sink := sinkToString(binding.Spec.Sink) + conditions := commands.ConditionsValue(binding.Status.Conditions) + ready := commands.ReadyCondition(binding.Status.Conditions) + reason := commands.NonReadyConditionReason(binding.Status.Conditions) + + if options.AllNamespaces { + row.Cells = append(row.Cells, binding.Namespace) + } + + row.Cells = append(row.Cells, name, subject, sink, conditions, ready, reason) + return []metav1beta1.TableRow{row}, nil +} + +func printSinkBindingList(sinkBindingList *v1alpha1.SinkBindingList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) { + + rows := make([]metav1beta1.TableRow, 0, len(sinkBindingList.Items)) + for _, binding := range sinkBindingList.Items { + r, err := printSinkBinding(&binding, options) + if err != nil { + return nil, err + } + rows = append(rows, r...) + } + return rows, nil +} diff --git a/pkg/kn/commands/source/binding/list.go b/pkg/kn/commands/source/binding/list.go new file mode 100644 index 0000000000..c11600fffb --- /dev/null +++ b/pkg/kn/commands/source/binding/list.go @@ -0,0 +1,74 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package binding + +import ( + "fmt" + + "github.com/spf13/cobra" + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/kn/commands/flags" +) + +// NewBindingListCommand is for listing sink bindings +func NewBindingListCommand(p *commands.KnParams) *cobra.Command { + listFlags := flags.NewListPrintFlags(BindingListHandlers) + + cmd := &cobra.Command{ + Use: "list", + Short: "List sink bindings.", + Example: ` + # List all sink binding in YAML format + kn source binding list -o yaml`, + + RunE: func(cmd *cobra.Command, args []string) (err error) { + // TODO: filter list by given source name + + bindingClient, err := newSinkBindingClient(p, cmd) + if err != nil { + return err + } + + sourceList, err := bindingClient.ListSinkBindings() + if err != nil { + return err + } + + if len(sourceList.Items) == 0 { + fmt.Fprintf(cmd.OutOrStdout(), "No sink binding found.\n") + return nil + } + + if bindingClient.Namespace() == "" { + listFlags.EnsureWithNamespace() + } + + printer, err := listFlags.ToPrinter() + if err != nil { + return nil + } + + err = printer.PrintObj(sourceList, cmd.OutOrStdout()) + if err != nil { + return err + } + + return nil + }, + } + commands.AddNamespaceFlags(cmd.Flags(), true) + listFlags.AddFlags(cmd) + return cmd +} diff --git a/pkg/kn/commands/source/binding/list_test.go b/pkg/kn/commands/source/binding/list_test.go new file mode 100644 index 0000000000..a8415eac24 --- /dev/null +++ b/pkg/kn/commands/source/binding/list_test.go @@ -0,0 +1,60 @@ +// 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 binding + +import ( + "testing" + + "gotest.tools/assert" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + + client_sources_v1alpha1 "knative.dev/client/pkg/sources/v1alpha1" + "knative.dev/client/pkg/util" +) + +func TestListSimple(t *testing.T) { + bindingClient := client_sources_v1alpha1.NewMockKnSinkBindingClient(t) + + bindingRecorder := bindingClient.Recorder() + binding := createSinkBinding("testbinding", "mysvc", deploymentGvk, "mydeploy", nil) + bindingList := v1alpha1.SinkBindingList{ + Items: []v1alpha1.SinkBinding{ + *binding, + }, + } + bindingRecorder.ListSinkBindings(&bindingList, nil) + + out, err := executeSinkBindingCommand(bindingClient, nil, "list") + assert.NilError(t, err, "Sources should be listed") + util.ContainsAll(out, "NAME", "SUBJECT", "SINK", "CONDITIONS", "READY", "REASON") + util.ContainsAll(out, "testbinding", "deployment:apps/v1:mydeploy", "mysvc") + + bindingRecorder.Validate() +} + +func TestListEmpty(t *testing.T) { + bindingClient := client_sources_v1alpha1.NewMockKnSinkBindingClient(t) + + bindingRecorder := bindingClient.Recorder() + bindingList := v1alpha1.SinkBindingList{} + bindingRecorder.ListSinkBindings(&bindingList, nil) + + out, err := executeSinkBindingCommand(bindingClient, nil, "list") + assert.NilError(t, err, "Sources should be listed") + util.ContainsNone(out, "NAME", "SUBJECT", "SINK", "CONDITIONS", "READY", "REASON") + util.ContainsAll(out, "No", "sink binding", "found") + + bindingRecorder.Validate() +} diff --git a/pkg/kn/commands/source/binding/update.go b/pkg/kn/commands/source/binding/update.go new file mode 100644 index 0000000000..8b670fe5d8 --- /dev/null +++ b/pkg/kn/commands/source/binding/update.go @@ -0,0 +1,101 @@ +// 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 binding + +import ( + "errors" + "fmt" + + "github.com/spf13/cobra" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/kn/commands/flags" + v1alpha12 "knative.dev/client/pkg/sources/v1alpha1" +) + +// NewBindingUpdateCommand prepares the command for a sink binding update +func NewBindingUpdateCommand(p *commands.KnParams) *cobra.Command { + var bindingFlags bindingUpdateFlags + var sinkFlags flags.SinkFlags + + cmd := &cobra.Command{ + Use: "update NAME --subject SCHEDULE --sink SINK --ce-override OVERRIDE", + Short: "Update a sink binding.", + Example: ` + # Update the subject of a sink binding 'my-binding' to a new cronjob with label selector 'app=ping' + kn source binding update my-binding --subject cronjob:batch/v1beta1:app=ping"`, + + RunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) != 1 { + return errors.New("requires the name of the sink binding to update as single argument") + } + name := args[0] + + sinkBindingClient, err := newSinkBindingClient(p, cmd) + if err != nil { + return err + } + + namespace, err := p.GetNamespace(cmd) + if err != nil { + return err + } + dynamicClient, err := p.NewDynamicClient(namespace) + if err != nil { + return err + } + + source, err := sinkBindingClient.GetSinkBinding(name) + if err != nil { + return err + } + + b := v1alpha12.NewSinkBindingBuilderFromExisting(source) + if cmd.Flags().Changed("sink") { + destination, err := sinkFlags.ResolveSink(dynamicClient, namespace) + if err != nil { + return err + } + b.Sink(toDuckV1(destination)) + } + if cmd.Flags().Changed("subject") { + reference, err := toReference(bindingFlags.subject, namespace) + if err != nil { + return err + } + b.Subject(reference) + } + err = updateCeOverrides(bindingFlags, b) + if err != nil { + return err + } + + binding, err := b.Build() + if err != nil { + return err + } + err = sinkBindingClient.UpdateSinkBinding(binding) + if err == nil { + fmt.Fprintf(cmd.OutOrStdout(), "Sink binding '%s' updated in namespace '%s'.\n", name, sinkBindingClient.Namespace()) + } + return err + }, + } + commands.AddNamespaceFlags(cmd.Flags(), false) + bindingFlags.addBindingFlags(cmd) + sinkFlags.Add(cmd) + + return cmd +} diff --git a/pkg/kn/commands/source/binding/update_test.go b/pkg/kn/commands/source/binding/update_test.go new file mode 100644 index 0000000000..a4932a46c8 --- /dev/null +++ b/pkg/kn/commands/source/binding/update_test.go @@ -0,0 +1,68 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package binding + +import ( + "errors" + "testing" + + "gotest.tools/assert" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" + + dynamic_fake "knative.dev/client/pkg/dynamic/fake" + v1alpha13 "knative.dev/client/pkg/sources/v1alpha1" + "knative.dev/client/pkg/util" +) + +func TestSimpleUpdate(t *testing.T) { + sinkBindingClient := v1alpha13.NewMockKnSinkBindingClient(t) + + mysvc := createService("myscv") + othersvc := createService("othersvc") + + dynamicClient := dynamic_fake.CreateFakeKnDynamicClient("default", mysvc, othersvc) + + bindingRecorder := sinkBindingClient.Recorder() + ceOverrideMap := map[string]string{"bla": "blub", "foo": "bar"} + bindingRecorder.GetSinkBinding("testbinding", createSinkBinding("testbinding", "mysvc", deploymentGvk, "mydeploy", ceOverrideMap), nil) + bindingRecorder.UpdateSinkBinding(createSinkBinding("testbinding", "othersvc", deploymentGvk, "mydeploy", ceOverrideMap), nil) + + out, err := executeSinkBindingCommand(sinkBindingClient, dynamicClient, "update", "testbinding", "--sink", "svc:othersvc", "--ce-override", "bla=blub", "--ce-override", "foo=bar") + assert.NilError(t, err) + util.ContainsAll(out, "updated", "default", "testbinding", "foo", "bar") + + bindingRecorder.Validate() +} + +func createService(name string) *serving_v1alpha1.Service { + mysvc := &serving_v1alpha1.Service{ + TypeMeta: v1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1"}, + ObjectMeta: v1.ObjectMeta{Name: name, Namespace: "default"}, + } + return mysvc +} + +func TestUpdateError(t *testing.T) { + sinkBindingClient := v1alpha13.NewMockKnSinkBindingClient(t) + bindingRecorder := sinkBindingClient.Recorder() + bindingRecorder.GetSinkBinding("testbinding", nil, errors.New("no such binding testbinding")) + + out, err := executeSinkBindingCommand(sinkBindingClient, nil, "update", "testbinding") + assert.ErrorContains(t, err, "testbinding") + util.ContainsAll(out, "testbinding", "name", "required") + + bindingRecorder.Validate() +} diff --git a/pkg/kn/commands/source/cronjob/cronjob_test.go b/pkg/kn/commands/source/cronjob/cronjob_test.go index 08da600e9d..d5124e31ce 100644 --- a/pkg/kn/commands/source/cronjob/cronjob_test.go +++ b/pkg/kn/commands/source/cronjob/cronjob_test.go @@ -84,7 +84,7 @@ func cleanupCronJobMockClient() { func createCronJobSource(name, schedule, data, service string) *v1alpha1.CronJobSource { sink := &v1beta1.Destination{ - Ref: &corev1.ObjectReference{Name: service, Kind: "Service", Namespace: "default", APIVersion: "serving.knative.dev/v1alpha1"}, + Ref: &corev1.ObjectReference{Name: service, Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1", Namespace: "default"}, } return source_client_v1alpha1.NewCronJobSourceBuilder(name).Schedule(schedule).Data(data).Sink(sink).Build() } diff --git a/pkg/kn/commands/source/cronjob/delete.go b/pkg/kn/commands/source/cronjob/delete.go index c453cdee64..0f1ccf278e 100644 --- a/pkg/kn/commands/source/cronjob/delete.go +++ b/pkg/kn/commands/source/cronjob/delete.go @@ -24,7 +24,7 @@ import ( // NewCronJobDeleteCommand is for deleting a CronJob source func NewCronJobDeleteCommand(p *commands.KnParams) *cobra.Command { - ApiServerDeleteCommand := &cobra.Command{ + CronJobDeleteCommand := &cobra.Command{ Use: "delete NAME", Short: "Delete a CronJob source.", Example: ` @@ -50,6 +50,6 @@ func NewCronJobDeleteCommand(p *commands.KnParams) *cobra.Command { return nil }, } - commands.AddNamespaceFlags(ApiServerDeleteCommand.Flags(), false) - return ApiServerDeleteCommand + commands.AddNamespaceFlags(CronJobDeleteCommand.Flags(), false) + return CronJobDeleteCommand } diff --git a/pkg/kn/commands/source/cronjob/describe.go b/pkg/kn/commands/source/cronjob/describe.go index 0efe86ade9..be150dd270 100644 --- a/pkg/kn/commands/source/cronjob/describe.go +++ b/pkg/kn/commands/source/cronjob/describe.go @@ -33,8 +33,8 @@ func NewCronJobDescribeCommand(p *commands.KnParams) *cobra.Command { Use: "describe NAME", Short: "Describe a CronJob source.", Example: ` - # Describe a cronjob source with name 'my-cron-trigger' - kn source cronjob describe my-cron-trigger`, + # Describe a cronjob source with name 'mycronjob' + kn source cronjob describe mycronjob`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("'source cronjob describe' requires the name of the source as single argument") diff --git a/pkg/kn/commands/source/cronjob/flags.go b/pkg/kn/commands/source/cronjob/flags.go index 3ca5894652..564a7c39bc 100644 --- a/pkg/kn/commands/source/cronjob/flags.go +++ b/pkg/kn/commands/source/cronjob/flags.go @@ -65,6 +65,9 @@ func printSource(source *v1alpha1.CronJobSource, options hprinters.PrintOptions) ready := commands.ReadyCondition(source.Status.Conditions) reason := commands.NonReadyConditionReason(source.Status.Conditions) + // Not moving to SinkToString() as it references v1beta1.Destination + // This source is going to be moved/removed soon to v1, so no need to move + // it now var sink string if source.Spec.Sink != nil { if source.Spec.Sink.Ref != nil { diff --git a/pkg/kn/commands/source/cronjob/update_test.go b/pkg/kn/commands/source/cronjob/update_test.go index db44e84bbc..b986f9ba3a 100644 --- a/pkg/kn/commands/source/cronjob/update_test.go +++ b/pkg/kn/commands/source/cronjob/update_test.go @@ -45,8 +45,8 @@ func TestSimpleUpdate(t *testing.T) { Ref: &corev1.ObjectReference{ Kind: "Service", Name: "mysvc", - Namespace: "default", APIVersion: "serving.knative.dev/v1alpha1", + Namespace: "default", }, }, }, diff --git a/pkg/kn/commands/source/human_readable_flags.go b/pkg/kn/commands/source/human_readable_flags.go index 80d9ec3e8d..11f8b91757 100644 --- a/pkg/kn/commands/source/human_readable_flags.go +++ b/pkg/kn/commands/source/human_readable_flags.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/runtime" + hprinters "knative.dev/client/pkg/printers" ) diff --git a/pkg/kn/commands/source/source.go b/pkg/kn/commands/source/source.go index 88e6c37843..7aa3f71cde 100644 --- a/pkg/kn/commands/source/source.go +++ b/pkg/kn/commands/source/source.go @@ -19,6 +19,7 @@ import ( "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands/source/apiserver" + "knative.dev/client/pkg/kn/commands/source/binding" "knative.dev/client/pkg/kn/commands/source/cronjob" ) @@ -30,5 +31,6 @@ func NewSourceCommand(p *commands.KnParams) *cobra.Command { sourceCmd.AddCommand(apiserver.NewAPIServerCommand(p)) sourceCmd.AddCommand(NewListTypesCommand(p)) sourceCmd.AddCommand(cronjob.NewCronJobCommand(p)) + sourceCmd.AddCommand(binding.NewBindingCommand(p)) return sourceCmd } diff --git a/pkg/kn/commands/trigger/create.go b/pkg/kn/commands/trigger/create.go index 906633fe02..065d3b911d 100644 --- a/pkg/kn/commands/trigger/create.go +++ b/pkg/kn/commands/trigger/create.go @@ -20,10 +20,11 @@ import ( "github.com/spf13/cobra" + duckv1 "knative.dev/pkg/apis/duck/v1" + client_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands/flags" - duckv1 "knative.dev/pkg/apis/duck/v1" ) // NewTriggerCreateCommand to create trigger create command diff --git a/pkg/kn/commands/trigger/create_test.go b/pkg/kn/commands/trigger/create_test.go index f01019fc31..a4e7d96fa9 100644 --- a/pkg/kn/commands/trigger/create_test.go +++ b/pkg/kn/commands/trigger/create_test.go @@ -20,10 +20,11 @@ import ( "gotest.tools/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" + dynamic_fake "knative.dev/client/pkg/dynamic/fake" eventing_client "knative.dev/client/pkg/eventing/v1alpha1" "knative.dev/client/pkg/util" - serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" ) var ( diff --git a/pkg/kn/commands/trigger/delete_test.go b/pkg/kn/commands/trigger/delete_test.go index 5e5f86fd4f..7abffa7c5d 100644 --- a/pkg/kn/commands/trigger/delete_test.go +++ b/pkg/kn/commands/trigger/delete_test.go @@ -19,6 +19,7 @@ import ( "testing" "gotest.tools/assert" + eventing_client "knative.dev/client/pkg/eventing/v1alpha1" "knative.dev/client/pkg/util" ) diff --git a/pkg/kn/commands/trigger/describe_test.go b/pkg/kn/commands/trigger/describe_test.go index 3b8ba46b4f..691aaf83a4 100644 --- a/pkg/kn/commands/trigger/describe_test.go +++ b/pkg/kn/commands/trigger/describe_test.go @@ -23,10 +23,11 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" - "knative.dev/client/pkg/util" v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" duckv1 "knative.dev/pkg/apis/duck/v1" + + client_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" + "knative.dev/client/pkg/util" ) func TestSimpleDescribe(t *testing.T) { diff --git a/pkg/kn/commands/trigger/list_test.go b/pkg/kn/commands/trigger/list_test.go index f89c4e7bbc..a0eccd99e2 100644 --- a/pkg/kn/commands/trigger/list_test.go +++ b/pkg/kn/commands/trigger/list_test.go @@ -20,11 +20,12 @@ import ( "gotest.tools/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" + eventing_client "knative.dev/client/pkg/eventing/v1alpha1" knserving_client "knative.dev/client/pkg/serving/v1alpha1" "knative.dev/client/pkg/util" - "knative.dev/eventing/pkg/apis/eventing/v1alpha1" - serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" ) func TestTriggerList(t *testing.T) { diff --git a/pkg/kn/commands/trigger/trigger_test.go b/pkg/kn/commands/trigger/trigger_test.go index 05e58cc70f..51889e50f8 100644 --- a/pkg/kn/commands/trigger/trigger_test.go +++ b/pkg/kn/commands/trigger/trigger_test.go @@ -19,12 +19,13 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/clientcmd" - kn_dynamic "knative.dev/client/pkg/dynamic" - eventc_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" - "knative.dev/client/pkg/kn/commands" "knative.dev/eventing/pkg/apis/eventing/v1alpha1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" + + kn_dynamic "knative.dev/client/pkg/dynamic" + eventc_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" + "knative.dev/client/pkg/kn/commands" ) // Helper methods @@ -76,19 +77,12 @@ func executeTriggerCommand(triggerClient eventc_v1alpha1.KnEventingClient, dynam } func createTrigger(namespace string, name string, filters map[string]string, broker string, svcname string) *v1alpha1.Trigger { - triggerBuilder := eventc_v1alpha1.NewTriggerBuilder(name). + return eventc_v1alpha1.NewTriggerBuilder(name). Namespace(namespace). Broker(broker). Filters(filters). - Subscriber(&duckv1.Destination{ - Ref: &corev1.ObjectReference{ - Name: svcname, - Kind: "Service", - Namespace: "default", - APIVersion: "serving.knative.dev/v1alpha1", - }, - }) - return triggerBuilder.Build() + Subscriber(createServiceSink(svcname)). + Build() } func createTriggerWithStatus(namespace string, name string, filters map[string]string, broker string, svcname string) *v1alpha1.Trigger { @@ -104,3 +98,9 @@ func createTriggerWithStatus(namespace string, name string, filters map[string]s } return wanted } + +func createServiceSink(service string) *duckv1.Destination { + return &duckv1.Destination{ + Ref: &corev1.ObjectReference{Name: service, Kind: "Service", APIVersion: "serving.knative.dev/v1alpha1", Namespace: "default"}, + } +} diff --git a/pkg/kn/commands/trigger/update.go b/pkg/kn/commands/trigger/update.go index 16b95c6d29..1a7c752cf6 100644 --- a/pkg/kn/commands/trigger/update.go +++ b/pkg/kn/commands/trigger/update.go @@ -20,15 +20,16 @@ import ( "github.com/spf13/cobra" + "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + duckv1 "knative.dev/pkg/apis/duck/v1" + client_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands/flags" "knative.dev/client/pkg/util" - "knative.dev/eventing/pkg/apis/eventing/v1alpha1" - duckv1 "knative.dev/pkg/apis/duck/v1" ) -// NewTriggerUpdateCommand prepares the command for a CronJobSource update +// NewTriggerUpdateCommand prepares the command for a tigger update func NewTriggerUpdateCommand(p *commands.KnParams) *cobra.Command { var triggerUpdateFlags TriggerUpdateFlags var sinkFlags flags.SinkFlags diff --git a/pkg/kn/commands/trigger/update_test.go b/pkg/kn/commands/trigger/update_test.go index 31b699dfc0..9175f2e062 100644 --- a/pkg/kn/commands/trigger/update_test.go +++ b/pkg/kn/commands/trigger/update_test.go @@ -20,10 +20,11 @@ import ( "gotest.tools/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" + dynamic_fake "knative.dev/client/pkg/dynamic/fake" eventing_client "knative.dev/client/pkg/eventing/v1alpha1" "knative.dev/client/pkg/util" - serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1" ) func TestTriggerUpdate(t *testing.T) { diff --git a/pkg/kn/commands/types.go b/pkg/kn/commands/types.go index aae0ab3e1f..3c47652b66 100644 --- a/pkg/kn/commands/types.go +++ b/pkg/kn/commands/types.go @@ -23,11 +23,12 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "knative.dev/client/pkg/util" eventing "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" eventing_sources "knative.dev/eventing/pkg/legacyclient/clientset/versioned/typed/legacysources/v1alpha1" serving_v1alpha1_client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1" + "knative.dev/client/pkg/util" + dynamic_kn "knative.dev/client/pkg/dynamic" sources_kn_v1alpha1 "knative.dev/client/pkg/eventing/legacysources/v1alpha1" eventing_kn_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1" diff --git a/pkg/sources/v1alpha1/binding_client.go b/pkg/sources/v1alpha1/binding_client.go new file mode 100644 index 0000000000..e7c906254b --- /dev/null +++ b/pkg/sources/v1alpha1/binding_client.go @@ -0,0 +1,263 @@ +// 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 v1alpha1 + +import ( + "fmt" + + apis_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/tracker" + + kn_errors "knative.dev/client/pkg/errors" + "knative.dev/client/pkg/util" +) + +// KnSinkBindingClient to Eventing Sources. All methods are relative to the +// namespace specified during construction +type KnSinkBindingClient interface { + // Namespace in which this client is operating for + Namespace() string + // CreateSinkBinding is used to create an instance of binding + CreateSinkBinding(binding *v1alpha1.SinkBinding) error + // DeleteSinkBinding is used to delete an instance of binding + DeleteSinkBinding(name string) error + // GetSinkBinding is used to get an instance of binding + GetSinkBinding(name string) (*v1alpha1.SinkBinding, error) + // ListSinkBinding returns list of binding CRDs + ListSinkBindings() (*v1alpha1.SinkBindingList, error) + // UpdateSinkBinding is used to update an instance of binding + UpdateSinkBinding(binding *v1alpha1.SinkBinding) error +} + +// KnSinkBindingClient is a combination of Sources client interface and namespace +// Temporarily help to add sources dependencies +// May be changed when adding real sources features +type knBindingClient struct { + client client_v1alpha1.SinkBindingInterface + namespace string +} + +// NewKnSourcesClient is to invoke Eventing Sources Client API to create object +func newKnSinkBindingClient(client client_v1alpha1.SinkBindingInterface, namespace string) KnSinkBindingClient { + return &knBindingClient{ + client: client, + namespace: namespace, + } +} + +//CreateSinkBinding is used to create an instance of binding +func (c *knBindingClient) CreateSinkBinding(binding *v1alpha1.SinkBinding) error { + binding, err := c.client.Create(binding) + if err != nil { + return kn_errors.GetError(err) + } + return nil +} + +//DeleteSinkBinding is used to delete an instance of binding +func (c *knBindingClient) DeleteSinkBinding(name string) error { + err := c.client.Delete(name, &apis_v1.DeleteOptions{}) + if err != nil { + return kn_errors.GetError(err) + } + return nil +} + +//GetSinkBinding is used to get an instance of binding +func (c *knBindingClient) GetSinkBinding(name string) (*v1alpha1.SinkBinding, error) { + binding, err := c.client.Get(name, apis_v1.GetOptions{}) + if err != nil { + return nil, kn_errors.GetError(err) + } + return binding, nil +} + +func (c *knBindingClient) ListSinkBindings() (*v1alpha1.SinkBindingList, error) { + bindingList, err := c.client.List(apis_v1.ListOptions{}) + if err != nil { + return nil, kn_errors.GetError(err) + } + bindingListNew := bindingList.DeepCopy() + err = updateSinkBindingGvk(bindingListNew) + if err != nil { + return nil, err + } + + bindingListNew.Items = make([]v1alpha1.SinkBinding, len(bindingList.Items)) + for idx, binding := range bindingList.Items { + bindingClone := binding.DeepCopy() + err := updateSinkBindingGvk(bindingClone) + if err != nil { + return nil, err + } + bindingListNew.Items[idx] = *bindingClone + } + return bindingListNew, nil +} + +//CreateSinkBinding is used to create an instance of binding +func (c *knBindingClient) UpdateSinkBinding(binding *v1alpha1.SinkBinding) error { + binding, err := c.client.Update(binding) + if err != nil { + return kn_errors.GetError(err) + } + return nil +} + +// Return the client's namespace +func (c *knBindingClient) Namespace() string { + return c.namespace +} + +// update with the v1alpha1 group + version +func updateSinkBindingGvk(obj runtime.Object) error { + return util.UpdateGroupVersionKindWithScheme(obj, v1alpha1.SchemeGroupVersion, scheme.Scheme) +} + +// SinkBindingBuilder is for building the binding +type SinkBindingBuilder struct { + binding *v1alpha1.SinkBinding + sGvk *schema.GroupVersionKind + sName string + sLabelSelector map[string]string + sNamespace string + + // When set directly: + subject *tracker.Reference +} + +// NewSinkBindingBuilder for building binding object +func NewSinkBindingBuilder(name string) *SinkBindingBuilder { + return &SinkBindingBuilder{binding: &v1alpha1.SinkBinding{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: name, + }, + }} +} + +// NewSinkBindingBuilderFromExisting for building the object from existing SinkBinding object +func NewSinkBindingBuilderFromExisting(binding *v1alpha1.SinkBinding) *SinkBindingBuilder { + return &SinkBindingBuilder{binding: binding.DeepCopy()} +} + +// Namespace for this binding +func (b *SinkBindingBuilder) Namespace(ns string) *SinkBindingBuilder { + b.binding.Namespace = ns + return b +} + +// Subscriber for the binding to send to (it's a Sink actually) +func (b *SinkBindingBuilder) Subject(subject *tracker.Reference) *SinkBindingBuilder { + b.subject = subject + return b +} + +// Add a GVK of the subject +func (b *SinkBindingBuilder) SubjectGVK(gvk *schema.GroupVersionKind) *SinkBindingBuilder { + b.sGvk = gvk + return b +} + +// Add a subject name for building up the name +func (b *SinkBindingBuilder) SubjectName(name string) *SinkBindingBuilder { + b.sName = name + return b +} + +// Add a subject namespace for building up the name +func (b *SinkBindingBuilder) SubjectNamespace(ns string) *SinkBindingBuilder { + b.sNamespace = ns + return b +} + +// Add a label match part for building up the subject +func (b *SinkBindingBuilder) AddSubjectMatchLabel(labelKey, labelValue string) *SinkBindingBuilder { + if b.sLabelSelector == nil { + b.sLabelSelector = map[string]string{} + } + b.sLabelSelector[labelKey] = labelValue + return b +} + +// Broker to set the broker of binding object +func (b *SinkBindingBuilder) Sink(sink *duckv1.Destination) *SinkBindingBuilder { + b.binding.Spec.Sink = *sink + return b +} + +func (b *SinkBindingBuilder) AddCloudEventOverrides(ceo map[string]string) *SinkBindingBuilder { + ceOverrides := b.binding.Spec.CloudEventOverrides + if ceOverrides == nil { + ceOverrides = &duckv1.CloudEventOverrides{Extensions: map[string]string{}} + b.binding.Spec.CloudEventOverrides = ceOverrides + } + for k, v := range ceo { + ceOverrides.Extensions[k] = v + } + return b +} + +// Build to return an instance of binding object +func (b *SinkBindingBuilder) Build() (*v1alpha1.SinkBinding, error) { + // If set directly, return the sink binding directly + if b.subject != nil { + b.binding.Spec.Subject = *b.subject + return b.binding, nil + } + + if b.sGvk == nil && b.sName == "" && b.sLabelSelector == nil { + // None of the subject methods has been called, so no subject build up + return b.binding, nil + } + + // Otherwise, validate and build up the subject + if b.sGvk == nil { + return nil, fmt.Errorf("no group-version-kind provided for creating binding %s", b.binding.Name) + } + + if b.sName != "" && b.sLabelSelector != nil { + return nil, fmt.Errorf("either a subject name or label selector can be used for creating binding %s, but not both (subject name: %s, label selector: %v", b.binding.Name, b.sName, b.sLabelSelector) + } + + subject := b.prepareBaseSubject() + if b.sName != "" { + subject.Name = b.sName + } else { + subject.Selector = &meta_v1.LabelSelector{ + MatchLabels: b.sLabelSelector, + } + } + + b.binding.Spec.Subject = subject + return b.binding, nil +} + +func (b *SinkBindingBuilder) prepareBaseSubject() tracker.Reference { + subject := tracker.Reference{ + APIVersion: b.sGvk.GroupVersion().String(), + Kind: b.sGvk.Kind, + } + if b.sNamespace != "" { + subject.Namespace = b.sNamespace + } + return subject +} diff --git a/pkg/sources/v1alpha1/binding_client_mock.go b/pkg/sources/v1alpha1/binding_client_mock.go new file mode 100644 index 0000000000..aff7ad596e --- /dev/null +++ b/pkg/sources/v1alpha1/binding_client_mock.go @@ -0,0 +1,120 @@ +// 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 v1alpha1 + +import ( + "testing" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + + "knative.dev/client/pkg/util/mock" +) + +// MockKnSinkBindingClient is a combine of test object and recorder +type MockKnSinkBindingClient struct { + t *testing.T + recorder *EventingRecorder + namespace string +} + +// NewMockKnSinkBindingClient returns a new mock instance which you need to record for +func NewMockKnSinkBindingClient(t *testing.T, ns ...string) *MockKnSinkBindingClient { + namespace := "default" + if len(ns) > 0 { + namespace = ns[0] + } + return &MockKnSinkBindingClient{ + t: t, + recorder: &EventingRecorder{mock.NewRecorder(t, namespace)}, + } +} + +// Ensure that the interface is implemented +var _ KnSinkBindingClient = &MockKnSinkBindingClient{} + +// EventingRecorder is recorder for eventing objects +type EventingRecorder struct { + r *mock.Recorder +} + +// Recorder returns the recorder for registering API calls +func (c *MockKnSinkBindingClient) Recorder() *EventingRecorder { + return c.recorder +} + +// Namespace of this client +func (c *MockKnSinkBindingClient) Namespace() string { + return c.recorder.r.Namespace() +} + +// CreateSinkBinding records a call for CreateSinkBinding with the expected error +func (sr *EventingRecorder) CreateSinkBinding(binding interface{}, err error) { + sr.r.Add("CreateSinkBinding", []interface{}{binding}, []interface{}{err}) +} + +// CreateSinkBinding performs a previously recorded action +func (c *MockKnSinkBindingClient) CreateSinkBinding(binding *v1alpha1.SinkBinding) error { + call := c.recorder.r.VerifyCall("CreateSinkBinding", binding) + return mock.ErrorOrNil(call.Result[0]) +} + +// GetSinkBinding records a call for GetSinkBinding with the expected object or error. Either binding or err should be nil +func (sr *EventingRecorder) GetSinkBinding(name interface{}, binding *v1alpha1.SinkBinding, err error) { + sr.r.Add("GetSinkBinding", []interface{}{name}, []interface{}{binding, err}) +} + +// GetSinkBinding performs a previously recorded action +func (c *MockKnSinkBindingClient) GetSinkBinding(name string) (*v1alpha1.SinkBinding, error) { + call := c.recorder.r.VerifyCall("GetSinkBinding", name) + return call.Result[0].(*v1alpha1.SinkBinding), mock.ErrorOrNil(call.Result[1]) +} + +// DeleteSinkBinding records a call for DeleteSinkBinding with the expected error (nil if none) +func (sr *EventingRecorder) DeleteSinkBinding(name interface{}, err error) { + sr.r.Add("DeleteSinkBinding", []interface{}{name}, []interface{}{err}) +} + +// DeleteSinkBinding performs a previously recorded action, failing if non has been registered +func (c *MockKnSinkBindingClient) DeleteSinkBinding(name string) error { + call := c.recorder.r.VerifyCall("DeleteSinkBinding", name) + return mock.ErrorOrNil(call.Result[0]) +} + +// ListSinkBindings records a call for ListSinkBindings with the expected result and error (nil if none) +func (sr *EventingRecorder) ListSinkBindings(bindingList *v1alpha1.SinkBindingList, err error) { + sr.r.Add("ListSinkBindings", nil, []interface{}{bindingList, err}) +} + +// ListSinkBindings performs a previously recorded action +func (c *MockKnSinkBindingClient) ListSinkBindings() (*v1alpha1.SinkBindingList, error) { + call := c.recorder.r.VerifyCall("ListSinkBindings") + return call.Result[0].(*v1alpha1.SinkBindingList), mock.ErrorOrNil(call.Result[1]) +} + +// UpdateSinkBinding records a call for ListSinkBindings with the expected result and error (nil if none) +func (sr *EventingRecorder) UpdateSinkBinding(binding interface{}, err error) { + sr.r.Add("UpdateSinkBinding", []interface{}{binding}, []interface{}{err}) +} + +// UpdateSinkBinding performs a previously recorded action +func (c *MockKnSinkBindingClient) UpdateSinkBinding(binding *v1alpha1.SinkBinding) error { + call := c.recorder.r.VerifyCall("UpdateSinkBinding") + return mock.ErrorOrNil(call.Result[0]) +} + +// Validate validates whether every recorded action has been called +func (sr *EventingRecorder) Validate() { + sr.r.CheckThatAllRecordedMethodsHaveBeenCalled() +} diff --git a/pkg/sources/v1alpha1/binding_client_mock_test.go b/pkg/sources/v1alpha1/binding_client_mock_test.go new file mode 100644 index 0000000000..f43c5b2e08 --- /dev/null +++ b/pkg/sources/v1alpha1/binding_client_mock_test.go @@ -0,0 +1,44 @@ +// 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 v1alpha1 + +import ( + "testing" + + "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +func TestMockKnClient(t *testing.T) { + client := NewMockKnSinkBindingClient(t) + + recorder := client.Recorder() + + // Record all services + recorder.GetSinkBinding("hello", nil, nil) + recorder.CreateSinkBinding(&v1alpha1.SinkBinding{}, nil) + recorder.DeleteSinkBinding("hello", nil) + recorder.ListSinkBindings(nil, nil) + recorder.UpdateSinkBinding(&v1alpha1.SinkBinding{}, nil) + + // Call all service + client.GetSinkBinding("hello") + client.CreateSinkBinding(&v1alpha1.SinkBinding{}) + client.DeleteSinkBinding("hello") + client.ListSinkBindings() + client.UpdateSinkBinding(&v1alpha1.SinkBinding{}) + + // Validate + recorder.Validate() +} diff --git a/pkg/sources/v1alpha1/binding_client_test.go b/pkg/sources/v1alpha1/binding_client_test.go new file mode 100644 index 0000000000..3642e34eb9 --- /dev/null +++ b/pkg/sources/v1alpha1/binding_client_test.go @@ -0,0 +1,253 @@ +// 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 v1alpha1 + +import ( + "fmt" + "testing" + + "gotest.tools/assert" + v12 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + client_testing "k8s.io/client-go/testing" + "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake" + v1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/tracker" +) + +var testNamespace = "test-ns" + +func setup() (fakeSvr fake.FakeSourcesV1alpha1, client KnSinkBindingClient) { + fakeE := fake.FakeSourcesV1alpha1{Fake: &client_testing.Fake{}} + cli := NewKnSourcesClient(&fakeE, "test-ns").SinkBindingClient() + return fakeE, cli +} + +func TestDeleteSinkBinding(t *testing.T) { + var name = "new-binding" + server, client := setup() + + server.AddReactor("delete", "sinkbindings", + func(a client_testing.Action) (bool, runtime.Object, error) { + name := a.(client_testing.DeleteAction).GetName() + if name == "errorSinkBinding" { + return true, nil, fmt.Errorf("error while deleting binding %s", name) + } + return true, nil, nil + }) + + err := client.DeleteSinkBinding(name) + assert.NilError(t, err) + + err = client.DeleteSinkBinding("errorSinkBinding") + assert.ErrorContains(t, err, "errorSinkBinding") +} + +func TestCreateSinkBinding(t *testing.T) { + var name = "new-binding" + server, client := setup() + + objNew := newSinkBinding(name, "mysvc", "mycronjob") + + server.AddReactor("create", "sinkbindings", + func(a client_testing.Action) (bool, runtime.Object, error) { + assert.Equal(t, testNamespace, a.GetNamespace()) + name := a.(client_testing.CreateAction).GetObject().(metav1.Object).GetName() + if name == objNew.Name { + objNew.Generation = 2 + return true, objNew, nil + } + return true, nil, fmt.Errorf("error while creating binding %s", name) + }) + + t.Run("create binding without error", func(t *testing.T) { + err := client.CreateSinkBinding(objNew) + assert.NilError(t, err) + }) + + t.Run("create binding with an error returns an error object", func(t *testing.T) { + err := client.CreateSinkBinding(newSinkBinding("unknown", "mysvc", "mycronjobs")) + assert.ErrorContains(t, err, "unknown") + }) +} + +func TestGetSinkBinding(t *testing.T) { + var name = "mysinkbinding" + server, client := setup() + + server.AddReactor("get", "sinkbindings", + func(a client_testing.Action) (bool, runtime.Object, error) { + name := a.(client_testing.GetAction).GetName() + if name == "errorSinkBinding" { + return true, nil, fmt.Errorf("error while getting binding %s", name) + } + return true, newSinkBinding(name, "mysvc", "mycronjob"), nil + }) + + binding, err := client.GetSinkBinding(name) + assert.NilError(t, err) + assert.Equal(t, binding.Name, name) + assert.Equal(t, binding.Spec.Sink.Ref.Name, "mysvc") + assert.Equal(t, binding.Spec.Subject.Name, "mycronjob") + + _, err = client.GetSinkBinding("errorSinkBinding") + assert.ErrorContains(t, err, "errorSinkBinding") +} + +func TestListSinkBinding(t *testing.T) { + serving, client := setup() + + t.Run("list binding returns a list of sink-bindings", func(t *testing.T) { + binding1 := newSinkBinding("binding-1", "mysvc-1", "mycronjob") + binding2 := newSinkBinding("binding-2", "mysvc-2", "mycronjob") + + serving.AddReactor("list", "sinkbindings", + func(a client_testing.Action) (bool, runtime.Object, error) { + assert.Equal(t, testNamespace, a.GetNamespace()) + return true, &v1alpha1.SinkBindingList{Items: []v1alpha1.SinkBinding{*binding1, *binding2}}, nil + }) + + listSinkBindings, err := client.ListSinkBindings() + assert.NilError(t, err) + assert.Assert(t, len(listSinkBindings.Items) == 2) + assert.Equal(t, listSinkBindings.Items[0].Name, "binding-1") + assert.Equal(t, listSinkBindings.Items[0].Spec.Sink.Ref.Name, "mysvc-1") + assert.Equal(t, listSinkBindings.Items[0].Spec.Subject.Name, "mycronjob") + assert.Equal(t, listSinkBindings.Items[1].Name, "binding-2") + assert.Equal(t, listSinkBindings.Items[1].Spec.Sink.Ref.Name, "mysvc-2") + assert.Equal(t, listSinkBindings.Items[1].Spec.Subject.Name, "mycronjob") + + }) +} + +func TestSinkBindingBuilderAddCloudEventOverrides(t *testing.T) { + aBuilder := NewSinkBindingBuilder("testsinkbinding") + aBuilder.AddCloudEventOverrides(map[string]string{"type": "foo"}) + a, err := aBuilder.Build() + assert.NilError(t, err) + + t.Run("update bindings", func(t *testing.T) { + bBuilder := NewSinkBindingBuilderFromExisting(a) + b, err := bBuilder.Build() + assert.NilError(t, err) + assert.DeepEqual(t, b, a) + bBuilder.AddCloudEventOverrides(map[string]string{"type": "new"}) + expected := &v1.CloudEventOverrides{ + Extensions: map[string]string{ + "type": "new", + }, + } + + assert.DeepEqual(t, expected, b.Spec.CloudEventOverrides) + }) + + t.Run("update bindings with both new entry and old entry", func(t *testing.T) { + bBuilder := NewSinkBindingBuilderFromExisting(a) + b, err := bBuilder.Build() + assert.NilError(t, err) + assert.DeepEqual(t, b, a) + bBuilder.AddCloudEventOverrides(map[string]string{"source": "bar"}) + expected := &v1.CloudEventOverrides{ + Extensions: map[string]string{ + "type": "foo", + "source": "bar", + }, + } + assert.DeepEqual(t, expected, b.Spec.CloudEventOverrides) + }) +} + +func TestSinkBindingBuilderForSubjectError(t *testing.T) { + + b, err := NewSinkBindingBuilder("test").SubjectName("bla").Build() + assert.Assert(t, b == nil) + assert.ErrorContains(t, err, "group") + assert.ErrorContains(t, err, "version") + assert.ErrorContains(t, err, "kind") + + b, err = NewSinkBindingBuilder("test"). + SubjectGVK(&schema.GroupVersionKind{"apps", "v1", "Deployment"}). + SubjectName("foo"). + AddSubjectMatchLabel("bla", "blub"). + Build() + assert.ErrorContains(t, err, "label selector") + assert.ErrorContains(t, err, "name") + assert.ErrorContains(t, err, "subject") + assert.Assert(t, b == nil) + +} + +func TestSinkBindingBuilderForSubject(t *testing.T) { + gvk := schema.GroupVersionKind{"apps", "v1", "Deployment"} + + b, err := NewSinkBindingBuilder("test"). + SubjectGVK(&gvk). + SubjectName("foo"). + Build() + assert.NilError(t, err) + subject := b.Spec.Subject + assert.Equal(t, subject.Name, "foo") + assert.Assert(t, subject.Selector == nil) + assert.DeepEqual(t, subject.GroupVersionKind(), gvk) + + b, err = NewSinkBindingBuilder("test"). + SubjectGVK(&schema.GroupVersionKind{"apps", "v1", "Deployment"}). + AddSubjectMatchLabel("bla", "blub"). + AddSubjectMatchLabel("foo", "bar"). + Build() + + assert.NilError(t, err) + subject = b.Spec.Subject + assert.Equal(t, subject.Name, "") + assert.DeepEqual(t, subject.GroupVersionKind(), gvk) + selector := map[string]string{ + "bla": "blub", + "foo": "bar", + } + assert.DeepEqual(t, subject.Selector.MatchLabels, selector) +} + +func TestSinkBindingBuilderForSubjectDirect(t *testing.T) { + + subject := tracker.Reference{ + Name: "direct", + } + b, err := NewSinkBindingBuilder("test"). + Subject(&subject). + SubjectName("nope"). // should be ignored + AddSubjectMatchLabel("bla", "blub"). // should be ignored + Build() + assert.NilError(t, err) + subject = b.Spec.Subject + assert.Equal(t, subject.Name, "direct") + assert.Assert(t, subject.Selector == nil) +} + +func newSinkBinding(name, sinkService, cronJobName string) *v1alpha1.SinkBinding { + sink := &v1.Destination{ + Ref: &v12.ObjectReference{Name: sinkService, Kind: "Service", Namespace: "default", APIVersion: "serving.knative.dev/v1alpha1"}, + } + b, _ := NewSinkBindingBuilder(name). + Namespace(testNamespace). + Sink(sink). + SubjectGVK(&schema.GroupVersionKind{"batch", "v1beta1", "CronJob"}). + SubjectName(cronJobName). + AddCloudEventOverrides(map[string]string{"type": "foo"}). + Build() + return b +} diff --git a/pkg/sources/v1alpha1/client.go b/pkg/sources/v1alpha1/client.go new file mode 100644 index 0000000000..a6a4ebf1d9 --- /dev/null +++ b/pkg/sources/v1alpha1/client.go @@ -0,0 +1,47 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" +) + +// KnSinkBindingClient to Eventing Sources. All methods are relative to the +// namespace specified during construction +type KnSourcesClient interface { + // Get client for sink binding sources + SinkBindingClient() KnSinkBindingClient +} + +// sourcesClient is a combination of Sources client interface and namespace +// Temporarily help to add sources dependencies +// May be changed when adding real sources features +type sourcesClient struct { + client client_v1alpha1.SourcesV1alpha1Interface + namespace string +} + +// NewKnSourcesClient for managing all eventing built-in sources +func NewKnSourcesClient(client client_v1alpha1.SourcesV1alpha1Interface, namespace string) KnSourcesClient { + return &sourcesClient{ + client: client, + namespace: namespace, + } +} + +// ApiServerSourcesClient for dealing with ApiServer sources +func (c *sourcesClient) SinkBindingClient() KnSinkBindingClient { + return newKnSinkBindingClient(c.client.SinkBindings(c.namespace), c.namespace) +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/apiserversource.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/apiserversource.go new file mode 100644 index 0000000000..8c30ef3c25 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/apiserversource.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 v1alpha1 + +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" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ApiServerSourcesGetter has a method to return a ApiServerSourceInterface. +// A group's client should implement this interface. +type ApiServerSourcesGetter interface { + ApiServerSources(namespace string) ApiServerSourceInterface +} + +// ApiServerSourceInterface has methods to work with ApiServerSource resources. +type ApiServerSourceInterface interface { + Create(*v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error) + Update(*v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error) + UpdateStatus(*v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.ApiServerSource, error) + List(opts v1.ListOptions) (*v1alpha1.ApiServerSourceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ApiServerSource, err error) + ApiServerSourceExpansion +} + +// apiServerSources implements ApiServerSourceInterface +type apiServerSources struct { + client rest.Interface + ns string +} + +// newApiServerSources returns a ApiServerSources +func newApiServerSources(c *SourcesV1alpha1Client, namespace string) *apiServerSources { + return &apiServerSources{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the apiServerSource, and returns the corresponding apiServerSource object, and an error if there is any. +func (c *apiServerSources) Get(name string, options v1.GetOptions) (result *v1alpha1.ApiServerSource, err error) { + result = &v1alpha1.ApiServerSource{} + err = c.client.Get(). + Namespace(c.ns). + Resource("apiserversources"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ApiServerSources that match those selectors. +func (c *apiServerSources) List(opts v1.ListOptions) (result *v1alpha1.ApiServerSourceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ApiServerSourceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("apiserversources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested apiServerSources. +func (c *apiServerSources) 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("apiserversources"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a apiServerSource and creates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *apiServerSources) Create(apiServerSource *v1alpha1.ApiServerSource) (result *v1alpha1.ApiServerSource, err error) { + result = &v1alpha1.ApiServerSource{} + err = c.client.Post(). + Namespace(c.ns). + Resource("apiserversources"). + Body(apiServerSource). + Do(). + Into(result) + return +} + +// Update takes the representation of a apiServerSource and updates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *apiServerSources) Update(apiServerSource *v1alpha1.ApiServerSource) (result *v1alpha1.ApiServerSource, err error) { + result = &v1alpha1.ApiServerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("apiserversources"). + Name(apiServerSource.Name). + Body(apiServerSource). + 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 *apiServerSources) UpdateStatus(apiServerSource *v1alpha1.ApiServerSource) (result *v1alpha1.ApiServerSource, err error) { + result = &v1alpha1.ApiServerSource{} + err = c.client.Put(). + Namespace(c.ns). + Resource("apiserversources"). + Name(apiServerSource.Name). + SubResource("status"). + Body(apiServerSource). + Do(). + Into(result) + return +} + +// Delete takes name of the apiServerSource and deletes it. Returns an error if one occurs. +func (c *apiServerSources) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("apiserversources"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *apiServerSources) 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("apiserversources"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched apiServerSource. +func (c *apiServerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ApiServerSource, err error) { + result = &v1alpha1.ApiServerSource{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("apiserversources"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/doc.go new file mode 100644 index 0000000000..41e872fe9a --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/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 v1alpha1 diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/doc.go new file mode 100644 index 0000000000..c7f6e65cab --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/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. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_apiserversource.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_apiserversource.go new file mode 100644 index 0000000000..8424f3b2af --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_apiserversource.go @@ -0,0 +1,140 @@ +/* +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 fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +// FakeApiServerSources implements ApiServerSourceInterface +type FakeApiServerSources struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var apiserversourcesResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1alpha1", Resource: "apiserversources"} + +var apiserversourcesKind = schema.GroupVersionKind{Group: "sources.knative.dev", Version: "v1alpha1", Kind: "ApiServerSource"} + +// Get takes name of the apiServerSource, and returns the corresponding apiServerSource object, and an error if there is any. +func (c *FakeApiServerSources) Get(name string, options v1.GetOptions) (result *v1alpha1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(apiserversourcesResource, c.ns, name), &v1alpha1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ApiServerSource), err +} + +// List takes label and field selectors, and returns the list of ApiServerSources that match those selectors. +func (c *FakeApiServerSources) List(opts v1.ListOptions) (result *v1alpha1.ApiServerSourceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(apiserversourcesResource, apiserversourcesKind, c.ns, opts), &v1alpha1.ApiServerSourceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ApiServerSourceList{ListMeta: obj.(*v1alpha1.ApiServerSourceList).ListMeta} + for _, item := range obj.(*v1alpha1.ApiServerSourceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested apiServerSources. +func (c *FakeApiServerSources) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(apiserversourcesResource, c.ns, opts)) + +} + +// Create takes the representation of a apiServerSource and creates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *FakeApiServerSources) Create(apiServerSource *v1alpha1.ApiServerSource) (result *v1alpha1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(apiserversourcesResource, c.ns, apiServerSource), &v1alpha1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ApiServerSource), err +} + +// Update takes the representation of a apiServerSource and updates it. Returns the server's representation of the apiServerSource, and an error, if there is any. +func (c *FakeApiServerSources) Update(apiServerSource *v1alpha1.ApiServerSource) (result *v1alpha1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(apiserversourcesResource, c.ns, apiServerSource), &v1alpha1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ApiServerSource), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeApiServerSources) UpdateStatus(apiServerSource *v1alpha1.ApiServerSource) (*v1alpha1.ApiServerSource, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(apiserversourcesResource, "status", c.ns, apiServerSource), &v1alpha1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ApiServerSource), err +} + +// Delete takes name of the apiServerSource and deletes it. Returns an error if one occurs. +func (c *FakeApiServerSources) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(apiserversourcesResource, c.ns, name), &v1alpha1.ApiServerSource{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeApiServerSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(apiserversourcesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ApiServerSourceList{}) + return err +} + +// Patch applies the patch and returns the patched apiServerSource. +func (c *FakeApiServerSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ApiServerSource, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(apiserversourcesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ApiServerSource{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ApiServerSource), err +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sinkbinding.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sinkbinding.go new file mode 100644 index 0000000000..c9c446b0a0 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sinkbinding.go @@ -0,0 +1,140 @@ +/* +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 fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" +) + +// FakeSinkBindings implements SinkBindingInterface +type FakeSinkBindings struct { + Fake *FakeSourcesV1alpha1 + ns string +} + +var sinkbindingsResource = schema.GroupVersionResource{Group: "sources.knative.dev", Version: "v1alpha1", Resource: "sinkbindings"} + +var sinkbindingsKind = schema.GroupVersionKind{Group: "sources.knative.dev", Version: "v1alpha1", Kind: "SinkBinding"} + +// Get takes name of the sinkBinding, and returns the corresponding sinkBinding object, and an error if there is any. +func (c *FakeSinkBindings) Get(name string, options v1.GetOptions) (result *v1alpha1.SinkBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(sinkbindingsResource, c.ns, name), &v1alpha1.SinkBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SinkBinding), err +} + +// List takes label and field selectors, and returns the list of SinkBindings that match those selectors. +func (c *FakeSinkBindings) List(opts v1.ListOptions) (result *v1alpha1.SinkBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(sinkbindingsResource, sinkbindingsKind, c.ns, opts), &v1alpha1.SinkBindingList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.SinkBindingList{ListMeta: obj.(*v1alpha1.SinkBindingList).ListMeta} + for _, item := range obj.(*v1alpha1.SinkBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested sinkBindings. +func (c *FakeSinkBindings) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(sinkbindingsResource, c.ns, opts)) + +} + +// Create takes the representation of a sinkBinding and creates it. Returns the server's representation of the sinkBinding, and an error, if there is any. +func (c *FakeSinkBindings) Create(sinkBinding *v1alpha1.SinkBinding) (result *v1alpha1.SinkBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(sinkbindingsResource, c.ns, sinkBinding), &v1alpha1.SinkBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SinkBinding), err +} + +// Update takes the representation of a sinkBinding and updates it. Returns the server's representation of the sinkBinding, and an error, if there is any. +func (c *FakeSinkBindings) Update(sinkBinding *v1alpha1.SinkBinding) (result *v1alpha1.SinkBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(sinkbindingsResource, c.ns, sinkBinding), &v1alpha1.SinkBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SinkBinding), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeSinkBindings) UpdateStatus(sinkBinding *v1alpha1.SinkBinding) (*v1alpha1.SinkBinding, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(sinkbindingsResource, "status", c.ns, sinkBinding), &v1alpha1.SinkBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SinkBinding), err +} + +// Delete takes name of the sinkBinding and deletes it. Returns an error if one occurs. +func (c *FakeSinkBindings) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(sinkbindingsResource, c.ns, name), &v1alpha1.SinkBinding{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSinkBindings) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(sinkbindingsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.SinkBindingList{}) + return err +} + +// Patch applies the patch and returns the patched sinkBinding. +func (c *FakeSinkBindings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.SinkBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(sinkbindingsResource, c.ns, name, pt, data, subresources...), &v1alpha1.SinkBinding{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.SinkBinding), err +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go new file mode 100644 index 0000000000..41fe656771 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake/fake_sources_client.go @@ -0,0 +1,44 @@ +/* +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 fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" +) + +type FakeSourcesV1alpha1 struct { + *testing.Fake +} + +func (c *FakeSourcesV1alpha1) ApiServerSources(namespace string) v1alpha1.ApiServerSourceInterface { + return &FakeApiServerSources{c, namespace} +} + +func (c *FakeSourcesV1alpha1) SinkBindings(namespace string) v1alpha1.SinkBindingInterface { + return &FakeSinkBindings{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSourcesV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go new file mode 100644 index 0000000000..e0130fb3aa --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +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 v1alpha1 + +type ApiServerSourceExpansion interface{} + +type SinkBindingExpansion interface{} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sinkbinding.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sinkbinding.go new file mode 100644 index 0000000000..f3654923cb --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sinkbinding.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 v1alpha1 + +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" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// SinkBindingsGetter has a method to return a SinkBindingInterface. +// A group's client should implement this interface. +type SinkBindingsGetter interface { + SinkBindings(namespace string) SinkBindingInterface +} + +// SinkBindingInterface has methods to work with SinkBinding resources. +type SinkBindingInterface interface { + Create(*v1alpha1.SinkBinding) (*v1alpha1.SinkBinding, error) + Update(*v1alpha1.SinkBinding) (*v1alpha1.SinkBinding, error) + UpdateStatus(*v1alpha1.SinkBinding) (*v1alpha1.SinkBinding, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.SinkBinding, error) + List(opts v1.ListOptions) (*v1alpha1.SinkBindingList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.SinkBinding, err error) + SinkBindingExpansion +} + +// sinkBindings implements SinkBindingInterface +type sinkBindings struct { + client rest.Interface + ns string +} + +// newSinkBindings returns a SinkBindings +func newSinkBindings(c *SourcesV1alpha1Client, namespace string) *sinkBindings { + return &sinkBindings{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the sinkBinding, and returns the corresponding sinkBinding object, and an error if there is any. +func (c *sinkBindings) Get(name string, options v1.GetOptions) (result *v1alpha1.SinkBinding, err error) { + result = &v1alpha1.SinkBinding{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sinkbindings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of SinkBindings that match those selectors. +func (c *sinkBindings) List(opts v1.ListOptions) (result *v1alpha1.SinkBindingList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.SinkBindingList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sinkbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested sinkBindings. +func (c *sinkBindings) 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("sinkbindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a sinkBinding and creates it. Returns the server's representation of the sinkBinding, and an error, if there is any. +func (c *sinkBindings) Create(sinkBinding *v1alpha1.SinkBinding) (result *v1alpha1.SinkBinding, err error) { + result = &v1alpha1.SinkBinding{} + err = c.client.Post(). + Namespace(c.ns). + Resource("sinkbindings"). + Body(sinkBinding). + Do(). + Into(result) + return +} + +// Update takes the representation of a sinkBinding and updates it. Returns the server's representation of the sinkBinding, and an error, if there is any. +func (c *sinkBindings) Update(sinkBinding *v1alpha1.SinkBinding) (result *v1alpha1.SinkBinding, err error) { + result = &v1alpha1.SinkBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("sinkbindings"). + Name(sinkBinding.Name). + Body(sinkBinding). + 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 *sinkBindings) UpdateStatus(sinkBinding *v1alpha1.SinkBinding) (result *v1alpha1.SinkBinding, err error) { + result = &v1alpha1.SinkBinding{} + err = c.client.Put(). + Namespace(c.ns). + Resource("sinkbindings"). + Name(sinkBinding.Name). + SubResource("status"). + Body(sinkBinding). + Do(). + Into(result) + return +} + +// Delete takes name of the sinkBinding and deletes it. Returns an error if one occurs. +func (c *sinkBindings) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("sinkbindings"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *sinkBindings) 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("sinkbindings"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched sinkBinding. +func (c *sinkBindings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.SinkBinding, err error) { + result = &v1alpha1.SinkBinding{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("sinkbindings"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go new file mode 100644 index 0000000000..c862359f19 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/sources_client.go @@ -0,0 +1,94 @@ +/* +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 v1alpha1 + +import ( + rest "k8s.io/client-go/rest" + v1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type SourcesV1alpha1Interface interface { + RESTClient() rest.Interface + ApiServerSourcesGetter + SinkBindingsGetter +} + +// SourcesV1alpha1Client is used to interact with features provided by the sources.knative.dev group. +type SourcesV1alpha1Client struct { + restClient rest.Interface +} + +func (c *SourcesV1alpha1Client) ApiServerSources(namespace string) ApiServerSourceInterface { + return newApiServerSources(c, namespace) +} + +func (c *SourcesV1alpha1Client) SinkBindings(namespace string) SinkBindingInterface { + return newSinkBindings(c, namespace) +} + +// NewForConfig creates a new SourcesV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*SourcesV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &SourcesV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new SourcesV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SourcesV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SourcesV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *SourcesV1alpha1Client { + return &SourcesV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.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 *SourcesV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 33a3c4ad1a..41071a535f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -654,6 +654,8 @@ knative.dev/eventing/pkg/apis/sources/v1alpha1 knative.dev/eventing/pkg/client/clientset/versioned/scheme knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1 knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake +knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1 +knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake knative.dev/eventing/pkg/legacyclient/clientset/versioned/scheme knative.dev/eventing/pkg/legacyclient/clientset/versioned/typed/legacysources/v1alpha1 knative.dev/eventing/pkg/legacyclient/clientset/versioned/typed/legacysources/v1alpha1/fake