diff --git a/Gopkg.lock b/Gopkg.lock index bd83dfd89a0..ebe347a97c4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -26,6 +26,12 @@ packages = ["quantile"] revision = "3a771d992973f24aa725d07868b467d1ddfceafb" +[[projects]] + name = "github.com/codegangsta/inject" + packages = ["."] + revision = "37d7f8432a3e684eef9b2edece76bdfa6ac85b39" + version = "v1.0-rc1" + [[projects]] name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -92,6 +98,12 @@ revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" +[[projects]] + name = "github.com/go-martini/martini" + packages = ["."] + revision = "49411a5b646861ad29a6ddd5351717a0a9c49b94" + version = "v1.0" + [[projects]] name = "github.com/gogo/protobuf" packages = [ @@ -861,6 +873,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "0caaeabdd984ed27d80935dd80da631c3bc23644e5de6d1bab51f5be748d6fd5" + inputs-digest = "909eb15dbf4a019750628971a06bf6d44b9bbdad666373472c2f5f08538c3b50" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 6e8e0952c1a..d4ba762c0b8 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -36,6 +36,8 @@ import ( informers "github.com/knative/eventing/pkg/client/informers/externalversions" "github.com/knative/eventing/pkg/controller" "github.com/knative/eventing/pkg/controller/bind" + "github.com/knative/eventing/pkg/controller/bus" + "github.com/knative/eventing/pkg/controller/channel" "github.com/knative/eventing/pkg/signals" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -85,6 +87,8 @@ func main() { // Add new controllers here. ctors := []controller.Constructor{ bind.NewController, + bus.NewController, + channel.NewController, } // Build all of our controllers, with the clients constructed above. diff --git a/cmd/stub-bus/main.go b/cmd/stub-bus/main.go new file mode 100644 index 00000000000..c7009378f03 --- /dev/null +++ b/cmd/stub-bus/main.go @@ -0,0 +1,161 @@ +/* + * Copyright 2018 the original author or 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 main + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os" + "strings" + "time" + + "github.com/go-martini/martini" + "github.com/golang/glog" + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + clientset "github.com/knative/eventing/pkg/client/clientset/versioned" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + "github.com/knative/eventing/pkg/signals" + "github.com/knative/eventing/pkg/subscription" + "k8s.io/client-go/tools/clientcmd" +) + +var ( + masterURL string + kubeconfig string + + bus = os.Getenv("BUS_NAME") + forwardHeaders = []string{ + "content-type", + "x-request-id", + "x-b3-traceid", + "x-b3-spanid", + "x-b3-parentspanid", + "x-b3-sampled", + "x-b3-flags", + "x-ot-span-context", + } +) + +func splitChannelName(host string) (string, string) { + chunks := strings.Split(host, ".") + channel := chunks[0] + namespace := chunks[1] + return channel, namespace +} + +func main() { + flag.Parse() + + // set up signals so we handle the first shutdown signal gracefully + stopCh := signals.SetupSignalHandler() + + cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig) + if err != nil { + glog.Fatalf("Error building kubeconfig: %s", err.Error()) + } + + client, err := clientset.NewForConfig(cfg) + if err != nil { + glog.Fatalf("Error building clientset: %s", err.Error()) + } + + informerFactory := informers.NewSharedInformerFactory(client, time.Second*30) + monitor := subscription.NewMonitor(bus, informerFactory, subscription.MonitorEventHandlerFuncs{ + ProvisionFunc: func(channel channelsv1alpha1.Channel) { + glog.Infof("Provision channel %q\n", channel.Name) + }, + UnprovisionFunc: func(channel channelsv1alpha1.Channel) { + glog.Infof("Unprovision channel %q\n", channel.Name) + }, + SubscribeFunc: func(subscription channelsv1alpha1.Subscription) { + glog.Infof("Subscribe %q to %q channel\n", subscription.Spec.Subscriber, subscription.Spec.Channel) + }, + UnsubscribeFunc: func(subscription channelsv1alpha1.Subscription) { + glog.Infof("Unubscribe %q from %q channel\n", subscription.Spec.Subscriber, subscription.Spec.Channel) + }, + }) + go informerFactory.Start(stopCh) + + m := createServer(monitor) + m.Run() + + glog.Flush() +} + +func createServer(monitor *subscription.Monitor) *martini.ClassicMartini { + m := martini.Classic() + + m.Post("/", func(req *http.Request, res http.ResponseWriter) { + host := req.Host + glog.Infof("Recieved request for %s\n", host) + channel, namespace := splitChannelName(host) + subscriptions := monitor.Subscriptions(channel, namespace) + if subscriptions == nil { + res.WriteHeader(http.StatusNotFound) + return + } + + body, err := ioutil.ReadAll(req.Body) + if err != nil { + res.WriteHeader(http.StatusInternalServerError) + return + } + + res.WriteHeader(http.StatusAccepted) + go func() { + if len(*subscriptions) == 0 { + glog.Warningf("No subscribers for channel %q\n", channel) + } + + // make upstream requests + client := &http.Client{} + + for _, subscription := range *subscriptions { + go func(subscriber string) { + glog.Infof("Sending to %q for %q\n", subscriber, channel) + + url := fmt.Sprintf("http://%s/", subscriber) + request, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + glog.Errorf("Unable to create subscriber request %v", err) + } + request.Header.Set("x-bus", bus) + request.Header.Set("x-channel", channel) + for _, header := range forwardHeaders { + if value := req.Header.Get(header); value != "" { + request.Header.Set(header, value) + } + } + _, err = client.Do(request) + if err != nil { + glog.Errorf("Unable to complete subscriber request %v", err) + } + }(subscription.Subscriber) + } + }() + }) + + return m +} + +func init() { + flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") + flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") +} diff --git a/config/bus.yaml b/config/bus.yaml new file mode 100644 index 00000000000..70a192772af --- /dev/null +++ b/config/bus.yaml @@ -0,0 +1,25 @@ +# Copyright 2018 Google, Inc. All rights reserved. +# +# 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. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: buses.channels.knative.dev +spec: + scope: Namespaced + group: channels.knative.dev + version: v1alpha1 + names: + kind: Bus + plural: buses + singular: bus diff --git a/config/buses/stub.yaml b/config/buses/stub.yaml new file mode 100644 index 00000000000..80d39ac2c01 --- /dev/null +++ b/config/buses/stub.yaml @@ -0,0 +1,25 @@ +# Copyright 2018 Google, Inc. All rights reserved. +# +# 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. +apiVersion: channels.knative.dev/v1alpha1 +kind: Bus +metadata: + name: stub +spec: + dispatcher: + name: dispatcher + image: github.com/knative/eventing/cmd/stub-bus + args: [ + "-logtostderr", + "-stderrthreshold", "INFO", + ] diff --git a/config/channel.yaml b/config/channel.yaml new file mode 100644 index 00000000000..c56a3489226 --- /dev/null +++ b/config/channel.yaml @@ -0,0 +1,25 @@ +# Copyright 2018 Google, Inc. All rights reserved. +# +# 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. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: channels.channels.knative.dev +spec: + scope: Namespaced + group: channels.knative.dev + version: v1alpha1 + names: + kind: Channel + plural: channels + singular: channel diff --git a/config/clusterrole.yaml b/config/clusterrole.yaml new file mode 100644 index 00000000000..5e37fa384c5 --- /dev/null +++ b/config/clusterrole.yaml @@ -0,0 +1,21 @@ +# Copyright 2018 Google, Inc. All rights reserved. +# +# 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. +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: knative-channels-bus +rules: +- apiGroups: ["channels.knative.dev"] + resources: ["buses", "channels", "subscriptions"] + verbs: ["get", "watch", "list"] \ No newline at end of file diff --git a/config/subscription.yaml b/config/subscription.yaml new file mode 100644 index 00000000000..8b98f72dafe --- /dev/null +++ b/config/subscription.yaml @@ -0,0 +1,25 @@ +# Copyright 2018 Google, Inc. All rights reserved. +# +# 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. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: subscriptions.channels.knative.dev +spec: + scope: Namespaced + group: channels.knative.dev + version: v1alpha1 + names: + kind: Subscription + plural: subscriptions + singular: subscription diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 6428912fdee..b560c3cf9f2 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -27,7 +27,7 @@ CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-ge # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ github.com/knative/eventing/pkg/client github.com/knative/eventing/pkg/apis \ - feeds:v1alpha1 \ + "channels:v1alpha1 feeds:v1alpha1 istio:v1alpha2" \ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/channels/register.go b/pkg/apis/channels/register.go new file mode 100644 index 00000000000..cf684d5ac44 --- /dev/null +++ b/pkg/apis/channels/register.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 channels + +const ( + GroupName = "channels.knative.dev" +) diff --git a/pkg/apis/channels/v1alpha1/bus_types.go b/pkg/apis/channels/v1alpha1/bus_types.go new file mode 100644 index 00000000000..de9635baa7f --- /dev/null +++ b/pkg/apis/channels/v1alpha1/bus_types.go @@ -0,0 +1,61 @@ +/* + * Copyright 2018 the original author or 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 ( + kapi "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// Bus represents the buses.channels.knative.dev CRD +type Bus struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + Spec BusSpec `json:"spec"` + Status *BusStatus `json:"status,omitempty"` +} + +// BusSpec (what the user wants) for a bus +type BusSpec struct { + + // Parameters configuration params for the bus + Parameters *[]Parameter `json:"parameters,omitempty"` + + // Provisioner container definition to manage channels on the bus. + Provisioner *kapi.Container `json:"provisioner,omitempty"` + + // Dispatcher container definition to use for the bus data plane. + Dispatcher kapi.Container `json:"dispatcher"` +} + +// BusStatus (computed) for a bus +type BusStatus struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BusList returned in list operations +type BusList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []Bus `json:"items"` +} diff --git a/pkg/apis/channels/v1alpha1/channel_types.go b/pkg/apis/channels/v1alpha1/channel_types.go new file mode 100644 index 00000000000..85d0d8adabe --- /dev/null +++ b/pkg/apis/channels/v1alpha1/channel_types.go @@ -0,0 +1,60 @@ +/* + * Copyright 2018 the original author or 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 ( + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// Channel represents the channels.channels.knative.dev CRD +type Channel struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + Spec ChannelSpec `json:"spec"` + Status *ChannelStatus `json:"status,omitempty"` +} + +// ChannelSpec (what the user wants) for a channel +type ChannelSpec struct { + + // Name of the bus backing this channel (optional) + Bus string + + // Arguments configuration arguments for the bus + Arguments *[]Argument `json:"arguments,omitempty"` + + // Parameters configuration params for the channel + Parameters *[]Parameter `json:"parameters,omitempty"` +} + +// ChannelStatus (computed) for a channel +type ChannelStatus struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ChannelList returned in list operations +type ChannelList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []Channel `json:"items"` +} diff --git a/pkg/apis/channels/v1alpha1/doc.go b/pkg/apis/channels/v1alpha1/doc.go new file mode 100644 index 00000000000..6433304c238 --- /dev/null +++ b/pkg/apis/channels/v1alpha1/doc.go @@ -0,0 +1,16 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. +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. +*/ +// +k8s:deepcopy-gen=package +// Package v1alpha1 is the v1alpha1 version of the API. +// +groupName=channels.knative.dev +package v1alpha1 diff --git a/pkg/apis/channels/v1alpha1/param_types.go b/pkg/apis/channels/v1alpha1/param_types.go new file mode 100644 index 00000000000..fbababf4ee5 --- /dev/null +++ b/pkg/apis/channels/v1alpha1/param_types.go @@ -0,0 +1,37 @@ +/* + * Copyright 2018 the original author or 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 + +// inspired by the parameter/argument from buildtemplate/build + +// Parameter a named parameter that may be defined +type Parameter struct { + // Name parameter to apply + Name string `json:"name"` + + // Description human friendly description of the parameter + Description string `json:"description"` + + // Default (optional) value to use if not explicitly set + Default *string `json:"default,omitempty"` +} + +// Argument a value for a named parameter +type Argument struct { + Name string `json:"name"` + Value string `json:"value"` +} diff --git a/pkg/apis/channels/v1alpha1/register.go b/pkg/apis/channels/v1alpha1/register.go new file mode 100644 index 00000000000..8367d9dab86 --- /dev/null +++ b/pkg/apis/channels/v1alpha1/register.go @@ -0,0 +1,57 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + "github.com/knative/eventing/pkg/apis/channels" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: channels.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Bus{}, + &BusList{}, + &Channel{}, + &ChannelList{}, + &Subscription{}, + &SubscriptionList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/channels/v1alpha1/subscription_types.go b/pkg/apis/channels/v1alpha1/subscription_types.go new file mode 100644 index 00000000000..19ea529978b --- /dev/null +++ b/pkg/apis/channels/v1alpha1/subscription_types.go @@ -0,0 +1,60 @@ +/* + * Copyright 2018 the original author or 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 ( + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// Subscription represents the subscriptions.channels.knative.dev CRD +type Subscription struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + Spec SubscriptionSpec `json:"spec"` + Status *SubscriptionStatus `json:"status,omitempty"` +} + +// SubscriptionSpec (what the user wants) for a subscription +type SubscriptionSpec struct { + + // Name of the channel to subscribe to + Channel string `json:"channel"` + + // Name of the subscriber service + Subscriber string `json:"subscriber"` + + // Arguments for the channel + Arguments *[]Argument `json:"arguments,omitempty"` +} + +// SubscriptionStatus (computed) for a subscription +type SubscriptionStatus struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SubscriptionList returned in list operations +type SubscriptionList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []Subscription `json:"items"` +} diff --git a/pkg/apis/channels/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/channels/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..33aac9e1ee5 --- /dev/null +++ b/pkg/apis/channels/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,436 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Argument) DeepCopyInto(out *Argument) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Argument. +func (in *Argument) DeepCopy() *Argument { + if in == nil { + return nil + } + out := new(Argument) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Bus) DeepCopyInto(out *Bus) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + if *in == nil { + *out = nil + } else { + *out = new(BusStatus) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bus. +func (in *Bus) DeepCopy() *Bus { + if in == nil { + return nil + } + out := new(Bus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Bus) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BusList) DeepCopyInto(out *BusList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Bus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BusList. +func (in *BusList) DeepCopy() *BusList { + if in == nil { + return nil + } + out := new(BusList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BusList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BusSpec) DeepCopyInto(out *BusSpec) { + *out = *in + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + if *in == nil { + *out = nil + } else { + *out = new([]Parameter) + if **in != nil { + in, out := *in, *out + *out = make([]Parameter, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } + } + if in.Provisioner != nil { + in, out := &in.Provisioner, &out.Provisioner + if *in == nil { + *out = nil + } else { + *out = new(v1.Container) + (*in).DeepCopyInto(*out) + } + } + in.Dispatcher.DeepCopyInto(&out.Dispatcher) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BusSpec. +func (in *BusSpec) DeepCopy() *BusSpec { + if in == nil { + return nil + } + out := new(BusSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BusStatus) DeepCopyInto(out *BusStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BusStatus. +func (in *BusStatus) DeepCopy() *BusStatus { + if in == nil { + return nil + } + out := new(BusStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Channel) DeepCopyInto(out *Channel) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + if *in == nil { + *out = nil + } else { + *out = new(ChannelStatus) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Channel. +func (in *Channel) DeepCopy() *Channel { + if in == nil { + return nil + } + out := new(Channel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Channel) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelList) DeepCopyInto(out *ChannelList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Channel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelList. +func (in *ChannelList) DeepCopy() *ChannelList { + if in == nil { + return nil + } + out := new(ChannelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ChannelList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelSpec) DeepCopyInto(out *ChannelSpec) { + *out = *in + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + if *in == nil { + *out = nil + } else { + *out = new([]Argument) + if **in != nil { + in, out := *in, *out + *out = make([]Argument, len(*in)) + copy(*out, *in) + } + } + } + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + if *in == nil { + *out = nil + } else { + *out = new([]Parameter) + if **in != nil { + in, out := *in, *out + *out = make([]Parameter, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelSpec. +func (in *ChannelSpec) DeepCopy() *ChannelSpec { + if in == nil { + return nil + } + out := new(ChannelSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelStatus) DeepCopyInto(out *ChannelStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelStatus. +func (in *ChannelStatus) DeepCopy() *ChannelStatus { + if in == nil { + return nil + } + out := new(ChannelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Parameter) DeepCopyInto(out *Parameter) { + *out = *in + if in.Default != nil { + in, out := &in.Default, &out.Default + if *in == nil { + *out = nil + } else { + *out = new(string) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Parameter. +func (in *Parameter) DeepCopy() *Parameter { + if in == nil { + return nil + } + out := new(Parameter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subscription) DeepCopyInto(out *Subscription) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + if *in == nil { + *out = nil + } else { + *out = new(SubscriptionStatus) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subscription. +func (in *Subscription) DeepCopy() *Subscription { + if in == nil { + return nil + } + out := new(Subscription) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Subscription) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriptionList) DeepCopyInto(out *SubscriptionList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Subscription, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionList. +func (in *SubscriptionList) DeepCopy() *SubscriptionList { + if in == nil { + return nil + } + out := new(SubscriptionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubscriptionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriptionSpec) DeepCopyInto(out *SubscriptionSpec) { + *out = *in + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + if *in == nil { + *out = nil + } else { + *out = new([]Argument) + if **in != nil { + in, out := *in, *out + *out = make([]Argument, len(*in)) + copy(*out, *in) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionSpec. +func (in *SubscriptionSpec) DeepCopy() *SubscriptionSpec { + if in == nil { + return nil + } + out := new(SubscriptionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriptionStatus) DeepCopyInto(out *SubscriptionStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionStatus. +func (in *SubscriptionStatus) DeepCopy() *SubscriptionStatus { + if in == nil { + return nil + } + out := new(SubscriptionStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/istio/register.go b/pkg/apis/istio/register.go new file mode 100644 index 00000000000..4d6c0404047 --- /dev/null +++ b/pkg/apis/istio/register.go @@ -0,0 +1,23 @@ +/* + * Copyright 2018 the original author or 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 istio + +// TODO remove package after knative/serving#1002 + +const ( + GroupName = "config.istio.io" +) diff --git a/pkg/apis/istio/v1alpha2/doc.go b/pkg/apis/istio/v1alpha2/doc.go new file mode 100644 index 00000000000..424f9e1233d --- /dev/null +++ b/pkg/apis/istio/v1alpha2/doc.go @@ -0,0 +1,20 @@ +/* + * Copyright 2018 the original author or 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. + */ + +// +k8s:deepcopy-gen=package +// HACK to enable k8s go client for RouteRule resources +// +groupName=config.istio.io +package v1alpha2 diff --git a/pkg/apis/istio/v1alpha2/register.go b/pkg/apis/istio/v1alpha2/register.go new file mode 100644 index 00000000000..d65eae0097d --- /dev/null +++ b/pkg/apis/istio/v1alpha2/register.go @@ -0,0 +1,56 @@ +/* + * Copyright 2018 the original author or 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 v1alpha2 + +import ( + "github.com/knative/eventing/pkg/apis/istio" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: istio.GroupName, Version: "v1alpha2"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &RouteRule{}, + &RouteRuleList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/istio/v1alpha2/routerule.go b/pkg/apis/istio/v1alpha2/routerule.go new file mode 100644 index 00000000000..3656dd1e42b --- /dev/null +++ b/pkg/apis/istio/v1alpha2/routerule.go @@ -0,0 +1,72 @@ +/* + * Copyright 2018 the original author or 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 v1alpha2 + +import ( + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// RouteRule HACK +type RouteRule struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata"` + Spec RouteRuleSpec `json:"spec"` + Status *RouteRuleStatus `json:"status,omitempty"` +} + +// RouteRuleSpec HACK +type RouteRuleSpec struct { + Destination IstioService `json:"destination"` + Route []DestinationWeight `json:"route"` + Rewrite HTTPRewrite `json:"rewrite"` +} + +// IstioService HACK +type IstioService struct { + Domain string `json:"domain"` + Name string `json:"name"` + Namespace string `json:"namespace"` +} + +// DestinationWeight HACK +type DestinationWeight struct { + Destination IstioService `json:"destination"` + Weight int32 `json:"weight"` +} + +// HTTPRewrite HACK +type HTTPRewrite struct { + Authority string `json:"authority"` +} + +// RouteRuleStatus HACK +type RouteRuleStatus struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// HACK +type RouteRuleList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata"` + Items []RouteRule `json:"items"` +} diff --git a/pkg/apis/istio/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/istio/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 00000000000..c66ed208c91 --- /dev/null +++ b/pkg/apis/istio/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,182 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 deepcopy-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DestinationWeight) DeepCopyInto(out *DestinationWeight) { + *out = *in + out.Destination = in.Destination + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DestinationWeight. +func (in *DestinationWeight) DeepCopy() *DestinationWeight { + if in == nil { + return nil + } + out := new(DestinationWeight) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPRewrite) DeepCopyInto(out *HTTPRewrite) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRewrite. +func (in *HTTPRewrite) DeepCopy() *HTTPRewrite { + if in == nil { + return nil + } + out := new(HTTPRewrite) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IstioService) DeepCopyInto(out *IstioService) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IstioService. +func (in *IstioService) DeepCopy() *IstioService { + if in == nil { + return nil + } + out := new(IstioService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteRule) DeepCopyInto(out *RouteRule) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + if *in == nil { + *out = nil + } else { + *out = new(RouteRuleStatus) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRule. +func (in *RouteRule) DeepCopy() *RouteRule { + if in == nil { + return nil + } + out := new(RouteRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouteRule) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteRuleList) DeepCopyInto(out *RouteRuleList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RouteRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRuleList. +func (in *RouteRuleList) DeepCopy() *RouteRuleList { + if in == nil { + return nil + } + out := new(RouteRuleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouteRuleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteRuleSpec) DeepCopyInto(out *RouteRuleSpec) { + *out = *in + out.Destination = in.Destination + if in.Route != nil { + in, out := &in.Route, &out.Route + *out = make([]DestinationWeight, len(*in)) + copy(*out, *in) + } + out.Rewrite = in.Rewrite + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRuleSpec. +func (in *RouteRuleSpec) DeepCopy() *RouteRuleSpec { + if in == nil { + return nil + } + out := new(RouteRuleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteRuleStatus) DeepCopyInto(out *RouteRuleStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRuleStatus. +func (in *RouteRuleStatus) DeepCopy() *RouteRuleStatus { + if in == nil { + return nil + } + out := new(RouteRuleStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/istio/v1alpha2/zz_generated.defaults.go b/pkg/apis/istio/v1alpha2/zz_generated.defaults.go new file mode 100644 index 00000000000..58996627546 --- /dev/null +++ b/pkg/apis/istio/v1alpha2/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* + * Copyright 2018 the original author or 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. + */ + +// This file was autogenerated by defaulter-gen. Do not edit it manually! + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 4df7b1e781f..5bf30f4e848 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -20,7 +20,9 @@ package versioned import ( glog "github.com/golang/glog" + channelsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/channels/v1alpha1" feedsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/feeds/v1alpha1" + configv1alpha2 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/istio/v1alpha2" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -28,16 +30,35 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + ChannelsV1alpha1() channelsv1alpha1.ChannelsV1alpha1Interface + // Deprecated: please explicitly pick a version if possible. + Channels() channelsv1alpha1.ChannelsV1alpha1Interface FeedsV1alpha1() feedsv1alpha1.FeedsV1alpha1Interface // Deprecated: please explicitly pick a version if possible. Feeds() feedsv1alpha1.FeedsV1alpha1Interface + ConfigV1alpha2() configv1alpha2.ConfigV1alpha2Interface + // Deprecated: please explicitly pick a version if possible. + Config() configv1alpha2.ConfigV1alpha2Interface } // Clientset contains the clients for groups. Each group has exactly one // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - feedsV1alpha1 *feedsv1alpha1.FeedsV1alpha1Client + channelsV1alpha1 *channelsv1alpha1.ChannelsV1alpha1Client + feedsV1alpha1 *feedsv1alpha1.FeedsV1alpha1Client + configV1alpha2 *configv1alpha2.ConfigV1alpha2Client +} + +// ChannelsV1alpha1 retrieves the ChannelsV1alpha1Client +func (c *Clientset) ChannelsV1alpha1() channelsv1alpha1.ChannelsV1alpha1Interface { + return c.channelsV1alpha1 +} + +// Deprecated: Channels retrieves the default version of ChannelsClient. +// Please explicitly pick a version. +func (c *Clientset) Channels() channelsv1alpha1.ChannelsV1alpha1Interface { + return c.channelsV1alpha1 } // FeedsV1alpha1 retrieves the FeedsV1alpha1Client @@ -51,6 +72,17 @@ func (c *Clientset) Feeds() feedsv1alpha1.FeedsV1alpha1Interface { return c.feedsV1alpha1 } +// ConfigV1alpha2 retrieves the ConfigV1alpha2Client +func (c *Clientset) ConfigV1alpha2() configv1alpha2.ConfigV1alpha2Interface { + return c.configV1alpha2 +} + +// Deprecated: Config retrieves the default version of ConfigClient. +// Please explicitly pick a version. +func (c *Clientset) Config() configv1alpha2.ConfigV1alpha2Interface { + return c.configV1alpha2 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -67,10 +99,18 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error + cs.channelsV1alpha1, err = channelsv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.feedsV1alpha1, err = feedsv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err } + cs.configV1alpha2, err = configv1alpha2.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { @@ -84,7 +124,9 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset + cs.channelsV1alpha1 = channelsv1alpha1.NewForConfigOrDie(c) cs.feedsV1alpha1 = feedsv1alpha1.NewForConfigOrDie(c) + cs.configV1alpha2 = configv1alpha2.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -93,7 +135,9 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.channelsV1alpha1 = channelsv1alpha1.New(c) cs.feedsV1alpha1 = feedsv1alpha1.New(c) + cs.configV1alpha2 = configv1alpha2.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index c864b91b39e..9fb3afde711 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -20,8 +20,12 @@ package fake import ( clientset "github.com/knative/eventing/pkg/client/clientset/versioned" + channelsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/channels/v1alpha1" + fakechannelsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake" feedsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/feeds/v1alpha1" fakefeedsv1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/feeds/v1alpha1/fake" + configv1alpha2 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/istio/v1alpha2" + fakeconfigv1alpha2 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -70,6 +74,16 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} +// ChannelsV1alpha1 retrieves the ChannelsV1alpha1Client +func (c *Clientset) ChannelsV1alpha1() channelsv1alpha1.ChannelsV1alpha1Interface { + return &fakechannelsv1alpha1.FakeChannelsV1alpha1{Fake: &c.Fake} +} + +// Channels retrieves the ChannelsV1alpha1Client +func (c *Clientset) Channels() channelsv1alpha1.ChannelsV1alpha1Interface { + return &fakechannelsv1alpha1.FakeChannelsV1alpha1{Fake: &c.Fake} +} + // FeedsV1alpha1 retrieves the FeedsV1alpha1Client func (c *Clientset) FeedsV1alpha1() feedsv1alpha1.FeedsV1alpha1Interface { return &fakefeedsv1alpha1.FakeFeedsV1alpha1{Fake: &c.Fake} @@ -79,3 +93,13 @@ func (c *Clientset) FeedsV1alpha1() feedsv1alpha1.FeedsV1alpha1Interface { func (c *Clientset) Feeds() feedsv1alpha1.FeedsV1alpha1Interface { return &fakefeedsv1alpha1.FakeFeedsV1alpha1{Fake: &c.Fake} } + +// ConfigV1alpha2 retrieves the ConfigV1alpha2Client +func (c *Clientset) ConfigV1alpha2() configv1alpha2.ConfigV1alpha2Interface { + return &fakeconfigv1alpha2.FakeConfigV1alpha2{Fake: &c.Fake} +} + +// Config retrieves the ConfigV1alpha2Client +func (c *Clientset) Config() configv1alpha2.ConfigV1alpha2Interface { + return &fakeconfigv1alpha2.FakeConfigV1alpha2{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 791b9c08f8d..65b8ac72114 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -19,7 +19,9 @@ limitations under the License. package fake import ( + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" feedsv1alpha1 "github.com/knative/eventing/pkg/apis/feeds/v1alpha1" + configv1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -50,5 +52,7 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { + channelsv1alpha1.AddToScheme(scheme) feedsv1alpha1.AddToScheme(scheme) + configv1alpha2.AddToScheme(scheme) } diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index d31256e692c..b3a31a8cfc2 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -19,7 +19,9 @@ limitations under the License. package scheme import ( + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" feedsv1alpha1 "github.com/knative/eventing/pkg/apis/feeds/v1alpha1" + configv1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -50,5 +52,7 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { + channelsv1alpha1.AddToScheme(scheme) feedsv1alpha1.AddToScheme(scheme) + configv1alpha2.AddToScheme(scheme) } diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/bus.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/bus.go new file mode 100644 index 00000000000..fa493dbdf16 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/bus.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + 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" +) + +// BusesGetter has a method to return a BusInterface. +// A group's client should implement this interface. +type BusesGetter interface { + Buses(namespace string) BusInterface +} + +// BusInterface has methods to work with Bus resources. +type BusInterface interface { + Create(*v1alpha1.Bus) (*v1alpha1.Bus, error) + Update(*v1alpha1.Bus) (*v1alpha1.Bus, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Bus, error) + List(opts v1.ListOptions) (*v1alpha1.BusList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bus, err error) + BusExpansion +} + +// buses implements BusInterface +type buses struct { + client rest.Interface + ns string +} + +// newBuses returns a Buses +func newBuses(c *ChannelsV1alpha1Client, namespace string) *buses { + return &buses{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the bus, and returns the corresponding bus object, and an error if there is any. +func (c *buses) Get(name string, options v1.GetOptions) (result *v1alpha1.Bus, err error) { + result = &v1alpha1.Bus{} + err = c.client.Get(). + Namespace(c.ns). + Resource("buses"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Buses that match those selectors. +func (c *buses) List(opts v1.ListOptions) (result *v1alpha1.BusList, err error) { + result = &v1alpha1.BusList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("buses"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested buses. +func (c *buses) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("buses"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a bus and creates it. Returns the server's representation of the bus, and an error, if there is any. +func (c *buses) Create(bus *v1alpha1.Bus) (result *v1alpha1.Bus, err error) { + result = &v1alpha1.Bus{} + err = c.client.Post(). + Namespace(c.ns). + Resource("buses"). + Body(bus). + Do(). + Into(result) + return +} + +// Update takes the representation of a bus and updates it. Returns the server's representation of the bus, and an error, if there is any. +func (c *buses) Update(bus *v1alpha1.Bus) (result *v1alpha1.Bus, err error) { + result = &v1alpha1.Bus{} + err = c.client.Put(). + Namespace(c.ns). + Resource("buses"). + Name(bus.Name). + Body(bus). + Do(). + Into(result) + return +} + +// Delete takes name of the bus and deletes it. Returns an error if one occurs. +func (c *buses) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("buses"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *buses) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("buses"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched bus. +func (c *buses) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bus, err error) { + result = &v1alpha1.Bus{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("buses"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/channel.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/channel.go new file mode 100644 index 00000000000..f388a2bf52f --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/channel.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + 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" +) + +// ChannelsGetter has a method to return a ChannelInterface. +// A group's client should implement this interface. +type ChannelsGetter interface { + Channels(namespace string) ChannelInterface +} + +// ChannelInterface has methods to work with Channel resources. +type ChannelInterface interface { + Create(*v1alpha1.Channel) (*v1alpha1.Channel, error) + Update(*v1alpha1.Channel) (*v1alpha1.Channel, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Channel, error) + List(opts v1.ListOptions) (*v1alpha1.ChannelList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Channel, err error) + ChannelExpansion +} + +// channels implements ChannelInterface +type channels struct { + client rest.Interface + ns string +} + +// newChannels returns a Channels +func newChannels(c *ChannelsV1alpha1Client, namespace string) *channels { + return &channels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the channel, and returns the corresponding channel object, and an error if there is any. +func (c *channels) Get(name string, options v1.GetOptions) (result *v1alpha1.Channel, err error) { + result = &v1alpha1.Channel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Channels that match those selectors. +func (c *channels) List(opts v1.ListOptions) (result *v1alpha1.ChannelList, err error) { + result = &v1alpha1.ChannelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested channels. +func (c *channels) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a channel and creates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Create(channel *v1alpha1.Channel) (result *v1alpha1.Channel, err error) { + result = &v1alpha1.Channel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("channels"). + Body(channel). + Do(). + Into(result) + return +} + +// Update takes the representation of a channel and updates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Update(channel *v1alpha1.Channel) (result *v1alpha1.Channel, err error) { + result = &v1alpha1.Channel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("channels"). + Name(channel.Name). + Body(channel). + Do(). + Into(result) + return +} + +// Delete takes name of the channel and deletes it. Returns an error if one occurs. +func (c *channels) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("channels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *channels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched channel. +func (c *channels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Channel, err error) { + result = &v1alpha1.Channel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("channels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/channels_client.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/channels_client.go new file mode 100644 index 00000000000..bb5776fa3b5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/channels_client.go @@ -0,0 +1,100 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type ChannelsV1alpha1Interface interface { + RESTClient() rest.Interface + BusesGetter + ChannelsGetter + SubscriptionsGetter +} + +// ChannelsV1alpha1Client is used to interact with features provided by the channels.knative.dev group. +type ChannelsV1alpha1Client struct { + restClient rest.Interface +} + +func (c *ChannelsV1alpha1Client) Buses(namespace string) BusInterface { + return newBuses(c, namespace) +} + +func (c *ChannelsV1alpha1Client) Channels(namespace string) ChannelInterface { + return newChannels(c, namespace) +} + +func (c *ChannelsV1alpha1Client) Subscriptions(namespace string) SubscriptionInterface { + return newSubscriptions(c, namespace) +} + +// NewForConfig creates a new ChannelsV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*ChannelsV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ChannelsV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ChannelsV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ChannelsV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ChannelsV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *ChannelsV1alpha1Client { + return &ChannelsV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + 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 *ChannelsV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/doc.go new file mode 100644 index 00000000000..1d8f2a89974 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/doc.go new file mode 100644 index 00000000000..2195046d473 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_bus.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_bus.go new file mode 100644 index 00000000000..e7e85412d6d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_bus.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + 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" +) + +// FakeBuses implements BusInterface +type FakeBuses struct { + Fake *FakeChannelsV1alpha1 + ns string +} + +var busesResource = schema.GroupVersionResource{Group: "channels.knative.dev", Version: "v1alpha1", Resource: "buses"} + +var busesKind = schema.GroupVersionKind{Group: "channels.knative.dev", Version: "v1alpha1", Kind: "Bus"} + +// Get takes name of the bus, and returns the corresponding bus object, and an error if there is any. +func (c *FakeBuses) Get(name string, options v1.GetOptions) (result *v1alpha1.Bus, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(busesResource, c.ns, name), &v1alpha1.Bus{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Bus), err +} + +// List takes label and field selectors, and returns the list of Buses that match those selectors. +func (c *FakeBuses) List(opts v1.ListOptions) (result *v1alpha1.BusList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(busesResource, busesKind, c.ns, opts), &v1alpha1.BusList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BusList{} + for _, item := range obj.(*v1alpha1.BusList).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 buses. +func (c *FakeBuses) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(busesResource, c.ns, opts)) + +} + +// Create takes the representation of a bus and creates it. Returns the server's representation of the bus, and an error, if there is any. +func (c *FakeBuses) Create(bus *v1alpha1.Bus) (result *v1alpha1.Bus, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(busesResource, c.ns, bus), &v1alpha1.Bus{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Bus), err +} + +// Update takes the representation of a bus and updates it. Returns the server's representation of the bus, and an error, if there is any. +func (c *FakeBuses) Update(bus *v1alpha1.Bus) (result *v1alpha1.Bus, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(busesResource, c.ns, bus), &v1alpha1.Bus{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Bus), err +} + +// Delete takes name of the bus and deletes it. Returns an error if one occurs. +func (c *FakeBuses) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(busesResource, c.ns, name), &v1alpha1.Bus{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBuses) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(busesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.BusList{}) + return err +} + +// Patch applies the patch and returns the patched bus. +func (c *FakeBuses) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bus, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(busesResource, c.ns, name, data, subresources...), &v1alpha1.Bus{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Bus), err +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channel.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channel.go new file mode 100644 index 00000000000..2b816cbcefd --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channel.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + 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" +) + +// FakeChannels implements ChannelInterface +type FakeChannels struct { + Fake *FakeChannelsV1alpha1 + ns string +} + +var channelsResource = schema.GroupVersionResource{Group: "channels.knative.dev", Version: "v1alpha1", Resource: "channels"} + +var channelsKind = schema.GroupVersionKind{Group: "channels.knative.dev", Version: "v1alpha1", Kind: "Channel"} + +// Get takes name of the channel, and returns the corresponding channel object, and an error if there is any. +func (c *FakeChannels) Get(name string, options v1.GetOptions) (result *v1alpha1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(channelsResource, c.ns, name), &v1alpha1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Channel), err +} + +// List takes label and field selectors, and returns the list of Channels that match those selectors. +func (c *FakeChannels) List(opts v1.ListOptions) (result *v1alpha1.ChannelList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(channelsResource, channelsKind, c.ns, opts), &v1alpha1.ChannelList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ChannelList{} + for _, item := range obj.(*v1alpha1.ChannelList).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 channels. +func (c *FakeChannels) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(channelsResource, c.ns, opts)) + +} + +// Create takes the representation of a channel and creates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *FakeChannels) Create(channel *v1alpha1.Channel) (result *v1alpha1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(channelsResource, c.ns, channel), &v1alpha1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Channel), err +} + +// Update takes the representation of a channel and updates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *FakeChannels) Update(channel *v1alpha1.Channel) (result *v1alpha1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(channelsResource, c.ns, channel), &v1alpha1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Channel), err +} + +// Delete takes name of the channel and deletes it. Returns an error if one occurs. +func (c *FakeChannels) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(channelsResource, c.ns, name), &v1alpha1.Channel{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeChannels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(channelsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ChannelList{}) + return err +} + +// Patch applies the patch and returns the patched channel. +func (c *FakeChannels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(channelsResource, c.ns, name, data, subresources...), &v1alpha1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Channel), err +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channels_client.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channels_client.go new file mode 100644 index 00000000000..6451375d5ce --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_channels_client.go @@ -0,0 +1,48 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/channels/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeChannelsV1alpha1 struct { + *testing.Fake +} + +func (c *FakeChannelsV1alpha1) Buses(namespace string) v1alpha1.BusInterface { + return &FakeBuses{c, namespace} +} + +func (c *FakeChannelsV1alpha1) Channels(namespace string) v1alpha1.ChannelInterface { + return &FakeChannels{c, namespace} +} + +func (c *FakeChannelsV1alpha1) Subscriptions(namespace string) v1alpha1.SubscriptionInterface { + return &FakeSubscriptions{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeChannelsV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_subscription.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_subscription.go new file mode 100644 index 00000000000..a4ef34488ca --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/fake/fake_subscription.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + 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" +) + +// FakeSubscriptions implements SubscriptionInterface +type FakeSubscriptions struct { + Fake *FakeChannelsV1alpha1 + ns string +} + +var subscriptionsResource = schema.GroupVersionResource{Group: "channels.knative.dev", Version: "v1alpha1", Resource: "subscriptions"} + +var subscriptionsKind = schema.GroupVersionKind{Group: "channels.knative.dev", Version: "v1alpha1", Kind: "Subscription"} + +// Get takes name of the subscription, and returns the corresponding subscription object, and an error if there is any. +func (c *FakeSubscriptions) Get(name string, options v1.GetOptions) (result *v1alpha1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(subscriptionsResource, c.ns, name), &v1alpha1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Subscription), err +} + +// List takes label and field selectors, and returns the list of Subscriptions that match those selectors. +func (c *FakeSubscriptions) List(opts v1.ListOptions) (result *v1alpha1.SubscriptionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(subscriptionsResource, subscriptionsKind, c.ns, opts), &v1alpha1.SubscriptionList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.SubscriptionList{} + for _, item := range obj.(*v1alpha1.SubscriptionList).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 subscriptions. +func (c *FakeSubscriptions) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(subscriptionsResource, c.ns, opts)) + +} + +// Create takes the representation of a subscription and creates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *FakeSubscriptions) Create(subscription *v1alpha1.Subscription) (result *v1alpha1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(subscriptionsResource, c.ns, subscription), &v1alpha1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Subscription), err +} + +// Update takes the representation of a subscription and updates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *FakeSubscriptions) Update(subscription *v1alpha1.Subscription) (result *v1alpha1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(subscriptionsResource, c.ns, subscription), &v1alpha1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Subscription), err +} + +// Delete takes name of the subscription and deletes it. Returns an error if one occurs. +func (c *FakeSubscriptions) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(subscriptionsResource, c.ns, name), &v1alpha1.Subscription{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSubscriptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(subscriptionsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.SubscriptionList{}) + return err +} + +// Patch applies the patch and returns the patched subscription. +func (c *FakeSubscriptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(subscriptionsResource, c.ns, name, data, subresources...), &v1alpha1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Subscription), err +} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/generated_expansion.go new file mode 100644 index 00000000000..003509217f6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/generated_expansion.go @@ -0,0 +1,25 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 BusExpansion interface{} + +type ChannelExpansion interface{} + +type SubscriptionExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/channels/v1alpha1/subscription.go b/pkg/client/clientset/versioned/typed/channels/v1alpha1/subscription.go new file mode 100644 index 00000000000..178561aaee4 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/channels/v1alpha1/subscription.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + 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" +) + +// SubscriptionsGetter has a method to return a SubscriptionInterface. +// A group's client should implement this interface. +type SubscriptionsGetter interface { + Subscriptions(namespace string) SubscriptionInterface +} + +// SubscriptionInterface has methods to work with Subscription resources. +type SubscriptionInterface interface { + Create(*v1alpha1.Subscription) (*v1alpha1.Subscription, error) + Update(*v1alpha1.Subscription) (*v1alpha1.Subscription, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Subscription, error) + List(opts v1.ListOptions) (*v1alpha1.SubscriptionList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Subscription, err error) + SubscriptionExpansion +} + +// subscriptions implements SubscriptionInterface +type subscriptions struct { + client rest.Interface + ns string +} + +// newSubscriptions returns a Subscriptions +func newSubscriptions(c *ChannelsV1alpha1Client, namespace string) *subscriptions { + return &subscriptions{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the subscription, and returns the corresponding subscription object, and an error if there is any. +func (c *subscriptions) Get(name string, options v1.GetOptions) (result *v1alpha1.Subscription, err error) { + result = &v1alpha1.Subscription{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Subscriptions that match those selectors. +func (c *subscriptions) List(opts v1.ListOptions) (result *v1alpha1.SubscriptionList, err error) { + result = &v1alpha1.SubscriptionList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested subscriptions. +func (c *subscriptions) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a subscription and creates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Create(subscription *v1alpha1.Subscription) (result *v1alpha1.Subscription, err error) { + result = &v1alpha1.Subscription{} + err = c.client.Post(). + Namespace(c.ns). + Resource("subscriptions"). + Body(subscription). + Do(). + Into(result) + return +} + +// Update takes the representation of a subscription and updates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Update(subscription *v1alpha1.Subscription) (result *v1alpha1.Subscription, err error) { + result = &v1alpha1.Subscription{} + err = c.client.Put(). + Namespace(c.ns). + Resource("subscriptions"). + Name(subscription.Name). + Body(subscription). + Do(). + Into(result) + return +} + +// Delete takes name of the subscription and deletes it. Returns an error if one occurs. +func (c *subscriptions) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *subscriptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched subscription. +func (c *subscriptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Subscription, err error) { + result = &v1alpha1.Subscription{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("subscriptions"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/doc.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/doc.go new file mode 100644 index 00000000000..e38ac2cb44e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 v1alpha2 diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/doc.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/doc.go new file mode 100644 index 00000000000..2195046d473 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_istio_client.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_istio_client.go new file mode 100644 index 00000000000..e6d53ea0f87 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_istio_client.go @@ -0,0 +1,40 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha2 "github.com/knative/eventing/pkg/client/clientset/versioned/typed/istio/v1alpha2" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeConfigV1alpha2 struct { + *testing.Fake +} + +func (c *FakeConfigV1alpha2) RouteRules(namespace string) v1alpha2.RouteRuleInterface { + return &FakeRouteRules{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeConfigV1alpha2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_routerule.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_routerule.go new file mode 100644 index 00000000000..2d3e2179751 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/fake/fake_routerule.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" + 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" +) + +// FakeRouteRules implements RouteRuleInterface +type FakeRouteRules struct { + Fake *FakeConfigV1alpha2 + ns string +} + +var routerulesResource = schema.GroupVersionResource{Group: "config.istio.io", Version: "v1alpha2", Resource: "routerules"} + +var routerulesKind = schema.GroupVersionKind{Group: "config.istio.io", Version: "v1alpha2", Kind: "RouteRule"} + +// Get takes name of the routeRule, and returns the corresponding routeRule object, and an error if there is any. +func (c *FakeRouteRules) Get(name string, options v1.GetOptions) (result *v1alpha2.RouteRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(routerulesResource, c.ns, name), &v1alpha2.RouteRule{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RouteRule), err +} + +// List takes label and field selectors, and returns the list of RouteRules that match those selectors. +func (c *FakeRouteRules) List(opts v1.ListOptions) (result *v1alpha2.RouteRuleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(routerulesResource, routerulesKind, c.ns, opts), &v1alpha2.RouteRuleList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.RouteRuleList{} + for _, item := range obj.(*v1alpha2.RouteRuleList).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 routeRules. +func (c *FakeRouteRules) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(routerulesResource, c.ns, opts)) + +} + +// Create takes the representation of a routeRule and creates it. Returns the server's representation of the routeRule, and an error, if there is any. +func (c *FakeRouteRules) Create(routeRule *v1alpha2.RouteRule) (result *v1alpha2.RouteRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(routerulesResource, c.ns, routeRule), &v1alpha2.RouteRule{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RouteRule), err +} + +// Update takes the representation of a routeRule and updates it. Returns the server's representation of the routeRule, and an error, if there is any. +func (c *FakeRouteRules) Update(routeRule *v1alpha2.RouteRule) (result *v1alpha2.RouteRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(routerulesResource, c.ns, routeRule), &v1alpha2.RouteRule{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RouteRule), err +} + +// Delete takes name of the routeRule and deletes it. Returns an error if one occurs. +func (c *FakeRouteRules) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(routerulesResource, c.ns, name), &v1alpha2.RouteRule{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRouteRules) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(routerulesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.RouteRuleList{}) + return err +} + +// Patch applies the patch and returns the patched routeRule. +func (c *FakeRouteRules) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RouteRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(routerulesResource, c.ns, name, data, subresources...), &v1alpha2.RouteRule{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RouteRule), err +} diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/generated_expansion.go new file mode 100644 index 00000000000..28db7e76e70 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 v1alpha2 + +type RouteRuleExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/istio_client.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/istio_client.go new file mode 100644 index 00000000000..a0e84b27121 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/istio_client.go @@ -0,0 +1,90 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 v1alpha2 + +import ( + v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" + "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type ConfigV1alpha2Interface interface { + RESTClient() rest.Interface + RouteRulesGetter +} + +// ConfigV1alpha2Client is used to interact with features provided by the config.istio.io group. +type ConfigV1alpha2Client struct { + restClient rest.Interface +} + +func (c *ConfigV1alpha2Client) RouteRules(namespace string) RouteRuleInterface { + return newRouteRules(c, namespace) +} + +// NewForConfig creates a new ConfigV1alpha2Client for the given config. +func NewForConfig(c *rest.Config) (*ConfigV1alpha2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ConfigV1alpha2Client{client}, nil +} + +// NewForConfigOrDie creates a new ConfigV1alpha2Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ConfigV1alpha2Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ConfigV1alpha2Client for the given RESTClient. +func New(c rest.Interface) *ConfigV1alpha2Client { + return &ConfigV1alpha2Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha2.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + 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 *ConfigV1alpha2Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/istio/v1alpha2/routerule.go b/pkg/client/clientset/versioned/typed/istio/v1alpha2/routerule.go new file mode 100644 index 00000000000..d6fbcc0da2e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/istio/v1alpha2/routerule.go @@ -0,0 +1,157 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 v1alpha2 + +import ( + v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" + scheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + 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" +) + +// RouteRulesGetter has a method to return a RouteRuleInterface. +// A group's client should implement this interface. +type RouteRulesGetter interface { + RouteRules(namespace string) RouteRuleInterface +} + +// RouteRuleInterface has methods to work with RouteRule resources. +type RouteRuleInterface interface { + Create(*v1alpha2.RouteRule) (*v1alpha2.RouteRule, error) + Update(*v1alpha2.RouteRule) (*v1alpha2.RouteRule, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.RouteRule, error) + List(opts v1.ListOptions) (*v1alpha2.RouteRuleList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RouteRule, err error) + RouteRuleExpansion +} + +// routeRules implements RouteRuleInterface +type routeRules struct { + client rest.Interface + ns string +} + +// newRouteRules returns a RouteRules +func newRouteRules(c *ConfigV1alpha2Client, namespace string) *routeRules { + return &routeRules{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the routeRule, and returns the corresponding routeRule object, and an error if there is any. +func (c *routeRules) Get(name string, options v1.GetOptions) (result *v1alpha2.RouteRule, err error) { + result = &v1alpha2.RouteRule{} + err = c.client.Get(). + Namespace(c.ns). + Resource("routerules"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of RouteRules that match those selectors. +func (c *routeRules) List(opts v1.ListOptions) (result *v1alpha2.RouteRuleList, err error) { + result = &v1alpha2.RouteRuleList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("routerules"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested routeRules. +func (c *routeRules) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("routerules"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a routeRule and creates it. Returns the server's representation of the routeRule, and an error, if there is any. +func (c *routeRules) Create(routeRule *v1alpha2.RouteRule) (result *v1alpha2.RouteRule, err error) { + result = &v1alpha2.RouteRule{} + err = c.client.Post(). + Namespace(c.ns). + Resource("routerules"). + Body(routeRule). + Do(). + Into(result) + return +} + +// Update takes the representation of a routeRule and updates it. Returns the server's representation of the routeRule, and an error, if there is any. +func (c *routeRules) Update(routeRule *v1alpha2.RouteRule) (result *v1alpha2.RouteRule, err error) { + result = &v1alpha2.RouteRule{} + err = c.client.Put(). + Namespace(c.ns). + Resource("routerules"). + Name(routeRule.Name). + Body(routeRule). + Do(). + Into(result) + return +} + +// Delete takes name of the routeRule and deletes it. Returns an error if one occurs. +func (c *routeRules) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("routerules"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *routeRules) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("routerules"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched routeRule. +func (c *routeRules) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RouteRule, err error) { + result = &v1alpha2.RouteRule{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("routerules"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/channels/interface.go b/pkg/client/informers/externalversions/channels/interface.go new file mode 100644 index 00000000000..6818771fa4b --- /dev/null +++ b/pkg/client/informers/externalversions/channels/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package channels + +import ( + v1alpha1 "github.com/knative/eventing/pkg/client/informers/externalversions/channels/v1alpha1" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/channels/v1alpha1/bus.go b/pkg/client/informers/externalversions/channels/v1alpha1/bus.go new file mode 100644 index 00000000000..f5ef24ee2d4 --- /dev/null +++ b/pkg/client/informers/externalversions/channels/v1alpha1/bus.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + channels_v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/channels/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// BusInformer provides access to a shared informer and lister for +// Buses. +type BusInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.BusLister +} + +type busInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBusInformer constructs a new informer for Bus type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBusInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBusInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBusInformer constructs a new informer for Bus type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBusInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Buses(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Buses(namespace).Watch(options) + }, + }, + &channels_v1alpha1.Bus{}, + resyncPeriod, + indexers, + ) +} + +func (f *busInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBusInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *busInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&channels_v1alpha1.Bus{}, f.defaultInformer) +} + +func (f *busInformer) Lister() v1alpha1.BusLister { + return v1alpha1.NewBusLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/channels/v1alpha1/channel.go b/pkg/client/informers/externalversions/channels/v1alpha1/channel.go new file mode 100644 index 00000000000..054a61cfca8 --- /dev/null +++ b/pkg/client/informers/externalversions/channels/v1alpha1/channel.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + channels_v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/channels/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ChannelInformer provides access to a shared informer and lister for +// Channels. +type ChannelInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ChannelLister +} + +type channelInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewChannelInformer constructs a new informer for Channel type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredChannelInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredChannelInformer constructs a new informer for Channel type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Channels(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Channels(namespace).Watch(options) + }, + }, + &channels_v1alpha1.Channel{}, + resyncPeriod, + indexers, + ) +} + +func (f *channelInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredChannelInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *channelInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&channels_v1alpha1.Channel{}, f.defaultInformer) +} + +func (f *channelInformer) Lister() v1alpha1.ChannelLister { + return v1alpha1.NewChannelLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/channels/v1alpha1/interface.go b/pkg/client/informers/externalversions/channels/v1alpha1/interface.go new file mode 100644 index 00000000000..8a3fed2ce7c --- /dev/null +++ b/pkg/client/informers/externalversions/channels/v1alpha1/interface.go @@ -0,0 +1,59 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Buses returns a BusInformer. + Buses() BusInformer + // Channels returns a ChannelInformer. + Channels() ChannelInformer + // Subscriptions returns a SubscriptionInformer. + Subscriptions() SubscriptionInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Buses returns a BusInformer. +func (v *version) Buses() BusInformer { + return &busInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Channels returns a ChannelInformer. +func (v *version) Channels() ChannelInformer { + return &channelInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Subscriptions returns a SubscriptionInformer. +func (v *version) Subscriptions() SubscriptionInformer { + return &subscriptionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/channels/v1alpha1/subscription.go b/pkg/client/informers/externalversions/channels/v1alpha1/subscription.go new file mode 100644 index 00000000000..dc2a476e2e5 --- /dev/null +++ b/pkg/client/informers/externalversions/channels/v1alpha1/subscription.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + channels_v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/eventing/pkg/client/listers/channels/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// SubscriptionInformer provides access to a shared informer and lister for +// Subscriptions. +type SubscriptionInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.SubscriptionLister +} + +type subscriptionInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewSubscriptionInformer constructs a new informer for Subscription type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewSubscriptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredSubscriptionInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredSubscriptionInformer constructs a new informer for Subscription type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredSubscriptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Subscriptions(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ChannelsV1alpha1().Subscriptions(namespace).Watch(options) + }, + }, + &channels_v1alpha1.Subscription{}, + resyncPeriod, + indexers, + ) +} + +func (f *subscriptionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredSubscriptionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *subscriptionInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&channels_v1alpha1.Subscription{}, f.defaultInformer) +} + +func (f *subscriptionInformer) Lister() v1alpha1.SubscriptionLister { + return v1alpha1.NewSubscriptionLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 661944469da..ead8d02e798 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -24,8 +24,10 @@ import ( time "time" versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + channels "github.com/knative/eventing/pkg/client/informers/externalversions/channels" feeds "github.com/knative/eventing/pkg/client/informers/externalversions/feeds" internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + istio "github.com/knative/eventing/pkg/client/informers/externalversions/istio" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -123,9 +125,19 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + Channels() channels.Interface Feeds() feeds.Interface + Config() istio.Interface +} + +func (f *sharedInformerFactory) Channels() channels.Interface { + return channels.New(f, f.namespace, f.tweakListOptions) } func (f *sharedInformerFactory) Feeds() feeds.Interface { return feeds.New(f, f.namespace, f.tweakListOptions) } + +func (f *sharedInformerFactory) Config() istio.Interface { + return istio.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 5aa6782198e..5a7cbb84ed2 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -21,7 +21,9 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/knative/eventing/pkg/apis/feeds/v1alpha1" + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + feeds_v1alpha1 "github.com/knative/eventing/pkg/apis/feeds/v1alpha1" + v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -52,12 +54,24 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=feeds.knative.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("binds"): + // Group=channels.knative.dev, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("buses"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Channels().V1alpha1().Buses().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("channels"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Channels().V1alpha1().Channels().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("subscriptions"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Channels().V1alpha1().Subscriptions().Informer()}, nil + + // Group=config.istio.io, Version=v1alpha2 + case v1alpha2.SchemeGroupVersion.WithResource("routerules"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha2().RouteRules().Informer()}, nil + + // Group=feeds.knative.dev, Version=v1alpha1 + case feeds_v1alpha1.SchemeGroupVersion.WithResource("binds"): return &genericInformer{resource: resource.GroupResource(), informer: f.Feeds().V1alpha1().Binds().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("eventsources"): + case feeds_v1alpha1.SchemeGroupVersion.WithResource("eventsources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Feeds().V1alpha1().EventSources().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("eventtypes"): + case feeds_v1alpha1.SchemeGroupVersion.WithResource("eventtypes"): return &genericInformer{resource: resource.GroupResource(), informer: f.Feeds().V1alpha1().EventTypes().Informer()}, nil } diff --git a/pkg/client/informers/externalversions/istio/interface.go b/pkg/client/informers/externalversions/istio/interface.go new file mode 100644 index 00000000000..b781c35e8a6 --- /dev/null +++ b/pkg/client/informers/externalversions/istio/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package config + +import ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "github.com/knative/eventing/pkg/client/informers/externalversions/istio/v1alpha2" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha2 provides access to shared informers for resources in V1alpha2. + V1alpha2() v1alpha2.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha2 returns a new v1alpha2.Interface. +func (g *group) V1alpha2() v1alpha2.Interface { + return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/istio/v1alpha2/interface.go b/pkg/client/informers/externalversions/istio/v1alpha2/interface.go new file mode 100644 index 00000000000..c9df313ae30 --- /dev/null +++ b/pkg/client/informers/externalversions/istio/v1alpha2/interface.go @@ -0,0 +1,45 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // RouteRules returns a RouteRuleInformer. + RouteRules() RouteRuleInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// RouteRules returns a RouteRuleInformer. +func (v *version) RouteRules() RouteRuleInformer { + return &routeRuleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/istio/v1alpha2/routerule.go b/pkg/client/informers/externalversions/istio/v1alpha2/routerule.go new file mode 100644 index 00000000000..3c76a1930c3 --- /dev/null +++ b/pkg/client/informers/externalversions/istio/v1alpha2/routerule.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + istio_v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" + versioned "github.com/knative/eventing/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "github.com/knative/eventing/pkg/client/listers/istio/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// RouteRuleInformer provides access to a shared informer and lister for +// RouteRules. +type RouteRuleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.RouteRuleLister +} + +type routeRuleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRouteRuleInformer constructs a new informer for RouteRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRouteRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRouteRuleInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRouteRuleInformer constructs a new informer for RouteRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRouteRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigV1alpha2().RouteRules(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigV1alpha2().RouteRules(namespace).Watch(options) + }, + }, + &istio_v1alpha2.RouteRule{}, + resyncPeriod, + indexers, + ) +} + +func (f *routeRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRouteRuleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *routeRuleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&istio_v1alpha2.RouteRule{}, f.defaultInformer) +} + +func (f *routeRuleInformer) Lister() v1alpha2.RouteRuleLister { + return v1alpha2.NewRouteRuleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/channels/v1alpha1/bus.go b/pkg/client/listers/channels/v1alpha1/bus.go new file mode 100644 index 00000000000..d6096d74641 --- /dev/null +++ b/pkg/client/listers/channels/v1alpha1/bus.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// BusLister helps list Buses. +type BusLister interface { + // List lists all Buses in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Bus, err error) + // Buses returns an object that can list and get Buses. + Buses(namespace string) BusNamespaceLister + BusListerExpansion +} + +// busLister implements the BusLister interface. +type busLister struct { + indexer cache.Indexer +} + +// NewBusLister returns a new BusLister. +func NewBusLister(indexer cache.Indexer) BusLister { + return &busLister{indexer: indexer} +} + +// List lists all Buses in the indexer. +func (s *busLister) List(selector labels.Selector) (ret []*v1alpha1.Bus, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Bus)) + }) + return ret, err +} + +// Buses returns an object that can list and get Buses. +func (s *busLister) Buses(namespace string) BusNamespaceLister { + return busNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BusNamespaceLister helps list and get Buses. +type BusNamespaceLister interface { + // List lists all Buses in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Bus, err error) + // Get retrieves the Bus from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Bus, error) + BusNamespaceListerExpansion +} + +// busNamespaceLister implements the BusNamespaceLister +// interface. +type busNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Buses in the indexer for a given namespace. +func (s busNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Bus, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Bus)) + }) + return ret, err +} + +// Get retrieves the Bus from the indexer for a given namespace and name. +func (s busNamespaceLister) Get(name string) (*v1alpha1.Bus, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("bus"), name) + } + return obj.(*v1alpha1.Bus), nil +} diff --git a/pkg/client/listers/channels/v1alpha1/channel.go b/pkg/client/listers/channels/v1alpha1/channel.go new file mode 100644 index 00000000000..7e70e49916f --- /dev/null +++ b/pkg/client/listers/channels/v1alpha1/channel.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ChannelLister helps list Channels. +type ChannelLister interface { + // List lists all Channels in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Channel, err error) + // Channels returns an object that can list and get Channels. + Channels(namespace string) ChannelNamespaceLister + ChannelListerExpansion +} + +// channelLister implements the ChannelLister interface. +type channelLister struct { + indexer cache.Indexer +} + +// NewChannelLister returns a new ChannelLister. +func NewChannelLister(indexer cache.Indexer) ChannelLister { + return &channelLister{indexer: indexer} +} + +// List lists all Channels in the indexer. +func (s *channelLister) List(selector labels.Selector) (ret []*v1alpha1.Channel, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Channel)) + }) + return ret, err +} + +// Channels returns an object that can list and get Channels. +func (s *channelLister) Channels(namespace string) ChannelNamespaceLister { + return channelNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ChannelNamespaceLister helps list and get Channels. +type ChannelNamespaceLister interface { + // List lists all Channels in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Channel, err error) + // Get retrieves the Channel from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Channel, error) + ChannelNamespaceListerExpansion +} + +// channelNamespaceLister implements the ChannelNamespaceLister +// interface. +type channelNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Channels in the indexer for a given namespace. +func (s channelNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Channel, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Channel)) + }) + return ret, err +} + +// Get retrieves the Channel from the indexer for a given namespace and name. +func (s channelNamespaceLister) Get(name string) (*v1alpha1.Channel, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("channel"), name) + } + return obj.(*v1alpha1.Channel), nil +} diff --git a/pkg/client/listers/channels/v1alpha1/expansion_generated.go b/pkg/client/listers/channels/v1alpha1/expansion_generated.go new file mode 100644 index 00000000000..792426e9fcc --- /dev/null +++ b/pkg/client/listers/channels/v1alpha1/expansion_generated.go @@ -0,0 +1,43 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha1 + +// BusListerExpansion allows custom methods to be added to +// BusLister. +type BusListerExpansion interface{} + +// BusNamespaceListerExpansion allows custom methods to be added to +// BusNamespaceLister. +type BusNamespaceListerExpansion interface{} + +// ChannelListerExpansion allows custom methods to be added to +// ChannelLister. +type ChannelListerExpansion interface{} + +// ChannelNamespaceListerExpansion allows custom methods to be added to +// ChannelNamespaceLister. +type ChannelNamespaceListerExpansion interface{} + +// SubscriptionListerExpansion allows custom methods to be added to +// SubscriptionLister. +type SubscriptionListerExpansion interface{} + +// SubscriptionNamespaceListerExpansion allows custom methods to be added to +// SubscriptionNamespaceLister. +type SubscriptionNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/channels/v1alpha1/subscription.go b/pkg/client/listers/channels/v1alpha1/subscription.go new file mode 100644 index 00000000000..b79680fcdb1 --- /dev/null +++ b/pkg/client/listers/channels/v1alpha1/subscription.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// SubscriptionLister helps list Subscriptions. +type SubscriptionLister interface { + // List lists all Subscriptions in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Subscription, err error) + // Subscriptions returns an object that can list and get Subscriptions. + Subscriptions(namespace string) SubscriptionNamespaceLister + SubscriptionListerExpansion +} + +// subscriptionLister implements the SubscriptionLister interface. +type subscriptionLister struct { + indexer cache.Indexer +} + +// NewSubscriptionLister returns a new SubscriptionLister. +func NewSubscriptionLister(indexer cache.Indexer) SubscriptionLister { + return &subscriptionLister{indexer: indexer} +} + +// List lists all Subscriptions in the indexer. +func (s *subscriptionLister) List(selector labels.Selector) (ret []*v1alpha1.Subscription, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Subscription)) + }) + return ret, err +} + +// Subscriptions returns an object that can list and get Subscriptions. +func (s *subscriptionLister) Subscriptions(namespace string) SubscriptionNamespaceLister { + return subscriptionNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// SubscriptionNamespaceLister helps list and get Subscriptions. +type SubscriptionNamespaceLister interface { + // List lists all Subscriptions in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Subscription, err error) + // Get retrieves the Subscription from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Subscription, error) + SubscriptionNamespaceListerExpansion +} + +// subscriptionNamespaceLister implements the SubscriptionNamespaceLister +// interface. +type subscriptionNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Subscriptions in the indexer for a given namespace. +func (s subscriptionNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Subscription, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Subscription)) + }) + return ret, err +} + +// Get retrieves the Subscription from the indexer for a given namespace and name. +func (s subscriptionNamespaceLister) Get(name string) (*v1alpha1.Subscription, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("subscription"), name) + } + return obj.(*v1alpha1.Subscription), nil +} diff --git a/pkg/client/listers/istio/v1alpha2/expansion_generated.go b/pkg/client/listers/istio/v1alpha2/expansion_generated.go new file mode 100644 index 00000000000..381e18b6494 --- /dev/null +++ b/pkg/client/listers/istio/v1alpha2/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha2 + +// RouteRuleListerExpansion allows custom methods to be added to +// RouteRuleLister. +type RouteRuleListerExpansion interface{} + +// RouteRuleNamespaceListerExpansion allows custom methods to be added to +// RouteRuleNamespaceLister. +type RouteRuleNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/istio/v1alpha2/routerule.go b/pkg/client/listers/istio/v1alpha2/routerule.go new file mode 100644 index 00000000000..f146e158be7 --- /dev/null +++ b/pkg/client/listers/istio/v1alpha2/routerule.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// RouteRuleLister helps list RouteRules. +type RouteRuleLister interface { + // List lists all RouteRules in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.RouteRule, err error) + // RouteRules returns an object that can list and get RouteRules. + RouteRules(namespace string) RouteRuleNamespaceLister + RouteRuleListerExpansion +} + +// routeRuleLister implements the RouteRuleLister interface. +type routeRuleLister struct { + indexer cache.Indexer +} + +// NewRouteRuleLister returns a new RouteRuleLister. +func NewRouteRuleLister(indexer cache.Indexer) RouteRuleLister { + return &routeRuleLister{indexer: indexer} +} + +// List lists all RouteRules in the indexer. +func (s *routeRuleLister) List(selector labels.Selector) (ret []*v1alpha2.RouteRule, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.RouteRule)) + }) + return ret, err +} + +// RouteRules returns an object that can list and get RouteRules. +func (s *routeRuleLister) RouteRules(namespace string) RouteRuleNamespaceLister { + return routeRuleNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// RouteRuleNamespaceLister helps list and get RouteRules. +type RouteRuleNamespaceLister interface { + // List lists all RouteRules in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha2.RouteRule, err error) + // Get retrieves the RouteRule from the indexer for a given namespace and name. + Get(name string) (*v1alpha2.RouteRule, error) + RouteRuleNamespaceListerExpansion +} + +// routeRuleNamespaceLister implements the RouteRuleNamespaceLister +// interface. +type routeRuleNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all RouteRules in the indexer for a given namespace. +func (s routeRuleNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.RouteRule, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.RouteRule)) + }) + return ret, err +} + +// Get retrieves the RouteRule from the indexer for a given namespace and name. +func (s routeRuleNamespaceLister) Get(name string) (*v1alpha2.RouteRule, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("routerule"), name) + } + return obj.(*v1alpha2.RouteRule), nil +} diff --git a/pkg/controller/bus/controller.go b/pkg/controller/bus/controller.go new file mode 100644 index 00000000000..823d969f1e3 --- /dev/null +++ b/pkg/controller/bus/controller.go @@ -0,0 +1,774 @@ +/* +Copyright 2017 The Kubernetes 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 bus + +import ( + "fmt" + "reflect" + "time" + + "github.com/golang/glog" + "github.com/knative/eventing/pkg/controller" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1beta1 "k8s.io/api/rbac/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + kubeinformers "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + appslisters "k8s.io/client-go/listers/apps/v1" + corelisters "k8s.io/client-go/listers/core/v1" + rbaclisters "k8s.io/client-go/listers/rbac/v1beta1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/workqueue" + + clientset "github.com/knative/eventing/pkg/client/clientset/versioned" + channelscheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + listers "github.com/knative/eventing/pkg/client/listers/channels/v1alpha1" + elainformers "github.com/knative/serving/pkg/client/informers/externalversions" + + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" +) + +const controllerAgentName = "bus-controller" + +const ( + // SuccessSynced is used as part of the Event 'reason' when a Bus is synced + SuccessSynced = "Synced" + // ErrResourceExists is used as part of the Event 'reason' when a Bus fails + // to sync due to a Service of the same name already existing. + ErrResourceExists = "ErrResourceExists" + + // MessageResourceExists is the message used for Events when a resource + // fails to sync due to a Service already existing + MessageResourceExists = "Resource %q already exists and is not managed by Bus" + // MessageResourceSynced is the message used for an Event fired when a Bus + // is synced successfully + MessageResourceSynced = "Bus synced successfully" +) + +// Controller is the controller implementation for Bus resources +type Controller struct { + // kubeclientset is a standard kubernetes clientset + kubeclientset kubernetes.Interface + // busclientset is a clientset for our own API group + busclientset clientset.Interface + + deploymentsLister appslisters.DeploymentLister + deploymentsSynced cache.InformerSynced + servicesLister corelisters.ServiceLister + servicesSynced cache.InformerSynced + serviceAccountsLister corelisters.ServiceAccountLister + serviceAccountsSynced cache.InformerSynced + clusterRoleBindingsLister rbaclisters.ClusterRoleBindingLister + clusterRoleBindingsSynced cache.InformerSynced + busesLister listers.BusLister + busesSynced cache.InformerSynced + + // workqueue is a rate limited work queue. This is used to queue work to be + // processed instead of performing it as soon as a change happens. This + // means we can ensure we only process a fixed amount of resources at a + // time, and makes it easy to ensure we are never processing the same item + // simultaneously in two different workers. + workqueue workqueue.RateLimitingInterface + // recorder is an event recorder for recording Event resources to the + // Kubernetes API. + recorder record.EventRecorder +} + +// NewController returns a new bus controller +func NewController( + kubeclientset kubernetes.Interface, + busclientset clientset.Interface, + kubeInformerFactory kubeinformers.SharedInformerFactory, + busInformerFactory informers.SharedInformerFactory, + routeInformerFactory elainformers.SharedInformerFactory) controller.Interface { + + // obtain references to shared index informers for the Bus, Deployment and Service + // types. + busInformer := busInformerFactory.Channels().V1alpha1().Buses() + deploymentInformer := kubeInformerFactory.Apps().V1().Deployments() + serviceInformer := kubeInformerFactory.Core().V1().Services() + serviceAccountInformer := kubeInformerFactory.Core().V1().ServiceAccounts() + clusterRoleBindingInformer := kubeInformerFactory.Rbac().V1beta1().ClusterRoleBindings() + + // Create event broadcaster + // Add bus-controller types to the default Kubernetes Scheme so Events can be + // logged for bus-controller types. + channelscheme.AddToScheme(scheme.Scheme) + glog.V(4).Info("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + eventBroadcaster.StartLogging(glog.Infof) + eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")}) + recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) + + controller := &Controller{ + kubeclientset: kubeclientset, + busclientset: busclientset, + deploymentsLister: deploymentInformer.Lister(), + deploymentsSynced: deploymentInformer.Informer().HasSynced, + servicesLister: serviceInformer.Lister(), + servicesSynced: serviceInformer.Informer().HasSynced, + serviceAccountsLister: serviceAccountInformer.Lister(), + serviceAccountsSynced: serviceAccountInformer.Informer().HasSynced, + clusterRoleBindingsLister: clusterRoleBindingInformer.Lister(), + clusterRoleBindingsSynced: clusterRoleBindingInformer.Informer().HasSynced, + busesLister: busInformer.Lister(), + busesSynced: busInformer.Informer().HasSynced, + workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Buses"), + recorder: recorder, + } + + glog.Info("Setting up event handlers") + // Set up an event handler for when Bus resources change + busInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: controller.enqueueBus, + UpdateFunc: func(old, new interface{}) { + controller.enqueueBus(new) + }, + }) + // Set up an event handler for when Service resources change. This + // handler will lookup the owner of the given Service, and if it is + // owned by a Bus resource will enqueue that Bus resource for + // processing. This way, we don't need to implement custom logic for + // handling Service resources. More info on this pattern: + // https://github.com/kubernetes/community/blob/8cafef897a22026d42f5e5bb3f104febe7e29830/contributors/devel/controllers.md + serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: controller.handleObject, + UpdateFunc: func(old, new interface{}) { + newService := new.(*corev1.Service) + oldService := old.(*corev1.Service) + if newService.ResourceVersion == oldService.ResourceVersion { + // Periodic resync will send update events for all known Services. + // Two different versions of the same Service will always have different RVs. + return + } + controller.handleObject(new) + }, + DeleteFunc: controller.handleObject, + }) + + return controller +} + +// Run will set up the event handlers for types we are interested in, as well +// as syncing informer caches and starting workers. It will block until stopCh +// is closed, at which point it will shutdown the workqueue and wait for +// workers to finish processing their current work items. +func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { + defer runtime.HandleCrash() + defer c.workqueue.ShutDown() + + // Start the informer factories to begin populating the informer caches + glog.Info("Starting Bus controller") + + // Wait for the caches to be synced before starting workers + glog.Info("Waiting for informer caches to sync") + if ok := cache.WaitForCacheSync(stopCh, c.deploymentsSynced, c.servicesSynced, c.busesSynced); !ok { + return fmt.Errorf("failed to wait for caches to sync") + } + + glog.Info("Starting workers") + // Launch two workers to process Bus resources + for i := 0; i < threadiness; i++ { + go wait.Until(c.runWorker, time.Second, stopCh) + } + + glog.Info("Started workers") + <-stopCh + glog.Info("Shutting down workers") + + return nil +} + +// runWorker is a long-running function that will continually call the +// processNextWorkItem function in order to read and process a message on the +// workqueue. +func (c *Controller) runWorker() { + for c.processNextWorkItem() { + } +} + +// processNextWorkItem will read a single work item off the workqueue and +// attempt to process it, by calling the syncHandler. +func (c *Controller) processNextWorkItem() bool { + obj, shutdown := c.workqueue.Get() + + if shutdown { + return false + } + + // We wrap this block in a func so we can defer c.workqueue.Done. + err := func(obj interface{}) error { + // We call Done here so the workqueue knows we have finished + // processing this item. We also must remember to call Forget if we + // do not want this work item being re-queued. For example, we do + // not call Forget if a transient error occurs, instead the item is + // put back on the workqueue and attempted again after a back-off + // period. + defer c.workqueue.Done(obj) + var key string + var ok bool + // We expect strings to come off the workqueue. These are of the + // form namespace/name. We do this as the delayed nature of the + // workqueue means the items in the informer cache may actually be + // more up to date that when the item was initially put onto the + // workqueue. + if key, ok = obj.(string); !ok { + // As the item in the workqueue is actually invalid, we call + // Forget here else we'd go into a loop of attempting to + // process a work item that is invalid. + c.workqueue.Forget(obj) + runtime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj)) + return nil + } + // Run the syncHandler, passing it the namespace/name string of the + // Bus resource to be synced. + if err := c.syncHandler(key); err != nil { + return fmt.Errorf("error syncing bus '%s': %s", key, err.Error()) + } + // Finally, if no error occurs we Forget this item so it does not + // get queued again until another change happens. + c.workqueue.Forget(obj) + glog.Infof("Successfully synced bus '%s'", key) + return nil + }(obj) + + if err != nil { + runtime.HandleError(err) + return true + } + + return true +} + +// syncHandler compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Bus resource +// with the current status of the resource. +func (c *Controller) syncHandler(key string) error { + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + runtime.HandleError(fmt.Errorf("invalid resource key: %s", key)) + return nil + } + + // Get the Bus resource with this namespace/name + bus, err := c.busesLister.Buses(namespace).Get(name) + if err != nil { + // The Bus resource may no longer exist, in which case we stop + // processing. + if errors.IsNotFound(err) { + runtime.HandleError(fmt.Errorf("bus '%s' in work queue no longer exists", key)) + return nil + } + + return err + } + + // Sync ServiceAccount derived from the Bus + serviceAccount, err := c.syncBusServiceAccount(bus) + if err != nil { + return err + } + + // Sync ClusterRoleBinding derived from the Bus + clusterRoleBinding, err := c.syncBusClusterRoleBinding(bus) + if err != nil { + return err + } + + // Sync Service derived from the Bus + dispatcherService, err := c.syncBusDispatcherService(bus) + if err != nil { + return err + } + + // Sync Deployment derived from the Bus + dispatcherDeployment, err := c.syncBusDispatcherDeployment(bus) + if err != nil { + return err + } + + // Sync Deployment derived from the Bus + provisionerDeployment, err := c.syncBusProvisionerDeployment(bus) + if err != nil { + return err + } + + // Finally, we update the status block of the Bus resource to reflect the + // current state of the world + err = c.updateBusStatus(bus, dispatcherService, dispatcherDeployment, provisionerDeployment, serviceAccount, clusterRoleBinding) + if err != nil { + return err + } + + c.recorder.Event(bus, corev1.EventTypeNormal, SuccessSynced, MessageResourceSynced) + return nil +} + +func (c *Controller) syncBusDispatcherService(bus *channelsv1alpha1.Bus) (*corev1.Service, error) { + // Get the service with the specified service name + serviceName := controller.BusDispatcherServiceName(bus.ObjectMeta.Name) + service, err := c.servicesLister.Services(bus.Namespace).Get(serviceName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + service, err = c.kubeclientset.CoreV1().Services(bus.Namespace).Create(newDispatcherService(bus)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Service is not controlled by this Bus resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(service, bus) { + msg := fmt.Sprintf(MessageResourceExists, service.Name) + c.recorder.Event(bus, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + return service, nil +} + +func (c *Controller) syncBusDispatcherDeployment(bus *channelsv1alpha1.Bus) (*appsv1.Deployment, error) { + // Get the deployment with the specified deployment name + deploymentName := controller.BusDispatcherDeploymentName(bus.ObjectMeta.Name) + deployment, err := c.deploymentsLister.Deployments(bus.Namespace).Get(deploymentName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + deployment, err = c.kubeclientset.AppsV1().Deployments(bus.Namespace).Create(newDispatcherDeployment(bus)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Deployment is not controlled by this Bus resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(deployment, bus) { + msg := fmt.Sprintf(MessageResourceExists, deployment.Name) + c.recorder.Event(bus, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + // If the Deployment does not match the Bus's proposed Deployment we should update + // the Deployment resource. + proposedDeployment := newDispatcherDeployment(bus) + if !reflect.DeepEqual(proposedDeployment.Spec, deployment.Spec) { + glog.V(4).Infof("Bus %s dispatcher spec updated", bus.Name) + deployment, err = c.kubeclientset.AppsV1().Deployments(bus.Namespace).Update(proposedDeployment) + + if err != nil { + return nil, err + } + } + + return deployment, nil +} + +func (c *Controller) syncBusServiceAccount(bus *channelsv1alpha1.Bus) (*corev1.ServiceAccount, error) { + // Get the serviceAccount with the specified serviceAccount name + serviceAccountName := controller.BusServiceAccountName(bus.ObjectMeta.Name) + serviceAccount, err := c.serviceAccountsLister.ServiceAccounts(bus.Namespace).Get(serviceAccountName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + serviceAccount, err = c.kubeclientset.CoreV1().ServiceAccounts(bus.Namespace).Create(newServiceAccount(bus)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the ServiceAccount is not controlled by this Bus resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(serviceAccount, bus) { + msg := fmt.Sprintf(MessageResourceExists, serviceAccount.Name) + c.recorder.Event(bus, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + return serviceAccount, nil +} + +func (c *Controller) syncBusClusterRoleBinding(bus *channelsv1alpha1.Bus) (*rbacv1beta1.ClusterRoleBinding, error) { + // Get the clusterRoleBinding with the specified clusterRoleBinding name + clusterRoleBindingName := controller.BusClusterRoleBindingName(bus.ObjectMeta.Name) + clusterRoleBinding, err := c.clusterRoleBindingsLister.Get(clusterRoleBindingName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + clusterRoleBinding, err = c.kubeclientset.RbacV1beta1().ClusterRoleBindings().Create(newClusterRoleBinding(bus)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the ClusterRoleBinding is not controlled by this Bus resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(clusterRoleBinding, bus) { + msg := fmt.Sprintf(MessageResourceExists, clusterRoleBinding.Name) + c.recorder.Event(bus, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + // If the ClusterRoleBinding does not match the Bus's proposed ClusterRoleBinding we + // should update the ClusterRoleBinding resource. + proposedClusterRoleBinding := newClusterRoleBinding(bus) + if !reflect.DeepEqual(proposedClusterRoleBinding.Subjects, clusterRoleBinding.Subjects) && + !reflect.DeepEqual(proposedClusterRoleBinding.RoleRef, clusterRoleBinding.RoleRef) { + glog.V(4).Infof("Bus %s provisioner spec updated", bus.Name) + clusterRoleBinding, err = c.kubeclientset.RbacV1beta1().ClusterRoleBindings().Update(proposedClusterRoleBinding) + + if err != nil { + return nil, err + } + } + + return clusterRoleBinding, nil +} + +func (c *Controller) syncBusProvisionerDeployment(bus *channelsv1alpha1.Bus) (*appsv1.Deployment, error) { + provisioner := bus.Spec.Provisioner + + // Get the deployment with the specified deployment name + deploymentName := controller.BusProvisionerDeploymentName(bus.ObjectMeta.Name) + deployment, err := c.deploymentsLister.Deployments(bus.Namespace).Get(deploymentName) + + // If the resource shouldn't exists + if provisioner == nil { + // If the resource exists, we'll delete it + if deployment != nil { + err = c.kubeclientset.AppsV1().Deployments(bus.Namespace).Delete(deploymentName, nil) + } + if errors.IsNotFound(err) { + return nil, nil + } + return nil, err + } + + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + deployment, err = c.kubeclientset.AppsV1().Deployments(bus.Namespace).Create(newProvisionerDeployment(bus)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Deployment is not controlled by this Bus resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(deployment, bus) { + msg := fmt.Sprintf(MessageResourceExists, deployment.Name) + c.recorder.Event(bus, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + // If the Deployment does not match the Bus's proposed Deployment we should update + // the Deployment resource. + proposedDeployment := newProvisionerDeployment(bus) + if !reflect.DeepEqual(proposedDeployment.Spec, deployment.Spec) { + glog.V(4).Infof("Bus %s provisioner spec updated", bus.Name) + deployment, err = c.kubeclientset.AppsV1().Deployments(bus.Namespace).Update(proposedDeployment) + + if err != nil { + return nil, err + } + } + + return deployment, nil +} + +func (c *Controller) updateBusStatus( + bus *channelsv1alpha1.Bus, + dispatcherService *corev1.Service, + dispatcherDeployment *appsv1.Deployment, + provisionerDeployment *appsv1.Deployment, + serviceAccount *corev1.ServiceAccount, + clusterRoleBinding *rbacv1beta1.ClusterRoleBinding, +) error { + // NEVER modify objects from the store. It's a read-only, local cache. + // You can use DeepCopy() to make a deep copy of original object and modify this copy + // Or create a copy manually for better performance + busCopy := bus.DeepCopy() + // If the CustomResourceSubresources feature gate is not enabled, + // we must use Update instead of UpdateStatus to update the Status block of the Bus resource. + // UpdateStatus will not allow changes to the Spec of the resource, + // which is ideal for ensuring nothing other than resource status has been updated. + _, err := c.busclientset.ChannelsV1alpha1().Buses(bus.Namespace).Update(busCopy) + return err +} + +// enqueueBus takes a Bus resource and converts it into a namespace/name +// string which is then put onto the work queue. This method should *not* be +// passed resources of any type other than Bus. +func (c *Controller) enqueueBus(obj interface{}) { + var key string + var err error + if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil { + runtime.HandleError(err) + return + } + c.workqueue.AddRateLimited(key) +} + +// handleObject will take any resource implementing metav1.Object and attempt +// to find the Bus resource that 'owns' it. It does this by looking at the +// objects metadata.ownerReferences field for an appropriate OwnerReference. +// It then enqueues that Bus resource to be processed. If the object does not +// have an appropriate OwnerReference, it will simply be skipped. +func (c *Controller) handleObject(obj interface{}) { + var object metav1.Object + var ok bool + if object, ok = obj.(metav1.Object); !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + runtime.HandleError(fmt.Errorf("error decoding object, invalid type")) + return + } + object, ok = tombstone.Obj.(metav1.Object) + if !ok { + runtime.HandleError(fmt.Errorf("error decoding object tombstone, invalid type")) + return + } + glog.V(4).Infof("Recovered deleted object '%s' from tombstone", object.GetName()) + } + glog.V(4).Infof("Processing object: %s", object.GetName()) + if ownerRef := metav1.GetControllerOf(object); ownerRef != nil { + // If this object is not owned by a Bus, we should not do anything more + // with it. + if ownerRef.Kind != "Bus" { + return + } + + bus, err := c.busesLister.Buses(object.GetNamespace()).Get(ownerRef.Name) + if err != nil { + glog.V(4).Infof("ignoring orphaned object '%s' of bus '%s'", object.GetSelfLink(), ownerRef.Name) + return + } + + c.enqueueBus(bus) + return + } +} + +// newDispatcherService creates a new Service for a Bus resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Bus resource that 'owns' it. +func newDispatcherService(bus *channelsv1alpha1.Bus) *corev1.Service { + labels := map[string]string{ + "bus": bus.Name, + "role": "dispatcher", + } + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.BusDispatcherServiceName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + Labels: labels, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(bus, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Bus", + }), + }, + }, + Spec: corev1.ServiceSpec{ + Selector: labels, + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + }, + }, + }, + } +} + +// newDispatcherDeployment creates a new Deployment for a Bus resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Bus resource that 'owns' it. +func newDispatcherDeployment(bus *channelsv1alpha1.Bus) *appsv1.Deployment { + labels := map[string]string{ + "bus": bus.Name, + "role": "dispatcher", + } + one := int32(1) + container := bus.Spec.Dispatcher.DeepCopy() + container.Env = append(container.Env, + corev1.EnvVar{ + Name: "PORT", + Value: "8080", + }, + corev1.EnvVar{ + Name: "BUS_NAME", + Value: bus.Name, + }, + ) + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.BusDispatcherDeploymentName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(bus, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Bus", + }), + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &one, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: controller.BusServiceAccountName(bus.Name), + Containers: []corev1.Container{ + *container, + }, + }, + }, + }, + } +} + +// newServiceAccount creates a new ServiceAccount for a Bus resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Bus resource that 'owns' it. +func newServiceAccount(bus *channelsv1alpha1.Bus) *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.BusServiceAccountName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(bus, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Bus", + }), + }, + }, + } +} + +// newClusterRoleBinding creates a new ClusterRoleBinding for a Bus resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Bus resource that 'owns' it. +func newClusterRoleBinding(bus *channelsv1alpha1.Bus) *rbacv1beta1.ClusterRoleBinding { + return &rbacv1beta1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.BusClusterRoleBindingName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(bus, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Bus", + }), + }, + }, + Subjects: []rbacv1beta1.Subject{ + { + Kind: "ServiceAccount", + Name: controller.BusServiceAccountName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + }, + }, + RoleRef: rbacv1beta1.RoleRef{ + Kind: "ClusterRole", + Name: "knative-channels-bus", + APIGroup: "rbac.authorization.k8s.io", + }, + } +} + +// newProvisionerDeployment creates a new Deployment for a Bus resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Bus resource that 'owns' it. +func newProvisionerDeployment(bus *channelsv1alpha1.Bus) *appsv1.Deployment { + labels := map[string]string{ + "bus": bus.Name, + "role": "provisioner", + } + one := int32(1) + container := bus.Spec.Provisioner.DeepCopy() + container.Env = append(container.Env, + corev1.EnvVar{ + Name: "BUS_NAME", + Value: bus.Name, + }, + ) + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.BusProvisionerDeploymentName(bus.ObjectMeta.Name), + Namespace: bus.Namespace, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(bus, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Bus", + }), + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &one, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: controller.BusServiceAccountName(bus.Name), + Containers: []corev1.Container{ + *container, + }, + }, + }, + }, + } +} diff --git a/pkg/controller/channel/controller.go b/pkg/controller/channel/controller.go new file mode 100644 index 00000000000..5156380f6af --- /dev/null +++ b/pkg/controller/channel/controller.go @@ -0,0 +1,577 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package channel + +import ( + "fmt" + "time" + + "github.com/golang/glog" + istiolisters "github.com/knative/eventing/pkg/client/listers/istio/v1alpha2" + "github.com/knative/eventing/pkg/controller" + corev1 "k8s.io/api/core/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + kubeinformers "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + corelisters "k8s.io/client-go/listers/core/v1" + extensionslisters "k8s.io/client-go/listers/extensions/v1beta1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/workqueue" + + clientset "github.com/knative/eventing/pkg/client/clientset/versioned" + channelscheme "github.com/knative/eventing/pkg/client/clientset/versioned/scheme" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + listers "github.com/knative/eventing/pkg/client/listers/channels/v1alpha1" + elainformers "github.com/knative/serving/pkg/client/informers/externalversions" + + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + istiov1alpha2 "github.com/knative/eventing/pkg/apis/istio/v1alpha2" +) + +const controllerAgentName = "channel-controller" + +const ( + // SuccessSynced is used as part of the Event 'reason' when a Channel is synced + SuccessSynced = "Synced" + // ErrResourceExists is used as part of the Event 'reason' when a Channel fails + // to sync due to a Service of the same name already existing. + ErrResourceExists = "ErrResourceExists" + + // MessageResourceExists is the message used for Events when a resource + // fails to sync due to a Service already existing + MessageResourceExists = "Resource %q already exists and is not managed by Channel" + // MessageResourceSynced is the message used for an Event fired when a Channel + // is synced successfully + MessageResourceSynced = "Channel synced successfully" +) + +// Controller is the controller implementation for Channel resources +type Controller struct { + // kubeclientset is a standard kubernetes clientset + kubeclientset kubernetes.Interface + // channelclientset is a clientset for our own API group + channelclientset clientset.Interface + + ingressesLister extensionslisters.IngressLister + ingressesSynced cache.InformerSynced + routerulesLister istiolisters.RouteRuleLister + routerulesSynced cache.InformerSynced + servicesLister corelisters.ServiceLister + servicesSynced cache.InformerSynced + channelsLister listers.ChannelLister + channelsSynced cache.InformerSynced + + // workqueue is a rate limited work queue. This is used to queue work to be + // processed instead of performing it as soon as a change happens. This + // means we can ensure we only process a fixed amount of resources at a + // time, and makes it easy to ensure we are never processing the same item + // simultaneously in two different workers. + workqueue workqueue.RateLimitingInterface + // recorder is an event recorder for recording Event resources to the + // Kubernetes API. + recorder record.EventRecorder +} + +// NewController returns a new channel controller +func NewController( + kubeclientset kubernetes.Interface, + channelclientset clientset.Interface, + kubeInformerFactory kubeinformers.SharedInformerFactory, + channelInformerFactory informers.SharedInformerFactory, + routeInformerFactory elainformers.SharedInformerFactory) controller.Interface { + + // obtain references to shared index informers for the Ingress, Service and Channel + // types. + ingressInformer := kubeInformerFactory.Extensions().V1beta1().Ingresses() + routeruleInformer := channelInformerFactory.Config().V1alpha2().RouteRules() + serviceInformer := kubeInformerFactory.Core().V1().Services() + channelInformer := channelInformerFactory.Channels().V1alpha1().Channels() + + // Create event broadcaster + // Add channel-controller types to the default Kubernetes Scheme so Events can be + // logged for channel-controller types. + channelscheme.AddToScheme(scheme.Scheme) + glog.V(4).Info("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + eventBroadcaster.StartLogging(glog.Infof) + eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")}) + recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) + + controller := &Controller{ + kubeclientset: kubeclientset, + channelclientset: channelclientset, + ingressesLister: ingressInformer.Lister(), + ingressesSynced: ingressInformer.Informer().HasSynced, + routerulesLister: routeruleInformer.Lister(), + routerulesSynced: routeruleInformer.Informer().HasSynced, + servicesLister: serviceInformer.Lister(), + servicesSynced: serviceInformer.Informer().HasSynced, + channelsLister: channelInformer.Lister(), + channelsSynced: channelInformer.Informer().HasSynced, + workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Channels"), + recorder: recorder, + } + + glog.Info("Setting up event handlers") + // Set up an event handler for when Channel resources change + channelInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: controller.enqueueChannel, + UpdateFunc: func(old, new interface{}) { + controller.enqueueChannel(new) + }, + }) + // Set up an event handler for when Service resources change. This + // handler will lookup the owner of the given Service, and if it is + // owned by a Channel resource will enqueue that Channel resource for + // processing. This way, we don't need to implement custom logic for + // handling Service resources. More info on this pattern: + // https://github.com/kubernetes/community/blob/8cafef897a22026d42f5e5bb3f104febe7e29830/contributors/devel/controllers.md + serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: controller.handleObject, + UpdateFunc: func(old, new interface{}) { + newService := new.(*corev1.Service) + oldService := old.(*corev1.Service) + if newService.ResourceVersion == oldService.ResourceVersion { + // Periodic resync will send update events for all known Services. + // Two different versions of the same Service will always have different RVs. + return + } + controller.handleObject(new) + }, + DeleteFunc: controller.handleObject, + }) + + return controller +} + +// Run will set up the event handlers for types we are interested in, as well +// as syncing informer caches and starting workers. It will block until stopCh +// is closed, at which point it will shutdown the workqueue and wait for +// workers to finish processing their current work items. +func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { + defer runtime.HandleCrash() + defer c.workqueue.ShutDown() + + // Start the informer factories to begin populating the informer caches + glog.Info("Starting Channel controller") + + // Wait for the caches to be synced before starting workers + glog.Info("Waiting for informer caches to sync") + if ok := cache.WaitForCacheSync(stopCh, c.ingressesSynced, c.servicesSynced, c.channelsSynced); !ok { + return fmt.Errorf("failed to wait for caches to sync") + } + + glog.Info("Starting workers") + // Launch two workers to process Channel resources + for i := 0; i < threadiness; i++ { + go wait.Until(c.runWorker, time.Second, stopCh) + } + + glog.Info("Started workers") + <-stopCh + glog.Info("Shutting down workers") + + return nil +} + +// runWorker is a long-running function that will continually call the +// processNextWorkItem function in order to read and process a message on the +// workqueue. +func (c *Controller) runWorker() { + for c.processNextWorkItem() { + } +} + +// processNextWorkItem will read a single work item off the workqueue and +// attempt to process it, by calling the syncHandler. +func (c *Controller) processNextWorkItem() bool { + obj, shutdown := c.workqueue.Get() + + if shutdown { + return false + } + + // We wrap this block in a func so we can defer c.workqueue.Done. + err := func(obj interface{}) error { + // We call Done here so the workqueue knows we have finished + // processing this item. We also must remember to call Forget if we + // do not want this work item being re-queued. For example, we do + // not call Forget if a transient error occurs, instead the item is + // put back on the workqueue and attempted again after a back-off + // period. + defer c.workqueue.Done(obj) + var key string + var ok bool + // We expect strings to come off the workqueue. These are of the + // form namespace/name. We do this as the delayed nature of the + // workqueue means the items in the informer cache may actually be + // more up to date that when the item was initially put onto the + // workqueue. + if key, ok = obj.(string); !ok { + // As the item in the workqueue is actually invalid, we call + // Forget here else we'd go into a loop of attempting to + // process a work item that is invalid. + c.workqueue.Forget(obj) + runtime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj)) + return nil + } + // Run the syncHandler, passing it the namespace/name string of the + // Channel resource to be synced. + if err := c.syncHandler(key); err != nil { + return fmt.Errorf("error syncing channel '%s': %s", key, err.Error()) + } + // Finally, if no error occurs we Forget this item so it does not + // get queued again until another change happens. + c.workqueue.Forget(obj) + glog.Infof("Successfully synced channel '%s'", key) + return nil + }(obj) + + if err != nil { + runtime.HandleError(err) + return true + } + + return true +} + +// syncHandler compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Channel resource +// with the current status of the resource. +func (c *Controller) syncHandler(key string) error { + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + runtime.HandleError(fmt.Errorf("invalid resource key: %s", key)) + return nil + } + + // Get the Channel resource with this namespace/name + channel, err := c.channelsLister.Channels(namespace).Get(name) + if err != nil { + // The Channel resource may no longer exist, in which case we stop + // processing. + if errors.IsNotFound(err) { + runtime.HandleError(fmt.Errorf("channel '%s' in work queue no longer exists", key)) + return nil + } + + return err + } + + // Sync Service derived from the Channel + service, err := c.syncChannelService(channel) + if err != nil { + return err + } + + // Sync RouteRule derived from a Channel + routeRule, err := c.syncChannelRouteRule(channel) + if err != nil { + return err + } + + // Sync Ingress derived from the Channel + ingress, err := c.syncChannelIngress(channel) + if err != nil { + return err + } + + // Finally, we update the status block of the Channel resource to reflect the + // current state of the world + err = c.updateChannelStatus(channel, service, ingress, routeRule) + if err != nil { + return err + } + + c.recorder.Event(channel, corev1.EventTypeNormal, SuccessSynced, MessageResourceSynced) + return nil +} + +func (c *Controller) syncChannelService(channel *channelsv1alpha1.Channel) (*corev1.Service, error) { + // Get the service with the specified service name + serviceName := controller.ChannelServiceName(channel.ObjectMeta.Name) + service, err := c.servicesLister.Services(channel.Namespace).Get(serviceName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + service, err = c.kubeclientset.CoreV1().Services(channel.Namespace).Create(newService(channel)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Service is not controlled by this Channel resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(service, channel) { + msg := fmt.Sprintf(MessageResourceExists, service.Name) + c.recorder.Event(channel, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + return service, nil +} + +func (c *Controller) syncChannelRouteRule(channel *channelsv1alpha1.Channel) (*istiov1alpha2.RouteRule, error) { + // Get the RouteRule with the specified Channel name + routeruleName := controller.ChannelRouteRuleName(channel.ObjectMeta.Name) + routerule, err := c.routerulesLister.RouteRules(channel.Namespace).Get(routeruleName) + + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + routerule, err = c.channelclientset.ConfigV1alpha2().RouteRules(channel.Namespace).Create(newRouteRule(channel)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Service is not controlled by this Channel resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(routerule, channel) { + msg := fmt.Sprintf(MessageResourceExists, routerule.Name) + c.recorder.Event(channel, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + return routerule, nil +} + +func (c *Controller) syncChannelIngress(channel *channelsv1alpha1.Channel) (*extensionsv1beta1.Ingress, error) { + // TODO make ingress optional + + // Get the ingress with the specified ingress name + ingressName := controller.ChannelIngressName(channel.ObjectMeta.Name) + ingress, err := c.ingressesLister.Ingresses(channel.Namespace).Get(ingressName) + // If the resource doesn't exist, we'll create it + if errors.IsNotFound(err) { + ingress, err = c.kubeclientset.ExtensionsV1beta1().Ingresses(channel.Namespace).Create(newIngress(channel)) + } + + // If an error occurs during Get/Create, we'll requeue the item so we can + // attempt processing again later. This could have been caused by a + // temporary network failure, or any other transient reason. + if err != nil { + return nil, err + } + + // If the Ingress is not controlled by this Channel resource, we should log + // a warning to the event recorder and return + if !metav1.IsControlledBy(ingress, channel) { + msg := fmt.Sprintf(MessageResourceExists, ingress.Name) + c.recorder.Event(channel, corev1.EventTypeWarning, ErrResourceExists, msg) + return nil, fmt.Errorf(msg) + } + + return ingress, nil +} + +func (c *Controller) updateChannelStatus(channel *channelsv1alpha1.Channel, service *corev1.Service, ingress *extensionsv1beta1.Ingress, routeRule *istiov1alpha2.RouteRule) error { + // NEVER modify objects from the store. It's a read-only, local cache. + // You can use DeepCopy() to make a deep copy of original object and modify this copy + // Or create a copy manually for better performance + channelCopy := channel.DeepCopy() + // If the CustomResourceSubresources feature gate is not enabled, + // we must use Update instead of UpdateStatus to update the Status block of the Channel resource. + // UpdateStatus will not allow changes to the Spec of the resource, + // which is ideal for ensuring nothing other than resource status has been updated. + _, err := c.channelclientset.ChannelsV1alpha1().Channels(channel.Namespace).Update(channelCopy) + return err +} + +// enqueueChannel takes a Channel resource and converts it into a namespace/name +// string which is then put onto the work queue. This method should *not* be +// passed resources of any type other than Channel. +func (c *Controller) enqueueChannel(obj interface{}) { + var key string + var err error + if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil { + runtime.HandleError(err) + return + } + c.workqueue.AddRateLimited(key) +} + +// handleObject will take any resource implementing metav1.Object and attempt +// to find the Channel resource that 'owns' it. It does this by looking at the +// objects metadata.ownerReferences field for an appropriate OwnerReference. +// It then enqueues that Channel resource to be processed. If the object does not +// have an appropriate OwnerReference, it will simply be skipped. +func (c *Controller) handleObject(obj interface{}) { + var object metav1.Object + var ok bool + if object, ok = obj.(metav1.Object); !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + runtime.HandleError(fmt.Errorf("error decoding object, invalid type")) + return + } + object, ok = tombstone.Obj.(metav1.Object) + if !ok { + runtime.HandleError(fmt.Errorf("error decoding object tombstone, invalid type")) + return + } + glog.V(4).Infof("Recovered deleted object '%s' from tombstone", object.GetName()) + } + glog.V(4).Infof("Processing object: %s", object.GetName()) + if ownerRef := metav1.GetControllerOf(object); ownerRef != nil { + // If this object is not owned by a Channel, we should not do anything more + // with it. + if ownerRef.Kind != "Channel" { + return + } + + channel, err := c.channelsLister.Channels(object.GetNamespace()).Get(ownerRef.Name) + if err != nil { + glog.V(4).Infof("ignoring orphaned object '%s' of channel '%s'", object.GetSelfLink(), ownerRef.Name) + return + } + + c.enqueueChannel(channel) + return + } +} + +// newService creates a new Service for a Channel resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Channel resource that 'owns' it. +func newService(channel *channelsv1alpha1.Channel) *corev1.Service { + labels := map[string]string{ + "channel": channel.Name, + } + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.ChannelServiceName(channel.ObjectMeta.Name), + Namespace: channel.Namespace, + Labels: labels, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(channel, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Channel", + }), + }, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + {Name: "http", Port: 80}, + }, + }, + } +} + +// newRouteRule creates a new RouteRule for a Channel resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Channel resource that 'owns' it. +func newRouteRule(channel *channelsv1alpha1.Channel) *istiov1alpha2.RouteRule { + labels := map[string]string{ + "bus": channel.Spec.Bus, + "channel": channel.Name, + } + return &istiov1alpha2.RouteRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.ChannelRouteRuleName(channel.Name), + Namespace: channel.Namespace, + Labels: labels, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(channel, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Channel", + }), + }, + }, + Spec: istiov1alpha2.RouteRuleSpec{ + Destination: istiov1alpha2.IstioService{ + Name: controller.ChannelServiceName(channel.Name), + }, + Route: []istiov1alpha2.DestinationWeight{ + { + Destination: istiov1alpha2.IstioService{ + Name: controller.BusDispatcherServiceName(channel.Spec.Bus), + }, + Weight: 100, + }, + }, + Rewrite: istiov1alpha2.HTTPRewrite{ + Authority: fmt.Sprintf("%s.%s.channels.cluster.local", channel.Name, channel.Namespace), + }, + }, + } +} + +// newIngress creates a new Ingress for a Channel resource. It also sets +// the appropriate OwnerReferences on the resource so handleObject can discover +// the Channel resource that 'owns' it. +func newIngress(channel *channelsv1alpha1.Channel) *extensionsv1beta1.Ingress { + labels := map[string]string{ + "channel": channel.Name, + } + annotations := map[string]string{ + "kubernetes.io/ingress.class": "istio", + } + return &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.ChannelIngressName(channel.ObjectMeta.Name), + Namespace: channel.Namespace, + Labels: labels, + Annotations: annotations, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(channel, schema.GroupVersionKind{ + Group: channelsv1alpha1.SchemeGroupVersion.Group, + Version: channelsv1alpha1.SchemeGroupVersion.Version, + Kind: "Channel", + }), + }, + }, + Spec: extensionsv1beta1.IngressSpec{ + Rules: []extensionsv1beta1.IngressRule{ + { + // TODO make host name configurable + Host: channel.ObjectMeta.Name, + IngressRuleValue: extensionsv1beta1.IngressRuleValue{ + HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ + Paths: []extensionsv1beta1.HTTPIngressPath{ + { + Backend: extensionsv1beta1.IngressBackend{ + ServiceName: controller.ChannelServiceName(channel.ObjectMeta.Name), + ServicePort: intstr.FromString("http"), + }, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/controller/names.go b/pkg/controller/names.go new file mode 100644 index 00000000000..587d151e13a --- /dev/null +++ b/pkg/controller/names.go @@ -0,0 +1,51 @@ +/* + * Copyright 2018 the original author or 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 controller + +import "fmt" + +func BusProvisionerDeploymentName(busName string) string { + return fmt.Sprintf("%s-bus-provisioner", busName) +} + +func BusDispatcherDeploymentName(busName string) string { + return fmt.Sprintf("%s-bus", busName) +} + +func BusServiceAccountName(busName string) string { + return fmt.Sprintf("%s-bus", busName) +} + +func BusClusterRoleBindingName(busName string) string { + return fmt.Sprintf("%s-bus", busName) +} + +func BusDispatcherServiceName(busName string) string { + return fmt.Sprintf("%s-bus", busName) +} + +func ChannelRouteRuleName(channelName string) string { + return fmt.Sprintf("%s-channel", channelName) +} + +func ChannelIngressName(channelName string) string { + return fmt.Sprintf("%s-channel", channelName) +} + +func ChannelServiceName(channelName string) string { + return fmt.Sprintf("%s-channel", channelName) +} diff --git a/pkg/subscription/monitor.go b/pkg/subscription/monitor.go new file mode 100644 index 00000000000..ff41aea1ab0 --- /dev/null +++ b/pkg/subscription/monitor.go @@ -0,0 +1,348 @@ +/* + * Copyright 2018 the original author or 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 subscription + +import ( + "reflect" + "sync" + + "github.com/golang/glog" + channelsv1alpha1 "github.com/knative/eventing/pkg/apis/channels/v1alpha1" + informers "github.com/knative/eventing/pkg/client/informers/externalversions" + "k8s.io/client-go/tools/cache" +) + +// Monitor utility to manage channels and subscriptions for a bus +type Monitor struct { + busName string + handler MonitorEventHandlerFuncs + + bus *channelsv1alpha1.BusSpec + cache map[channelKey]*channelSummary + mutex *sync.Mutex +} + +// MonitorEventHandlerFuncs handler functions for channel and subscription provisioning +type MonitorEventHandlerFuncs struct { + ProvisionFunc func(channel channelsv1alpha1.Channel) + UnprovisionFunc func(channel channelsv1alpha1.Channel) + SubscribeFunc func(subscription channelsv1alpha1.Subscription) + UnsubscribeFunc func(subscription channelsv1alpha1.Subscription) +} + +type channelSummary struct { + Channel *channelsv1alpha1.ChannelSpec + Subscriptions map[subscriptionKey]subscriptionSummary +} + +type subscriptionSummary struct { + Subscription channelsv1alpha1.SubscriptionSpec +} + +// NewMonitor creates a monitor for a bus +func NewMonitor(busName string, informerFactory informers.SharedInformerFactory, handler MonitorEventHandlerFuncs) *Monitor { + + busInformer := informerFactory.Channels().V1alpha1().Buses() + channelInformer := informerFactory.Channels().V1alpha1().Channels() + subscriptionInformer := informerFactory.Channels().V1alpha1().Subscriptions() + + monitor := &Monitor{ + busName: busName, + handler: handler, + + bus: nil, + cache: make(map[channelKey]*channelSummary), + mutex: &sync.Mutex{}, + } + + glog.Info("Setting up event handlers") + // Set up an event handler for when Bus resources change + busInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + bus := obj.(*channelsv1alpha1.Bus) + monitor.createOrUpdateBus(*bus) + }, + UpdateFunc: func(old, new interface{}) { + oldBus := old.(*channelsv1alpha1.Bus) + newBus := new.(*channelsv1alpha1.Bus) + + if oldBus.ResourceVersion == newBus.ResourceVersion { + // Periodic resync will send update events for all known Buses. + // Two different versions of the same Bus will always have different RVs. + return + } + + monitor.createOrUpdateBus(*newBus) + }, + }) + // Set up an event handler for when Channel resources change + channelInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + channel := obj.(*channelsv1alpha1.Channel) + monitor.createOrUpdateChannel(*channel) + }, + UpdateFunc: func(old, new interface{}) { + oldChannel := old.(*channelsv1alpha1.Channel) + newChannel := new.(*channelsv1alpha1.Channel) + + if oldChannel.ResourceVersion == newChannel.ResourceVersion { + // Periodic resync will send update events for all known Channels. + // Two different versions of the same Channel will always have different RVs. + return + } + + monitor.createOrUpdateChannel(*newChannel) + if oldChannel.Spec.Bus != newChannel.Spec.Bus { + monitor.removeChannel(*oldChannel) + } + }, + DeleteFunc: func(obj interface{}) { + channel := obj.(*channelsv1alpha1.Channel) + monitor.removeChannel(*channel) + }, + }) + // Set up an event handler for when Subscription resources change + subscriptionInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + subscription := obj.(*channelsv1alpha1.Subscription) + monitor.createOrUpdateSubscription(*subscription) + }, + UpdateFunc: func(old, new interface{}) { + oldSubscription := old.(*channelsv1alpha1.Subscription) + newSubscription := new.(*channelsv1alpha1.Subscription) + + if oldSubscription.ResourceVersion == newSubscription.ResourceVersion { + // Periodic resync will send update events for all known Subscriptions. + // Two different versions of the same Subscription will always have different RVs. + return + } + + monitor.createOrUpdateSubscription(*newSubscription) + if oldSubscription.Spec.Channel != newSubscription.Spec.Channel { + monitor.removeSubscription(*oldSubscription) + } + }, + DeleteFunc: func(obj interface{}) { + subscription := obj.(*channelsv1alpha1.Subscription) + monitor.removeSubscription(*subscription) + }, + }) + + return monitor +} + +// Channel for a channel name and namespace +func (m *Monitor) Channel(channel string, namespace string) *channelsv1alpha1.ChannelSpec { + channelKey := makeChannelKeyWithNames(channel, namespace) + summary := m.getChannelSummary(channelKey) + + if summary == nil { + return nil + } + return summary.Channel +} + +// Subscriptions for a channel name and namespace +func (m *Monitor) Subscriptions(channel string, namespace string) *[]channelsv1alpha1.SubscriptionSpec { + channelKey := makeChannelKeyWithNames(channel, namespace) + summary := m.getChannelSummary(channelKey) + + if summary == nil || summary.Channel == nil { + // the channel is unknown + return nil + } + + if summary.Channel.Bus != m.busName { + // the channel is not for this bus + return nil + } + + m.mutex.Lock() + subscriptions := make([]channelsv1alpha1.SubscriptionSpec, len(summary.Subscriptions)-1) + for _, subscription := range summary.Subscriptions { + subscriptions = append(subscriptions, subscription.Subscription) + } + m.mutex.Unlock() + + return &subscriptions +} + +// ChannelParams resolve parameters for a channel +func (m *Monitor) ChannelParams(channel channelsv1alpha1.ChannelSpec) map[string]string { + params := make(map[string]string) + + // apply bus defaults + if m.bus.Parameters != nil { + for _, param := range *m.bus.Parameters { + if param.Default != nil { + params[param.Name] = *param.Default + } + } + } + // apply channel arguments + if channel.Arguments != nil { + for _, arg := range *channel.Arguments { + // TODO ignore arguments not defined by parameters + params[arg.Name] = arg.Value + } + } + + return params +} + +// SubscriptionParams resolve parameters for a subscription +func (m *Monitor) SubscriptionParams( + channel channelsv1alpha1.ChannelSpec, + subscription channelsv1alpha1.SubscriptionSpec, +) map[string]string { + params := m.ChannelParams(channel) + + // apply channel defaults + if channel.Parameters != nil { + for _, param := range *channel.Parameters { + if _, ok := params[param.Name]; !ok && param.Default != nil { + params[param.Name] = *param.Default + } + } + } + // apply subscription arguments + if subscription.Arguments != nil { + for _, arg := range *subscription.Arguments { + // TODO ignore arguments not defined by parameters + params[arg.Name] = arg.Value + } + } + + return params +} + +func (m *Monitor) getChannelSummary(key channelKey) *channelSummary { + return m.cache[key] +} + +func (m *Monitor) getOrCreateChannelSummary(key channelKey) *channelSummary { + m.mutex.Lock() + summary, ok := m.cache[key] + if !ok { + summary = &channelSummary{ + Channel: nil, + Subscriptions: make(map[subscriptionKey]subscriptionSummary), + } + m.cache[key] = summary + } + m.mutex.Unlock() + + return summary +} + +func (m *Monitor) createOrUpdateBus(bus channelsv1alpha1.Bus) { + if bus.Name != m.busName { + // this is not our bus + return + } + if !reflect.DeepEqual(m.bus, bus.Spec) { + m.bus = &bus.Spec + } +} + +func (m *Monitor) createOrUpdateChannel(channel channelsv1alpha1.Channel) { + channelKey := makeChannelKeyFromChannel(channel) + summary := m.getOrCreateChannelSummary(channelKey) + + m.mutex.Lock() + old := summary.Channel + new := &channel.Spec + summary.Channel = new + m.mutex.Unlock() + + if !reflect.DeepEqual(old, new) { + m.handler.ProvisionFunc(channel) + } +} + +func (m *Monitor) removeChannel(channel channelsv1alpha1.Channel) { + channelKey := makeChannelKeyFromChannel(channel) + summary := m.getOrCreateChannelSummary(channelKey) + + m.mutex.Lock() + summary.Channel = nil + m.mutex.Unlock() + + m.handler.UnprovisionFunc(channel) +} + +func (m *Monitor) createOrUpdateSubscription(subscription channelsv1alpha1.Subscription) { + channelKey := makeChannelKeyFromSubscription(subscription) + summary := m.getOrCreateChannelSummary(channelKey) + subscriptionKey := makeSubscriptionKeyFromSubscription(subscription) + + m.mutex.Lock() + old := summary.Subscriptions[subscriptionKey] + new := subscriptionSummary{ + Subscription: subscription.Spec, + } + summary.Subscriptions[subscriptionKey] = new + m.mutex.Unlock() + + if !reflect.DeepEqual(old.Subscription, new.Subscription) { + m.handler.SubscribeFunc(subscription) + } +} + +func (m *Monitor) removeSubscription(subscription channelsv1alpha1.Subscription) { + channelKey := makeChannelKeyFromSubscription(subscription) + summary := m.getOrCreateChannelSummary(channelKey) + subscriptionKey := makeSubscriptionKeyFromSubscription(subscription) + + m.mutex.Lock() + delete(summary.Subscriptions, subscriptionKey) + m.mutex.Unlock() + + m.handler.UnsubscribeFunc(subscription) +} + +type channelKey struct { + Name string + Namespace string +} + +func makeChannelKeyFromChannel(channel channelsv1alpha1.Channel) channelKey { + return makeChannelKeyWithNames(channel.Name, channel.Namespace) +} + +func makeChannelKeyFromSubscription(subscription channelsv1alpha1.Subscription) channelKey { + return makeChannelKeyWithNames(subscription.Spec.Channel, subscription.Namespace) +} + +func makeChannelKeyWithNames(name string, namespace string) channelKey { + return channelKey{ + Name: name, + Namespace: namespace, + } +} + +type subscriptionKey struct { + Name string + Namespace string +} + +func makeSubscriptionKeyFromSubscription(subscription channelsv1alpha1.Subscription) subscriptionKey { + return subscriptionKey{ + Name: subscription.Name, + Namespace: subscription.Namespace, + } +} diff --git a/sample/hello/README.md b/sample/hello/README.md new file mode 100644 index 00000000000..56515b1b695 --- /dev/null +++ b/sample/hello/README.md @@ -0,0 +1,85 @@ +The hello sample includes a Knative Service, Channel and Subscription. + +# Deploy + +First, install the Stub bus, if not already installed: + +``` +ko apply -f config/buses/stub.yaml +``` + +Then, install the Buildpack build template if not already installed: + +```shell +kubectl apply -f https://github.com/knative/build-templates/raw/master/buildpack/buildpack.yaml +``` + +Then, deploy the hello function, channel and subscription: + +```shell +# Replace the token string with a suitable registry +REPO="gcr.io/" +perl -pi -e "s@DOCKER_REPO_OVERRIDE@$REPO@g" sample/hello/hello-service.yaml + +kubectl apply -f sample/hello/ +``` + +The service will build and deploy the function and expose an ingress for the function and channel. It may take a minute, but eventually you should see something similar to: + +``` +$ watch -n1 kubectl get ing +NAME HOSTS ADDRESS PORTS +aloha-channel aloha 1.2.3.4 80 +hello-ingress hello.default.demo-domain.com,*.hello.default.demo-domain.com 1.2.3.4 80 +``` + +# Invoke + +The hello function is reachable either directly via the route created by the hello service, or by the aloha channel. + +We can use kail to watch the log output for the function. In a separte shell run: + +``` +kail -d hello-00001-deployment +``` + +To invoke the function directly: + +``` +# Put the Ingress Host name into an environment variable. +$ export SERVICE_HOST=`kubectl get route hello -o jsonpath="{.status.domain}"` + +# Put the Ingress IP into an environment variable. +$ export SERVICE_IP=`kubectl get ingress hello-ingress -o jsonpath="{.status.loadBalancer.ingress[*]['ip']}"` + +# Curl the Ingress IP "as-if" DNS were properly configured. +$ curl -H "Host: $SERVICE_HOST" -H "Content-Type: text/plain" $SERVICE_IP -d "Knative" +[response] +``` + +You should see a response like: + +> hello knative from hello-00001-deployment-5fb4b845fd-7h2lc + +Unlike with direct access, when invoking over the channel, the caller will not recieve a response directly. + +We can use kail to watch the log output from the bus. In a separte shell run: + +``` +kail -d stub-bus -c dispatcher +``` + +To invoke the function via the channel: + +``` +# Put the Ingress Host name into an environment variable. +$ export SERVICE_HOST=`kubectl get ingress aloha-channel -o jsonpath="{.spec.rules[0].host}"` + +# Put the Ingress IP into an environment variable. +$ export SERVICE_IP=`kubectl get ingress aloha-channel -o jsonpath="{.status.loadBalancer.ingress[*]['ip']}"` + +# Curl the Ingress IP "as-if" DNS were properly configured. +$ curl -H "Host: $SERVICE_HOST" -H "Content-Type: text/plain" $SERVICE_IP -d "Knative" +``` + +This time there should be no response via curl, but you should see logging from the bus and the function indicating it received the request. diff --git a/sample/hello/hello-channel.yaml b/sample/hello/hello-channel.yaml new file mode 100644 index 00000000000..482f12da2de --- /dev/null +++ b/sample/hello/hello-channel.yaml @@ -0,0 +1,15 @@ +apiVersion: channels.knative.dev/v1alpha1 +kind: Channel +metadata: + name: aloha +spec: + bus: stub + +--- +apiVersion: channels.knative.dev/v1alpha1 +kind: Subscription +metadata: + name: aloha2hello +spec: + channel: aloha + subscriber: hello-00001-service diff --git a/sample/hello/hello-service.yaml b/sample/hello/hello-service.yaml new file mode 100644 index 00000000000..8f09a605638 --- /dev/null +++ b/sample/hello/hello-service.yaml @@ -0,0 +1,35 @@ +apiVersion: serving.knative.dev/v1alpha1 +kind: Service +metadata: + name: hello +spec: + runLatest: + configuration: + build: + source: + git: + url: https://github.com/projectriff-samples/node-hello + branch: master + template: + name: buildpack + arguments: + - name: IMAGE + value: &image DOCKER_REPO_OVERRIDE/hello + - name: BUILDPACK_ORDER + value: https://github.com/projectriff/node-function-invoker.git#buildpack + - name: SKIP_DETECT + value: "true" + # - name: CACHE + # value: buildpack-function-cache + # volumes: + # - name: buildpack-function-cache + # persistentVolumeClaim: + # claimName: buildpack-function-cache + + revisionTemplate: + metadata: + labels: + knative.dev/type: function + spec: + container: + image: *image diff --git a/vendor/github.com/codegangsta/inject/LICENSE b/vendor/github.com/codegangsta/inject/LICENSE new file mode 100644 index 00000000000..eb68a0e0585 --- /dev/null +++ b/vendor/github.com/codegangsta/inject/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/codegangsta/inject/inject.go b/vendor/github.com/codegangsta/inject/inject.go new file mode 100644 index 00000000000..3ff713c8a85 --- /dev/null +++ b/vendor/github.com/codegangsta/inject/inject.go @@ -0,0 +1,187 @@ +// Package inject provides utilities for mapping and injecting dependencies in various ways. +package inject + +import ( + "fmt" + "reflect" +) + +// Injector represents an interface for mapping and injecting dependencies into structs +// and function arguments. +type Injector interface { + Applicator + Invoker + TypeMapper + // SetParent sets the parent of the injector. If the injector cannot find a + // dependency in its Type map it will check its parent before returning an + // error. + SetParent(Injector) +} + +// Applicator represents an interface for mapping dependencies to a struct. +type Applicator interface { + // Maps dependencies in the Type map to each field in the struct + // that is tagged with 'inject'. Returns an error if the injection + // fails. + Apply(interface{}) error +} + +// Invoker represents an interface for calling functions via reflection. +type Invoker interface { + // Invoke attempts to call the interface{} provided as a function, + // providing dependencies for function arguments based on Type. Returns + // a slice of reflect.Value representing the returned values of the function. + // Returns an error if the injection fails. + Invoke(interface{}) ([]reflect.Value, error) +} + +// TypeMapper represents an interface for mapping interface{} values based on type. +type TypeMapper interface { + // Maps the interface{} value based on its immediate type from reflect.TypeOf. + Map(interface{}) TypeMapper + // Maps the interface{} value based on the pointer of an Interface provided. + // This is really only useful for mapping a value as an interface, as interfaces + // cannot at this time be referenced directly without a pointer. + MapTo(interface{}, interface{}) TypeMapper + // Provides a possibility to directly insert a mapping based on type and value. + // This makes it possible to directly map type arguments not possible to instantiate + // with reflect like unidirectional channels. + Set(reflect.Type, reflect.Value) TypeMapper + // Returns the Value that is mapped to the current type. Returns a zeroed Value if + // the Type has not been mapped. + Get(reflect.Type) reflect.Value +} + +type injector struct { + values map[reflect.Type]reflect.Value + parent Injector +} + +// InterfaceOf dereferences a pointer to an Interface type. +// It panics if value is not an pointer to an interface. +func InterfaceOf(value interface{}) reflect.Type { + t := reflect.TypeOf(value) + + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + if t.Kind() != reflect.Interface { + panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") + } + + return t +} + +// New returns a new Injector. +func New() Injector { + return &injector{ + values: make(map[reflect.Type]reflect.Value), + } +} + +// Invoke attempts to call the interface{} provided as a function, +// providing dependencies for function arguments based on Type. +// Returns a slice of reflect.Value representing the returned values of the function. +// Returns an error if the injection fails. +// It panics if f is not a function +func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { + t := reflect.TypeOf(f) + + var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func + for i := 0; i < t.NumIn(); i++ { + argType := t.In(i) + val := inj.Get(argType) + if !val.IsValid() { + return nil, fmt.Errorf("Value not found for type %v", argType) + } + + in[i] = val + } + + return reflect.ValueOf(f).Call(in), nil +} + +// Maps dependencies in the Type map to each field in the struct +// that is tagged with 'inject'. +// Returns an error if the injection fails. +func (inj *injector) Apply(val interface{}) error { + v := reflect.ValueOf(val) + + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + return nil // Should not panic here ? + } + + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + structField := t.Field(i) + if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") { + ft := f.Type() + v := inj.Get(ft) + if !v.IsValid() { + return fmt.Errorf("Value not found for type %v", ft) + } + + f.Set(v) + } + + } + + return nil +} + +// Maps the concrete value of val to its dynamic type using reflect.TypeOf, +// It returns the TypeMapper registered in. +func (i *injector) Map(val interface{}) TypeMapper { + i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) + return i +} + +func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { + i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) + return i +} + +// Maps the given reflect.Type to the given reflect.Value and returns +// the Typemapper the mapping has been registered in. +func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { + i.values[typ] = val + return i +} + +func (i *injector) Get(t reflect.Type) reflect.Value { + val := i.values[t] + + if val.IsValid() { + return val + } + + // no concrete types found, try to find implementors + // if t is an interface + if t.Kind() == reflect.Interface { + for k, v := range i.values { + if k.Implements(t) { + val = v + break + } + } + } + + // Still no type found, try to look it up on the parent + if !val.IsValid() && i.parent != nil { + val = i.parent.Get(t) + } + + return val + +} + +func (i *injector) SetParent(parent Injector) { + i.parent = parent +} diff --git a/vendor/github.com/go-martini/martini/LICENSE b/vendor/github.com/go-martini/martini/LICENSE new file mode 100644 index 00000000000..eb68a0e0585 --- /dev/null +++ b/vendor/github.com/go-martini/martini/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/go-martini/martini/env.go b/vendor/github.com/go-martini/martini/env.go new file mode 100644 index 00000000000..9bf15b5f61c --- /dev/null +++ b/vendor/github.com/go-martini/martini/env.go @@ -0,0 +1,25 @@ +package martini + +import ( + "os" +) + +// Envs +const ( + Dev string = "development" + Prod string = "production" + Test string = "test" +) + +// Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable. +var Env = Dev + +func setENV(e string) { + if len(e) > 0 { + Env = e + } +} + +func init() { + setENV(os.Getenv("MARTINI_ENV")) +} diff --git a/vendor/github.com/go-martini/martini/go_version.go b/vendor/github.com/go-martini/martini/go_version.go new file mode 100644 index 00000000000..bd271a8cf44 --- /dev/null +++ b/vendor/github.com/go-martini/martini/go_version.go @@ -0,0 +1,7 @@ +// +build !go1.1 + +package martini + +func MartiniDoesNotSupportGo1Point0() { + "Martini requires Go 1.1 or greater." +} diff --git a/vendor/github.com/go-martini/martini/logger.go b/vendor/github.com/go-martini/martini/logger.go new file mode 100644 index 00000000000..d01107c3bf6 --- /dev/null +++ b/vendor/github.com/go-martini/martini/logger.go @@ -0,0 +1,29 @@ +package martini + +import ( + "log" + "net/http" + "time" +) + +// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out. +func Logger() Handler { + return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) { + start := time.Now() + + addr := req.Header.Get("X-Real-IP") + if addr == "" { + addr = req.Header.Get("X-Forwarded-For") + if addr == "" { + addr = req.RemoteAddr + } + } + + log.Printf("Started %s %s for %s", req.Method, req.URL.Path, addr) + + rw := res.(ResponseWriter) + c.Next() + + log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) + } +} diff --git a/vendor/github.com/go-martini/martini/martini.go b/vendor/github.com/go-martini/martini/martini.go new file mode 100644 index 00000000000..a9e4dbcb98f --- /dev/null +++ b/vendor/github.com/go-martini/martini/martini.go @@ -0,0 +1,175 @@ +// Package martini is a powerful package for quickly writing modular web applications/services in Golang. +// +// For a full guide visit http://github.com/go-martini/martini +// +// package main +// +// import "github.com/go-martini/martini" +// +// func main() { +// m := martini.Classic() +// +// m.Get("/", func() string { +// return "Hello world!" +// }) +// +// m.Run() +// } +package martini + +import ( + "log" + "net/http" + "os" + "reflect" + + "github.com/codegangsta/inject" +) + +// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level. +type Martini struct { + inject.Injector + handlers []Handler + action Handler + logger *log.Logger +} + +// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used. +func New() *Martini { + m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)} + m.Map(m.logger) + m.Map(defaultReturnHandler()) + return m +} + +// Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers. +// Will panic if any of the handlers is not a callable function +func (m *Martini) Handlers(handlers ...Handler) { + m.handlers = make([]Handler, 0) + for _, handler := range handlers { + m.Use(handler) + } +} + +// Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic(). +func (m *Martini) Action(handler Handler) { + validateHandler(handler) + m.action = handler +} + +// Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added. +func (m *Martini) Use(handler Handler) { + validateHandler(handler) + + m.handlers = append(m.handlers, handler) +} + +// ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server. +func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) { + m.createContext(res, req).run() +} + +// Run the http server. Listening on os.GetEnv("PORT") or 3000 by default. +func (m *Martini) Run() { + port := os.Getenv("PORT") + if port == "" { + port = "3000" + } + + host := os.Getenv("HOST") + + logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) + + logger.Printf("listening on %s:%s (%s)\n", host, port, Env) + logger.Fatalln(http.ListenAndServe(host+":"+port, m)) +} + +func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context { + c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0} + c.SetParent(m) + c.MapTo(c, (*Context)(nil)) + c.MapTo(c.rw, (*http.ResponseWriter)(nil)) + c.Map(req) + return c +} + +// ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience. +type ClassicMartini struct { + *Martini + Router +} + +// Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static. +// Classic also maps martini.Routes as a service. +func Classic() *ClassicMartini { + r := NewRouter() + m := New() + m.Use(Logger()) + m.Use(Recovery()) + m.Use(Static("public")) + m.MapTo(r, (*Routes)(nil)) + m.Action(r.Handle) + return &ClassicMartini{m, r} +} + +// Handler can be any callable function. Martini attempts to inject services into the handler's argument list. +// Martini will panic if an argument could not be fullfilled via dependency injection. +type Handler interface{} + +func validateHandler(handler Handler) { + if reflect.TypeOf(handler).Kind() != reflect.Func { + panic("martini handler must be a callable func") + } +} + +// Context represents a request context. Services can be mapped on the request level from this interface. +type Context interface { + inject.Injector + // Next is an optional function that Middleware Handlers can call to yield the until after + // the other Handlers have been executed. This works really well for any operations that must + // happen after an http request + Next() + // Written returns whether or not the response for this context has been written. + Written() bool +} + +type context struct { + inject.Injector + handlers []Handler + action Handler + rw ResponseWriter + index int +} + +func (c *context) handler() Handler { + if c.index < len(c.handlers) { + return c.handlers[c.index] + } + if c.index == len(c.handlers) { + return c.action + } + panic("invalid index for context handler") +} + +func (c *context) Next() { + c.index += 1 + c.run() +} + +func (c *context) Written() bool { + return c.rw.Written() +} + +func (c *context) run() { + for c.index <= len(c.handlers) { + _, err := c.Invoke(c.handler()) + if err != nil { + panic(err) + } + c.index += 1 + + if c.Written() { + return + } + } +} diff --git a/vendor/github.com/go-martini/martini/recovery.go b/vendor/github.com/go-martini/martini/recovery.go new file mode 100644 index 00000000000..722622acd74 --- /dev/null +++ b/vendor/github.com/go-martini/martini/recovery.go @@ -0,0 +1,142 @@ +package martini + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "runtime" + + "github.com/codegangsta/inject" +) + +const ( + panicHtml = ` +PANIC: %s + + +

PANIC

+
%s
+
%s
+ +` +) + +var ( + dunno = []byte("???") + centerDot = []byte("·") + dot = []byte(".") + slash = []byte("/") +) + +// stack returns a nicely formated stack frame, skipping skip frames +func stack(skip int) []byte { + buf := new(bytes.Buffer) // the returned data + // As we loop, we open files and read them. These variables record the currently + // loaded file. + var lines [][]byte + var lastFile string + for i := skip; ; i++ { // Skip the expected number of frames + pc, file, line, ok := runtime.Caller(i) + if !ok { + break + } + // Print this much at least. If we can't find the source, it won't show. + fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) + if file != lastFile { + data, err := ioutil.ReadFile(file) + if err != nil { + continue + } + lines = bytes.Split(data, []byte{'\n'}) + lastFile = file + } + fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) + } + return buf.Bytes() +} + +// source returns a space-trimmed slice of the n'th line. +func source(lines [][]byte, n int) []byte { + n-- // in stack trace, lines are 1-indexed but our array is 0-indexed + if n < 0 || n >= len(lines) { + return dunno + } + return bytes.TrimSpace(lines[n]) +} + +// function returns, if possible, the name of the function containing the PC. +func function(pc uintptr) []byte { + fn := runtime.FuncForPC(pc) + if fn == nil { + return dunno + } + name := []byte(fn.Name()) + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Also the package path might contains dot (e.g. code.google.com/...), + // so first eliminate the path prefix + if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 { + name = name[lastslash+1:] + } + if period := bytes.Index(name, dot); period >= 0 { + name = name[period+1:] + } + name = bytes.Replace(name, centerDot, dot, -1) + return name +} + +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +// While Martini is in development mode, Recovery will also output the panic as HTML. +func Recovery() Handler { + return func(c Context, log *log.Logger) { + defer func() { + if err := recover(); err != nil { + stack := stack(3) + log.Printf("PANIC: %s\n%s", err, stack) + + // Lookup the current responsewriter + val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := val.Interface().(http.ResponseWriter) + + // respond with panic message while in development mode + var body []byte + if Env == Dev { + res.Header().Set("Content-Type", "text/html") + body = []byte(fmt.Sprintf(panicHtml, err, err, stack)) + } + + res.WriteHeader(http.StatusInternalServerError) + if nil != body { + res.Write(body) + } + } + }() + + c.Next() + } +} diff --git a/vendor/github.com/go-martini/martini/response_writer.go b/vendor/github.com/go-martini/martini/response_writer.go new file mode 100644 index 00000000000..fc161534884 --- /dev/null +++ b/vendor/github.com/go-martini/martini/response_writer.go @@ -0,0 +1,97 @@ +package martini + +import ( + "bufio" + "fmt" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + http.Flusher + // Status returns the status code of the response or 0 if the response has not been written. + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int + // Before allows for a function to be called before the ResponseWriter has been written to. This is + // useful for setting headers or any other operations that must happen before a response has been written. + Before(BeforeFunc) +} + +// BeforeFunc is a function that is called before the ResponseWriter has been written to. +type BeforeFunc func(ResponseWriter) + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { + return &responseWriter{rw, 0, 0, nil} +} + +type responseWriter struct { + http.ResponseWriter + status int + size int + beforeFuncs []BeforeFunc +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.callBefore() + rw.ResponseWriter.WriteHeader(s) + rw.status = s +} + +func (rw *responseWriter) Write(b []byte) (int, error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + size, err := rw.ResponseWriter.Write(b) + rw.size += size + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Before(before BeforeFunc) { + rw.beforeFuncs = append(rw.beforeFuncs, before) +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") + } + return hijacker.Hijack() +} + +func (rw *responseWriter) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +func (rw *responseWriter) callBefore() { + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { + rw.beforeFuncs[i](rw) + } +} + +func (rw *responseWriter) Flush() { + flusher, ok := rw.ResponseWriter.(http.Flusher) + if ok { + flusher.Flush() + } +} diff --git a/vendor/github.com/go-martini/martini/return_handler.go b/vendor/github.com/go-martini/martini/return_handler.go new file mode 100644 index 00000000000..4ea8f34b5e8 --- /dev/null +++ b/vendor/github.com/go-martini/martini/return_handler.go @@ -0,0 +1,43 @@ +package martini + +import ( + "github.com/codegangsta/inject" + "net/http" + "reflect" +) + +// ReturnHandler is a service that Martini provides that is called +// when a route handler returns something. The ReturnHandler is +// responsible for writing to the ResponseWriter based on the values +// that are passed into this function. +type ReturnHandler func(Context, []reflect.Value) + +func defaultReturnHandler() ReturnHandler { + return func(ctx Context, vals []reflect.Value) { + rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := rv.Interface().(http.ResponseWriter) + var responseVal reflect.Value + if len(vals) > 1 && vals[0].Kind() == reflect.Int { + res.WriteHeader(int(vals[0].Int())) + responseVal = vals[1] + } else if len(vals) > 0 { + responseVal = vals[0] + } + if canDeref(responseVal) { + responseVal = responseVal.Elem() + } + if isByteSlice(responseVal) { + res.Write(responseVal.Bytes()) + } else { + res.Write([]byte(responseVal.String())) + } + } +} + +func isByteSlice(val reflect.Value) bool { + return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8 +} + +func canDeref(val reflect.Value) bool { + return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr +} diff --git a/vendor/github.com/go-martini/martini/router.go b/vendor/github.com/go-martini/martini/router.go new file mode 100644 index 00000000000..034a7a2efe5 --- /dev/null +++ b/vendor/github.com/go-martini/martini/router.go @@ -0,0 +1,367 @@ +package martini + +import ( + "fmt" + "net/http" + "reflect" + "regexp" + "strconv" +) + +// Params is a map of name/value pairs for named routes. An instance of martini.Params is available to be injected into any route handler. +type Params map[string]string + +// Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection. +type Router interface { + Routes + + // Group adds a group where related routes can be added. + Group(string, func(Router), ...Handler) + // Get adds a route for a HTTP GET request to the specified matching pattern. + Get(string, ...Handler) Route + // Patch adds a route for a HTTP PATCH request to the specified matching pattern. + Patch(string, ...Handler) Route + // Post adds a route for a HTTP POST request to the specified matching pattern. + Post(string, ...Handler) Route + // Put adds a route for a HTTP PUT request to the specified matching pattern. + Put(string, ...Handler) Route + // Delete adds a route for a HTTP DELETE request to the specified matching pattern. + Delete(string, ...Handler) Route + // Options adds a route for a HTTP OPTIONS request to the specified matching pattern. + Options(string, ...Handler) Route + // Head adds a route for a HTTP HEAD request to the specified matching pattern. + Head(string, ...Handler) Route + // Any adds a route for any HTTP method request to the specified matching pattern. + Any(string, ...Handler) Route + + // NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default. + NotFound(...Handler) + + // Handle is the entry point for routing. This is used as a martini.Handler + Handle(http.ResponseWriter, *http.Request, Context) +} + +type router struct { + routes []*route + notFounds []Handler + groups []group +} + +type group struct { + pattern string + handlers []Handler +} + +// NewRouter creates a new Router instance. +// If you aren't using ClassicMartini, then you can add Routes as a +// service with: +// +// m := martini.New() +// r := martini.NewRouter() +// m.MapTo(r, (*martini.Routes)(nil)) +// +// If you are using ClassicMartini, then this is done for you. +func NewRouter() Router { + return &router{notFounds: []Handler{http.NotFound}, groups: make([]group, 0)} +} + +func (r *router) Group(pattern string, fn func(Router), h ...Handler) { + r.groups = append(r.groups, group{pattern, h}) + fn(r) + r.groups = r.groups[:len(r.groups)-1] +} + +func (r *router) Get(pattern string, h ...Handler) Route { + return r.addRoute("GET", pattern, h) +} + +func (r *router) Patch(pattern string, h ...Handler) Route { + return r.addRoute("PATCH", pattern, h) +} + +func (r *router) Post(pattern string, h ...Handler) Route { + return r.addRoute("POST", pattern, h) +} + +func (r *router) Put(pattern string, h ...Handler) Route { + return r.addRoute("PUT", pattern, h) +} + +func (r *router) Delete(pattern string, h ...Handler) Route { + return r.addRoute("DELETE", pattern, h) +} + +func (r *router) Options(pattern string, h ...Handler) Route { + return r.addRoute("OPTIONS", pattern, h) +} + +func (r *router) Head(pattern string, h ...Handler) Route { + return r.addRoute("HEAD", pattern, h) +} + +func (r *router) Any(pattern string, h ...Handler) Route { + return r.addRoute("*", pattern, h) +} + +func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Context) { + for _, route := range r.routes { + ok, vals := route.Match(req.Method, req.URL.Path) + if ok { + params := Params(vals) + context.Map(params) + route.Handle(context, res) + return + } + } + + // no routes exist, 404 + c := &routeContext{context, 0, r.notFounds} + context.MapTo(c, (*Context)(nil)) + c.run() +} + +func (r *router) NotFound(handler ...Handler) { + r.notFounds = handler +} + +func (r *router) addRoute(method string, pattern string, handlers []Handler) *route { + if len(r.groups) > 0 { + groupPattern := "" + h := make([]Handler, 0) + for _, g := range r.groups { + groupPattern += g.pattern + h = append(h, g.handlers...) + } + + pattern = groupPattern + pattern + h = append(h, handlers...) + handlers = h + } + + route := newRoute(method, pattern, handlers) + route.Validate() + r.routes = append(r.routes, route) + return route +} + +func (r *router) findRoute(name string) *route { + for _, route := range r.routes { + if route.name == name { + return route + } + } + + return nil +} + +// Route is an interface representing a Route in Martini's routing layer. +type Route interface { + // URLWith returns a rendering of the Route's url with the given string params. + URLWith([]string) string + // Name sets a name for the route. + Name(string) + // GetName returns the name of the route. + GetName() string + // Pattern returns the pattern of the route. + Pattern() string + // Method returns the method of the route. + Method() string +} + +type route struct { + method string + regex *regexp.Regexp + handlers []Handler + pattern string + name string +} + +func newRoute(method string, pattern string, handlers []Handler) *route { + route := route{method, nil, handlers, pattern, ""} + r := regexp.MustCompile(`:[^/#?()\.\\]+`) + pattern = r.ReplaceAllStringFunc(pattern, func(m string) string { + return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:]) + }) + r2 := regexp.MustCompile(`\*\*`) + var index int + pattern = r2.ReplaceAllStringFunc(pattern, func(m string) string { + index++ + return fmt.Sprintf(`(?P<_%d>[^#?]*)`, index) + }) + pattern += `\/?` + route.regex = regexp.MustCompile(pattern) + return &route +} + +func (r route) MatchMethod(method string) bool { + return r.method == "*" || method == r.method || (method == "HEAD" && r.method == "GET") +} + +func (r route) Match(method string, path string) (bool, map[string]string) { + // add Any method matching support + if !r.MatchMethod(method) { + return false, nil + } + + matches := r.regex.FindStringSubmatch(path) + if len(matches) > 0 && matches[0] == path { + params := make(map[string]string) + for i, name := range r.regex.SubexpNames() { + if len(name) > 0 { + params[name] = matches[i] + } + } + return true, params + } + return false, nil +} + +func (r *route) Validate() { + for _, handler := range r.handlers { + validateHandler(handler) + } +} + +func (r *route) Handle(c Context, res http.ResponseWriter) { + context := &routeContext{c, 0, r.handlers} + c.MapTo(context, (*Context)(nil)) + c.MapTo(r, (*Route)(nil)) + context.run() +} + +// URLWith returns the url pattern replacing the parameters for its values +func (r *route) URLWith(args []string) string { + if len(args) > 0 { + reg := regexp.MustCompile(`:[^/#?()\.\\]+`) + argCount := len(args) + i := 0 + url := reg.ReplaceAllStringFunc(r.pattern, func(m string) string { + var val interface{} + if i < argCount { + val = args[i] + } else { + val = m + } + i += 1 + return fmt.Sprintf(`%v`, val) + }) + + return url + } + return r.pattern +} + +func (r *route) Name(name string) { + r.name = name +} + +func (r *route) GetName() string { + return r.name +} + +func (r *route) Pattern() string { + return r.pattern +} + +func (r *route) Method() string { + return r.method +} + +// Routes is a helper service for Martini's routing layer. +type Routes interface { + // URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route. + URLFor(name string, params ...interface{}) string + // MethodsFor returns an array of methods available for the path + MethodsFor(path string) []string + // All returns an array with all the routes in the router. + All() []Route +} + +// URLFor returns the url for the given route name. +func (r *router) URLFor(name string, params ...interface{}) string { + route := r.findRoute(name) + + if route == nil { + panic("route not found") + } + + var args []string + for _, param := range params { + switch v := param.(type) { + case int: + args = append(args, strconv.FormatInt(int64(v), 10)) + case string: + args = append(args, v) + default: + if v != nil { + panic("Arguments passed to URLFor must be integers or strings") + } + } + } + + return route.URLWith(args) +} + +func (r *router) All() []Route { + var ri = make([]Route, len(r.routes)) + + for i, route := range r.routes { + ri[i] = Route(route) + } + + return ri +} + +func hasMethod(methods []string, method string) bool { + for _, v := range methods { + if v == method { + return true + } + } + return false +} + +// MethodsFor returns all methods available for path +func (r *router) MethodsFor(path string) []string { + methods := []string{} + for _, route := range r.routes { + matches := route.regex.FindStringSubmatch(path) + if len(matches) > 0 && matches[0] == path && !hasMethod(methods, route.method) { + methods = append(methods, route.method) + } + } + return methods +} + +type routeContext struct { + Context + index int + handlers []Handler +} + +func (r *routeContext) Next() { + r.index += 1 + r.run() +} + +func (r *routeContext) run() { + for r.index < len(r.handlers) { + handler := r.handlers[r.index] + vals, err := r.Invoke(handler) + if err != nil { + panic(err) + } + r.index += 1 + + // if the handler returned something, write it to the http response + if len(vals) > 0 { + ev := r.Get(reflect.TypeOf(ReturnHandler(nil))) + handleReturn := ev.Interface().(ReturnHandler) + handleReturn(r, vals) + } + + if r.Written() { + return + } + } +} diff --git a/vendor/github.com/go-martini/martini/static.go b/vendor/github.com/go-martini/martini/static.go new file mode 100644 index 00000000000..db527745198 --- /dev/null +++ b/vendor/github.com/go-martini/martini/static.go @@ -0,0 +1,109 @@ +package martini + +import ( + "log" + "net/http" + "path" + "strings" +) + +// StaticOptions is a struct for specifying configuration options for the martini.Static middleware. +type StaticOptions struct { + // Prefix is the optional prefix used to serve the static directory content + Prefix string + // SkipLogging will disable [Static] log messages when a static file is served. + SkipLogging bool + // IndexFile defines which file to serve as index if it exists. + IndexFile string + // Expires defines which user-defined function to use for producing a HTTP Expires Header + // https://developers.google.com/speed/docs/insights/LeverageBrowserCaching + Expires func() string +} + +func prepareStaticOptions(options []StaticOptions) StaticOptions { + var opt StaticOptions + if len(options) > 0 { + opt = options[0] + } + + // Defaults + if len(opt.IndexFile) == 0 { + opt.IndexFile = "index.html" + } + // Normalize the prefix if provided + if opt.Prefix != "" { + // Ensure we have a leading '/' + if opt.Prefix[0] != '/' { + opt.Prefix = "/" + opt.Prefix + } + // Remove any trailing '/' + opt.Prefix = strings.TrimRight(opt.Prefix, "/") + } + return opt +} + +// Static returns a middleware handler that serves static files in the given directory. +func Static(directory string, staticOpt ...StaticOptions) Handler { + dir := http.Dir(directory) + opt := prepareStaticOptions(staticOpt) + + return func(res http.ResponseWriter, req *http.Request, log *log.Logger) { + if req.Method != "GET" && req.Method != "HEAD" { + return + } + file := req.URL.Path + // if we have a prefix, filter requests by stripping the prefix + if opt.Prefix != "" { + if !strings.HasPrefix(file, opt.Prefix) { + return + } + file = file[len(opt.Prefix):] + if file != "" && file[0] != '/' { + return + } + } + f, err := dir.Open(file) + if err != nil { + // discard the error? + return + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return + } + + // try to serve index file + if fi.IsDir() { + // redirect if missing trailing slash + if !strings.HasSuffix(req.URL.Path, "/") { + http.Redirect(res, req, req.URL.Path+"/", http.StatusFound) + return + } + + file = path.Join(file, opt.IndexFile) + f, err = dir.Open(file) + if err != nil { + return + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + return + } + } + + if !opt.SkipLogging { + log.Println("[Static] Serving " + file) + } + + // Add an Expires header to the static content + if opt.Expires != nil { + res.Header().Set("Expires", opt.Expires()) + } + + http.ServeContent(res, req, file, fi.ModTime(), f) + } +}