From a1ff44454aea2933e8bd939c1dc34c7aeaafc1d0 Mon Sep 17 00:00:00 2001 From: Keerthan Ekbote Date: Tue, 27 Apr 2021 12:49:19 -0400 Subject: [PATCH] change: Creating gloo upstreams from kube services Signed-off-by: Keerthan Ekbote --- pkg/apis/gloo/v1/register.go | 2 + pkg/apis/gloo/v1/types.go | 32 ++++ pkg/apis/gloo/v1/zz_generated.deepcopy.go | 100 ++++++++++ .../typed/gloo/v1/fake/fake_gloo_client.go | 4 + .../typed/gloo/v1/fake/fake_upstream.go | 130 +++++++++++++ .../typed/gloo/v1/generated_expansion.go | 2 + .../versioned/typed/gloo/v1/gloo_client.go | 5 + .../versioned/typed/gloo/v1/upstream.go | 178 ++++++++++++++++++ .../informers/externalversions/generic.go | 2 + .../externalversions/gloo/v1/interface.go | 7 + .../externalversions/gloo/v1/upstream.go | 90 +++++++++ .../listers/gloo/v1/expansion_generated.go | 8 + pkg/client/listers/gloo/v1/upstream.go | 99 ++++++++++ pkg/router/factory.go | 5 - pkg/router/gloo.go | 49 +++-- 15 files changed, 697 insertions(+), 16 deletions(-) create mode 100644 pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_upstream.go create mode 100644 pkg/client/clientset/versioned/typed/gloo/v1/upstream.go create mode 100644 pkg/client/informers/externalversions/gloo/v1/upstream.go create mode 100644 pkg/client/listers/gloo/v1/upstream.go diff --git a/pkg/apis/gloo/v1/register.go b/pkg/apis/gloo/v1/register.go index 46c167ae..4775e12b 100755 --- a/pkg/apis/gloo/v1/register.go +++ b/pkg/apis/gloo/v1/register.go @@ -30,6 +30,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &RouteTable{}, &RouteTableList{}, + &Upstream{}, + &UpstreamList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/gloo/v1/types.go b/pkg/apis/gloo/v1/types.go index c9f54abc..689656d9 100644 --- a/pkg/apis/gloo/v1/types.go +++ b/pkg/apis/gloo/v1/types.go @@ -19,6 +19,28 @@ type RouteTableSpec struct { Routes []Route `json:"routes,omitempty"` } +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Upstream is a specification for a Gloo Upstream resource +type Upstream struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + UpstreamType UpstreamType `json:"upstream_type,omitempty"` +} + +type UpstreamType struct { + Kube KubeUpstream `json:"kube,omitempty"` +} + +type KubeUpstream struct { + ServiceName string `json:"service_name,omitempty""` + ServiceNamespace string `json:"service_namespace,omitempty"` + ServicePort int32 `json:"service_port,omitempty"` + Selector map[string]string `json:"selector,omitempty"` +} + type Route struct { Matchers []Matcher `json:"matchers,omitempty"` Action RouteAction `json:"routeAction,omitempty"` @@ -80,3 +102,13 @@ type RouteTableList struct { Items []RouteTable `json:"items"` } + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// UpstreamList is a list of Upstream resources +type UpstreamList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Upstream `json:"items"` +} diff --git a/pkg/apis/gloo/v1/zz_generated.deepcopy.go b/pkg/apis/gloo/v1/zz_generated.deepcopy.go index 44a00d9a..596a0d94 100644 --- a/pkg/apis/gloo/v1/zz_generated.deepcopy.go +++ b/pkg/apis/gloo/v1/zz_generated.deepcopy.go @@ -57,6 +57,29 @@ func (in *HeaderMatcher) DeepCopy() *HeaderMatcher { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeUpstream) DeepCopyInto(out *KubeUpstream) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeUpstream. +func (in *KubeUpstream) DeepCopy() *KubeUpstream { + if in == nil { + return nil + } + out := new(KubeUpstream) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Matcher) DeepCopyInto(out *Matcher) { *out = *in @@ -265,6 +288,83 @@ func (in *RouteTableSpec) DeepCopy() *RouteTableSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Upstream) DeepCopyInto(out *Upstream) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.UpstreamType.DeepCopyInto(&out.UpstreamType) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upstream. +func (in *Upstream) DeepCopy() *Upstream { + if in == nil { + return nil + } + out := new(Upstream) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Upstream) 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 *UpstreamList) DeepCopyInto(out *UpstreamList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Upstream, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamList. +func (in *UpstreamList) DeepCopy() *UpstreamList { + if in == nil { + return nil + } + out := new(UpstreamList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *UpstreamList) 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 *UpstreamType) DeepCopyInto(out *UpstreamType) { + *out = *in + in.Kube.DeepCopyInto(&out.Kube) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamType. +func (in *UpstreamType) DeepCopy() *UpstreamType { + if in == nil { + return nil + } + out := new(UpstreamType) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WeightedDestination) DeepCopyInto(out *WeightedDestination) { *out = *in diff --git a/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_gloo_client.go b/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_gloo_client.go index f2815d43..17bf2941 100644 --- a/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_gloo_client.go +++ b/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_gloo_client.go @@ -32,6 +32,10 @@ func (c *FakeGatewayV1) RouteTables(namespace string) v1.RouteTableInterface { return &FakeRouteTables{c, namespace} } +func (c *FakeGatewayV1) Upstreams(namespace string) v1.UpstreamInterface { + return &FakeUpstreams{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeGatewayV1) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_upstream.go b/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_upstream.go new file mode 100644 index 00000000..4669064f --- /dev/null +++ b/pkg/client/clientset/versioned/typed/gloo/v1/fake/fake_upstream.go @@ -0,0 +1,130 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + gloov1 "github.com/fluxcd/flagger/pkg/apis/gloo/v1" + 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" +) + +// FakeUpstreams implements UpstreamInterface +type FakeUpstreams struct { + Fake *FakeGatewayV1 + ns string +} + +var upstreamsResource = schema.GroupVersionResource{Group: "gateway.solo.io", Version: "v1", Resource: "upstreams"} + +var upstreamsKind = schema.GroupVersionKind{Group: "gateway.solo.io", Version: "v1", Kind: "Upstream"} + +// Get takes name of the upstream, and returns the corresponding upstream object, and an error if there is any. +func (c *FakeUpstreams) Get(ctx context.Context, name string, options v1.GetOptions) (result *gloov1.Upstream, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(upstreamsResource, c.ns, name), &gloov1.Upstream{}) + + if obj == nil { + return nil, err + } + return obj.(*gloov1.Upstream), err +} + +// List takes label and field selectors, and returns the list of Upstreams that match those selectors. +func (c *FakeUpstreams) List(ctx context.Context, opts v1.ListOptions) (result *gloov1.UpstreamList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(upstreamsResource, upstreamsKind, c.ns, opts), &gloov1.UpstreamList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &gloov1.UpstreamList{ListMeta: obj.(*gloov1.UpstreamList).ListMeta} + for _, item := range obj.(*gloov1.UpstreamList).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 upstreams. +func (c *FakeUpstreams) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(upstreamsResource, c.ns, opts)) + +} + +// Create takes the representation of a upstream and creates it. Returns the server's representation of the upstream, and an error, if there is any. +func (c *FakeUpstreams) Create(ctx context.Context, upstream *gloov1.Upstream, opts v1.CreateOptions) (result *gloov1.Upstream, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(upstreamsResource, c.ns, upstream), &gloov1.Upstream{}) + + if obj == nil { + return nil, err + } + return obj.(*gloov1.Upstream), err +} + +// Update takes the representation of a upstream and updates it. Returns the server's representation of the upstream, and an error, if there is any. +func (c *FakeUpstreams) Update(ctx context.Context, upstream *gloov1.Upstream, opts v1.UpdateOptions) (result *gloov1.Upstream, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(upstreamsResource, c.ns, upstream), &gloov1.Upstream{}) + + if obj == nil { + return nil, err + } + return obj.(*gloov1.Upstream), err +} + +// Delete takes name of the upstream and deletes it. Returns an error if one occurs. +func (c *FakeUpstreams) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(upstreamsResource, c.ns, name), &gloov1.Upstream{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeUpstreams) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(upstreamsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &gloov1.UpstreamList{}) + return err +} + +// Patch applies the patch and returns the patched upstream. +func (c *FakeUpstreams) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *gloov1.Upstream, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(upstreamsResource, c.ns, name, pt, data, subresources...), &gloov1.Upstream{}) + + if obj == nil { + return nil, err + } + return obj.(*gloov1.Upstream), err +} diff --git a/pkg/client/clientset/versioned/typed/gloo/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/gloo/v1/generated_expansion.go index 972af2a9..d05389b5 100644 --- a/pkg/client/clientset/versioned/typed/gloo/v1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/gloo/v1/generated_expansion.go @@ -19,3 +19,5 @@ limitations under the License. package v1 type RouteTableExpansion interface{} + +type UpstreamExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/gloo/v1/gloo_client.go b/pkg/client/clientset/versioned/typed/gloo/v1/gloo_client.go index 10e1fe2a..3c7f6e7d 100644 --- a/pkg/client/clientset/versioned/typed/gloo/v1/gloo_client.go +++ b/pkg/client/clientset/versioned/typed/gloo/v1/gloo_client.go @@ -27,6 +27,7 @@ import ( type GatewayV1Interface interface { RESTClient() rest.Interface RouteTablesGetter + UpstreamsGetter } // GatewayV1Client is used to interact with features provided by the gateway.solo.io group. @@ -38,6 +39,10 @@ func (c *GatewayV1Client) RouteTables(namespace string) RouteTableInterface { return newRouteTables(c, namespace) } +func (c *GatewayV1Client) Upstreams(namespace string) UpstreamInterface { + return newUpstreams(c, namespace) +} + // NewForConfig creates a new GatewayV1Client for the given config. func NewForConfig(c *rest.Config) (*GatewayV1Client, error) { config := *c diff --git a/pkg/client/clientset/versioned/typed/gloo/v1/upstream.go b/pkg/client/clientset/versioned/typed/gloo/v1/upstream.go new file mode 100644 index 00000000..c8f9eebc --- /dev/null +++ b/pkg/client/clientset/versioned/typed/gloo/v1/upstream.go @@ -0,0 +1,178 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + "time" + + v1 "github.com/fluxcd/flagger/pkg/apis/gloo/v1" + scheme "github.com/fluxcd/flagger/pkg/client/clientset/versioned/scheme" + metav1 "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" +) + +// UpstreamsGetter has a method to return a UpstreamInterface. +// A group's client should implement this interface. +type UpstreamsGetter interface { + Upstreams(namespace string) UpstreamInterface +} + +// UpstreamInterface has methods to work with Upstream resources. +type UpstreamInterface interface { + Create(ctx context.Context, upstream *v1.Upstream, opts metav1.CreateOptions) (*v1.Upstream, error) + Update(ctx context.Context, upstream *v1.Upstream, opts metav1.UpdateOptions) (*v1.Upstream, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Upstream, error) + List(ctx context.Context, opts metav1.ListOptions) (*v1.UpstreamList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Upstream, err error) + UpstreamExpansion +} + +// upstreams implements UpstreamInterface +type upstreams struct { + client rest.Interface + ns string +} + +// newUpstreams returns a Upstreams +func newUpstreams(c *GatewayV1Client, namespace string) *upstreams { + return &upstreams{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the upstream, and returns the corresponding upstream object, and an error if there is any. +func (c *upstreams) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Upstream, err error) { + result = &v1.Upstream{} + err = c.client.Get(). + Namespace(c.ns). + Resource("upstreams"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Upstreams that match those selectors. +func (c *upstreams) List(ctx context.Context, opts metav1.ListOptions) (result *v1.UpstreamList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.UpstreamList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("upstreams"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested upstreams. +func (c *upstreams) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("upstreams"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a upstream and creates it. Returns the server's representation of the upstream, and an error, if there is any. +func (c *upstreams) Create(ctx context.Context, upstream *v1.Upstream, opts metav1.CreateOptions) (result *v1.Upstream, err error) { + result = &v1.Upstream{} + err = c.client.Post(). + Namespace(c.ns). + Resource("upstreams"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(upstream). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a upstream and updates it. Returns the server's representation of the upstream, and an error, if there is any. +func (c *upstreams) Update(ctx context.Context, upstream *v1.Upstream, opts metav1.UpdateOptions) (result *v1.Upstream, err error) { + result = &v1.Upstream{} + err = c.client.Put(). + Namespace(c.ns). + Resource("upstreams"). + Name(upstream.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(upstream). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the upstream and deletes it. Returns an error if one occurs. +func (c *upstreams) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("upstreams"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *upstreams) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("upstreams"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched upstream. +func (c *upstreams) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Upstream, err error) { + result = &v1.Upstream{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("upstreams"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 5182a4e1..c503fe85 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -87,6 +87,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=gateway.solo.io, Version=v1 case v1.SchemeGroupVersion.WithResource("routetables"): return &genericInformer{resource: resource.GroupResource(), informer: f.Gateway().V1().RouteTables().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("upstreams"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Gateway().V1().Upstreams().Informer()}, nil // Group=networking.istio.io, Version=v1alpha3 case v1alpha3.SchemeGroupVersion.WithResource("destinationrules"): diff --git a/pkg/client/informers/externalversions/gloo/v1/interface.go b/pkg/client/informers/externalversions/gloo/v1/interface.go index 1b5a8391..3e9191be 100644 --- a/pkg/client/informers/externalversions/gloo/v1/interface.go +++ b/pkg/client/informers/externalversions/gloo/v1/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // RouteTables returns a RouteTableInformer. RouteTables() RouteTableInformer + // Upstreams returns a UpstreamInformer. + Upstreams() UpstreamInformer } type version struct { @@ -43,3 +45,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (v *version) RouteTables() RouteTableInformer { return &routeTableInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } + +// Upstreams returns a UpstreamInformer. +func (v *version) Upstreams() UpstreamInformer { + return &upstreamInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/gloo/v1/upstream.go b/pkg/client/informers/externalversions/gloo/v1/upstream.go new file mode 100644 index 00000000..c5b61b88 --- /dev/null +++ b/pkg/client/informers/externalversions/gloo/v1/upstream.go @@ -0,0 +1,90 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + time "time" + + gloov1 "github.com/fluxcd/flagger/pkg/apis/gloo/v1" + versioned "github.com/fluxcd/flagger/pkg/client/clientset/versioned" + internalinterfaces "github.com/fluxcd/flagger/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/fluxcd/flagger/pkg/client/listers/gloo/v1" + metav1 "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" +) + +// UpstreamInformer provides access to a shared informer and lister for +// Upstreams. +type UpstreamInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.UpstreamLister +} + +type upstreamInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewUpstreamInformer constructs a new informer for Upstream 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 NewUpstreamInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredUpstreamInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredUpstreamInformer constructs a new informer for Upstream 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 NewFilteredUpstreamInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().Upstreams(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().Upstreams(namespace).Watch(context.TODO(), options) + }, + }, + &gloov1.Upstream{}, + resyncPeriod, + indexers, + ) +} + +func (f *upstreamInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredUpstreamInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *upstreamInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&gloov1.Upstream{}, f.defaultInformer) +} + +func (f *upstreamInformer) Lister() v1.UpstreamLister { + return v1.NewUpstreamLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/gloo/v1/expansion_generated.go b/pkg/client/listers/gloo/v1/expansion_generated.go index 4902c03f..d513f28d 100644 --- a/pkg/client/listers/gloo/v1/expansion_generated.go +++ b/pkg/client/listers/gloo/v1/expansion_generated.go @@ -25,3 +25,11 @@ type RouteTableListerExpansion interface{} // RouteTableNamespaceListerExpansion allows custom methods to be added to // RouteTableNamespaceLister. type RouteTableNamespaceListerExpansion interface{} + +// UpstreamListerExpansion allows custom methods to be added to +// UpstreamLister. +type UpstreamListerExpansion interface{} + +// UpstreamNamespaceListerExpansion allows custom methods to be added to +// UpstreamNamespaceLister. +type UpstreamNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/gloo/v1/upstream.go b/pkg/client/listers/gloo/v1/upstream.go new file mode 100644 index 00000000..0f7af0c2 --- /dev/null +++ b/pkg/client/listers/gloo/v1/upstream.go @@ -0,0 +1,99 @@ +/* +Copyright 2020 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/fluxcd/flagger/pkg/apis/gloo/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// UpstreamLister helps list Upstreams. +// All objects returned here must be treated as read-only. +type UpstreamLister interface { + // List lists all Upstreams in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.Upstream, err error) + // Upstreams returns an object that can list and get Upstreams. + Upstreams(namespace string) UpstreamNamespaceLister + UpstreamListerExpansion +} + +// upstreamLister implements the UpstreamLister interface. +type upstreamLister struct { + indexer cache.Indexer +} + +// NewUpstreamLister returns a new UpstreamLister. +func NewUpstreamLister(indexer cache.Indexer) UpstreamLister { + return &upstreamLister{indexer: indexer} +} + +// List lists all Upstreams in the indexer. +func (s *upstreamLister) List(selector labels.Selector) (ret []*v1.Upstream, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Upstream)) + }) + return ret, err +} + +// Upstreams returns an object that can list and get Upstreams. +func (s *upstreamLister) Upstreams(namespace string) UpstreamNamespaceLister { + return upstreamNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// UpstreamNamespaceLister helps list and get Upstreams. +// All objects returned here must be treated as read-only. +type UpstreamNamespaceLister interface { + // List lists all Upstreams in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.Upstream, err error) + // Get retrieves the Upstream from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1.Upstream, error) + UpstreamNamespaceListerExpansion +} + +// upstreamNamespaceLister implements the UpstreamNamespaceLister +// interface. +type upstreamNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Upstreams in the indexer for a given namespace. +func (s upstreamNamespaceLister) List(selector labels.Selector) (ret []*v1.Upstream, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Upstream)) + }) + return ret, err +} + +// Get retrieves the Upstream from the indexer for a given namespace and name. +func (s upstreamNamespaceLister) Get(name string) (*v1.Upstream, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("upstream"), name) + } + return obj.(*v1.Upstream), nil +} diff --git a/pkg/router/factory.go b/pkg/router/factory.go index a9f2fbc4..a1b4a03e 100644 --- a/pkg/router/factory.go +++ b/pkg/router/factory.go @@ -122,16 +122,11 @@ func (factory *Factory) MeshRouter(provider string, labelSelector string) Interf ingressClass: factory.ingressClass, } case strings.HasPrefix(provider, flaggerv1.GlooProvider): - upstreamDiscoveryNs := flaggerv1.GlooProvider + "-system" - if strings.HasPrefix(provider, flaggerv1.GlooProvider+":") { - upstreamDiscoveryNs = strings.TrimPrefix(provider, flaggerv1.GlooProvider+":") - } return &GlooRouter{ logger: factory.logger, flaggerClient: factory.flaggerClient, kubeClient: factory.kubeClient, glooClient: factory.meshClient, - upstreamDiscoveryNs: upstreamDiscoveryNs, } case provider == flaggerv1.NGINXProvider: return &IngressRouter{ diff --git a/pkg/router/gloo.go b/pkg/router/gloo.go index 3e849be3..dfab730d 100644 --- a/pkg/router/gloo.go +++ b/pkg/router/gloo.go @@ -39,15 +39,23 @@ type GlooRouter struct { glooClient clientset.Interface flaggerClient clientset.Interface logger *zap.SugaredLogger - upstreamDiscoveryNs string } // Reconcile creates or updates the Gloo Edge route table func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error { - apexName, _, _ := canary.GetServiceNames() - canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, apexName, canary.Spec.Service.Port) - primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, apexName, canary.Spec.Service.Port) - + apexName, primaryName, canaryName := canary.GetServiceNames() + canaryUpstreamName := fmt.Sprintf("%s-%s-canaryUpstream-%v", canary.Namespace, apexName, canary.Spec.Service.Port) + primaryUpstreamName := fmt.Sprintf("%s-%s-primaryUpstream-%v", canary.Namespace, apexName, canary.Spec.Service.Port) + canaryUs := getGlooUpstreamForKubeService(canary, canaryUpstreamName, canaryName) + primaryUs := getGlooUpstreamForKubeService(canary, primaryUpstreamName, primaryName) + _, err := gr.glooClient.GatewayV1().Upstreams(canary.Namespace).Create(context.TODO(), canaryUs, metav1.CreateOptions{}) + if err != nil { + return err + } + _, err = gr.glooClient.GatewayV1().Upstreams(canary.Namespace).Create(context.TODO(), primaryUs, metav1.CreateOptions{}) + if err != nil { + return err + } newSpec := gloov1.RouteTableSpec{ Routes: []gloov1.Route{ { @@ -59,8 +67,8 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error { { Destination: gloov1.Destination{ Upstream: gloov1.ResourceRef{ - Name: primaryName, - Namespace: gr.upstreamDiscoveryNs, + Name: primaryUpstreamName, + Namespace: canary.Namespace, }, }, Weight: 100, @@ -68,8 +76,8 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error { { Destination: gloov1.Destination{ Upstream: gloov1.ResourceRef{ - Name: canaryName, - Namespace: gr.upstreamDiscoveryNs, + Name: canaryUpstreamName, + Namespace: canary.Namespace, }, }, Weight: 0, @@ -196,7 +204,7 @@ func (gr *GlooRouter) SetRoutes( Destination: gloov1.Destination{ Upstream: gloov1.ResourceRef{ Name: primaryName, - Namespace: gr.upstreamDiscoveryNs, + Namespace: canary.Namespace, }, }, Weight: uint32(primaryWeight), @@ -205,7 +213,7 @@ func (gr *GlooRouter) SetRoutes( Destination: gloov1.Destination{ Upstream: gloov1.ResourceRef{ Name: canaryName, - Namespace: gr.upstreamDiscoveryNs, + Namespace: canary.Namespace, }, }, Weight: uint32(canaryWeight), @@ -275,3 +283,22 @@ func getMethods(canary *flaggerv1.Canary) []string { } return methods } + +func getGlooUpstreamForKubeService(canary *flaggerv1.Canary, upstreamName, svcName string) *gloov1.Upstream{ + return &gloov1.Upstream{ + ObjectMeta: metav1.ObjectMeta{ + Name: upstreamName, + Namespace: canary.Namespace, + Labels: canary.Spec.Service.Apex.Labels, + Annotations: canary.Spec.Service.Apex.Annotations, + }, + UpstreamType: gloov1.UpstreamType{ + Kube: gloov1.KubeUpstream{ + ServiceName: svcName, + ServiceNamespace: canary.Namespace, + ServicePort: canary.Spec.Service.Port, + Selector: nil, + }, + }, + } +}