change: Creating gloo upstreams from kube services

Signed-off-by: Keerthan Ekbote <keerthan.ekbote@solo.io>
This commit is contained in:
Keerthan Ekbote
2021-04-27 12:49:19 -04:00
parent 3e845f1a29
commit a1ff44454a
15 changed files with 697 additions and 16 deletions
+2
View File
@@ -30,6 +30,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&RouteTable{},
&RouteTableList{},
&Upstream{},
&UpstreamList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
+32
View File
@@ -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"`
}
+100
View File
@@ -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
@@ -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 {
@@ -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
}
@@ -19,3 +19,5 @@ limitations under the License.
package v1
type RouteTableExpansion interface{}
type UpstreamExpansion interface{}
@@ -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
@@ -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
}
@@ -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"):
@@ -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}
}
@@ -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())
}
@@ -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{}
+99
View File
@@ -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
}
-5
View File
@@ -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{
+38 -11
View File
@@ -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,
},
},
}
}