Refactor Gloo integration

- build Gloo UpstreamGroup clientset
- drop solo-io, envoyproxy, hcl, consul, opencensus, apiextensions deps
- use the native routers with supergloo
This commit is contained in:
stefanprodan
2019-10-21 16:33:47 +03:00
parent f372523fb8
commit 46579d2ee6
32 changed files with 1298 additions and 971 deletions
+5
View File
@@ -0,0 +1,5 @@
package gloo
const (
GroupName = "gloo.solo.io"
)
+5
View File
@@ -0,0 +1,5 @@
// +k8s:deepcopy-gen=package
// Package v1 is the v1 version of the API.
// +groupName=gloo.solo.io
package v1
+36
View File
@@ -0,0 +1,36 @@
package v1
import (
"github.com/weaveworks/flagger/pkg/apis/gloo"
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: gloo.GroupName, Version: "v1"}
// 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,
&UpstreamGroup{},
&UpstreamGroupList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
+49
View File
@@ -0,0 +1,49 @@
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// UpstreamGroup is a specification for a Gloo UpstreamGroup resource
type UpstreamGroup struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec UpstreamGroupSpec `json:"spec"`
}
type UpstreamGroupSpec struct {
Destinations []WeightedDestination `json:"destinations,omitempty"`
}
// WeightedDestination attaches a weight to a single destination.
type WeightedDestination struct {
Destination Destination `json:"destination,omitempty"`
// Weight must be greater than zero
// Routing to each destination will be balanced by the ratio of the destination's weight to the total weight on a route
Weight uint32 `json:"weight,omitempty"`
}
// Destinations define routable destinations for proxied requests
type Destination struct {
Upstream ResourceRef `json:"upstream"`
}
// ResourceRef references resources across namespaces
type ResourceRef struct {
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// UpstreamGroupList is a list of UpstreamGroup resources
type UpstreamGroupList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`
Items []UpstreamGroup `json:"items"`
}
+156
View File
@@ -0,0 +1,156 @@
// +build !ignore_autogenerated
/*
Copyright The Flagger 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 deepcopy-gen. DO NOT EDIT.
package v1
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 *Destination) DeepCopyInto(out *Destination) {
*out = *in
out.Upstream = in.Upstream
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination.
func (in *Destination) DeepCopy() *Destination {
if in == nil {
return nil
}
out := new(Destination)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceRef) DeepCopyInto(out *ResourceRef) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRef.
func (in *ResourceRef) DeepCopy() *ResourceRef {
if in == nil {
return nil
}
out := new(ResourceRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpstreamGroup) DeepCopyInto(out *UpstreamGroup) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamGroup.
func (in *UpstreamGroup) DeepCopy() *UpstreamGroup {
if in == nil {
return nil
}
out := new(UpstreamGroup)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *UpstreamGroup) 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 *UpstreamGroupList) DeepCopyInto(out *UpstreamGroupList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]UpstreamGroup, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamGroupList.
func (in *UpstreamGroupList) DeepCopy() *UpstreamGroupList {
if in == nil {
return nil
}
out := new(UpstreamGroupList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *UpstreamGroupList) 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 *UpstreamGroupSpec) DeepCopyInto(out *UpstreamGroupSpec) {
*out = *in
if in.Destinations != nil {
in, out := &in.Destinations, &out.Destinations
*out = make([]WeightedDestination, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamGroupSpec.
func (in *UpstreamGroupSpec) DeepCopy() *UpstreamGroupSpec {
if in == nil {
return nil
}
out := new(UpstreamGroupSpec)
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
out.Destination = in.Destination
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WeightedDestination.
func (in *WeightedDestination) DeepCopy() *WeightedDestination {
if in == nil {
return nil
}
out := new(WeightedDestination)
in.DeepCopyInto(out)
return out
}
@@ -21,6 +21,7 @@ package versioned
import (
appmeshv1beta1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/appmesh/v1beta1"
flaggerv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha3"
gloov1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/gloo/v1"
networkingv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3"
splitv1alpha1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/smi/v1alpha1"
discovery "k8s.io/client-go/discovery"
@@ -32,6 +33,7 @@ type Interface interface {
Discovery() discovery.DiscoveryInterface
AppmeshV1beta1() appmeshv1beta1.AppmeshV1beta1Interface
FlaggerV1alpha3() flaggerv1alpha3.FlaggerV1alpha3Interface
GlooV1() gloov1.GlooV1Interface
NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3Interface
SplitV1alpha1() splitv1alpha1.SplitV1alpha1Interface
}
@@ -42,6 +44,7 @@ type Clientset struct {
*discovery.DiscoveryClient
appmeshV1beta1 *appmeshv1beta1.AppmeshV1beta1Client
flaggerV1alpha3 *flaggerv1alpha3.FlaggerV1alpha3Client
glooV1 *gloov1.GlooV1Client
networkingV1alpha3 *networkingv1alpha3.NetworkingV1alpha3Client
splitV1alpha1 *splitv1alpha1.SplitV1alpha1Client
}
@@ -56,6 +59,11 @@ func (c *Clientset) FlaggerV1alpha3() flaggerv1alpha3.FlaggerV1alpha3Interface {
return c.flaggerV1alpha3
}
// GlooV1 retrieves the GlooV1Client
func (c *Clientset) GlooV1() gloov1.GlooV1Interface {
return c.glooV1
}
// NetworkingV1alpha3 retrieves the NetworkingV1alpha3Client
func (c *Clientset) NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3Interface {
return c.networkingV1alpha3
@@ -90,6 +98,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
if err != nil {
return nil, err
}
cs.glooV1, err = gloov1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
cs.networkingV1alpha3, err = networkingv1alpha3.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
@@ -112,6 +124,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.appmeshV1beta1 = appmeshv1beta1.NewForConfigOrDie(c)
cs.flaggerV1alpha3 = flaggerv1alpha3.NewForConfigOrDie(c)
cs.glooV1 = gloov1.NewForConfigOrDie(c)
cs.networkingV1alpha3 = networkingv1alpha3.NewForConfigOrDie(c)
cs.splitV1alpha1 = splitv1alpha1.NewForConfigOrDie(c)
@@ -124,6 +137,7 @@ func New(c rest.Interface) *Clientset {
var cs Clientset
cs.appmeshV1beta1 = appmeshv1beta1.New(c)
cs.flaggerV1alpha3 = flaggerv1alpha3.New(c)
cs.glooV1 = gloov1.New(c)
cs.networkingV1alpha3 = networkingv1alpha3.New(c)
cs.splitV1alpha1 = splitv1alpha1.New(c)
@@ -24,6 +24,8 @@ import (
fakeappmeshv1beta1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/appmesh/v1beta1/fake"
flaggerv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha3"
fakeflaggerv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/flagger/v1alpha3/fake"
gloov1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/gloo/v1"
fakegloov1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/gloo/v1/fake"
networkingv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3"
fakenetworkingv1alpha3 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/istio/v1alpha3/fake"
splitv1alpha1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/smi/v1alpha1"
@@ -92,6 +94,11 @@ func (c *Clientset) FlaggerV1alpha3() flaggerv1alpha3.FlaggerV1alpha3Interface {
return &fakeflaggerv1alpha3.FakeFlaggerV1alpha3{Fake: &c.Fake}
}
// GlooV1 retrieves the GlooV1Client
func (c *Clientset) GlooV1() gloov1.GlooV1Interface {
return &fakegloov1.FakeGlooV1{Fake: &c.Fake}
}
// NetworkingV1alpha3 retrieves the NetworkingV1alpha3Client
func (c *Clientset) NetworkingV1alpha3() networkingv1alpha3.NetworkingV1alpha3Interface {
return &fakenetworkingv1alpha3.FakeNetworkingV1alpha3{Fake: &c.Fake}
@@ -21,6 +21,7 @@ package fake
import (
appmeshv1beta1 "github.com/weaveworks/flagger/pkg/apis/appmesh/v1beta1"
flaggerv1alpha3 "github.com/weaveworks/flagger/pkg/apis/flagger/v1alpha3"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
networkingv1alpha3 "github.com/weaveworks/flagger/pkg/apis/istio/v1alpha3"
splitv1alpha1 "github.com/weaveworks/flagger/pkg/apis/smi/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -36,6 +37,7 @@ var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
appmeshv1beta1.AddToScheme,
flaggerv1alpha3.AddToScheme,
gloov1.AddToScheme,
networkingv1alpha3.AddToScheme,
splitv1alpha1.AddToScheme,
}
@@ -21,6 +21,7 @@ package scheme
import (
appmeshv1beta1 "github.com/weaveworks/flagger/pkg/apis/appmesh/v1beta1"
flaggerv1alpha3 "github.com/weaveworks/flagger/pkg/apis/flagger/v1alpha3"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
networkingv1alpha3 "github.com/weaveworks/flagger/pkg/apis/istio/v1alpha3"
splitv1alpha1 "github.com/weaveworks/flagger/pkg/apis/smi/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -36,6 +37,7 @@ var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
appmeshv1beta1.AddToScheme,
flaggerv1alpha3.AddToScheme,
gloov1.AddToScheme,
networkingv1alpha3.AddToScheme,
splitv1alpha1.AddToScheme,
}
@@ -0,0 +1,20 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1
@@ -0,0 +1,20 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake
@@ -0,0 +1,40 @@
/*
Copyright The Flagger Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1 "github.com/weaveworks/flagger/pkg/client/clientset/versioned/typed/gloo/v1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeGlooV1 struct {
*testing.Fake
}
func (c *FakeGlooV1) UpstreamGroups(namespace string) v1.UpstreamGroupInterface {
return &FakeUpstreamGroups{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeGlooV1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}
@@ -0,0 +1,128 @@
/*
Copyright The Flagger 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 (
gloov1 "github.com/weaveworks/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"
)
// FakeUpstreamGroups implements UpstreamGroupInterface
type FakeUpstreamGroups struct {
Fake *FakeGlooV1
ns string
}
var upstreamgroupsResource = schema.GroupVersionResource{Group: "gloo.solo.io", Version: "v1", Resource: "upstreamgroups"}
var upstreamgroupsKind = schema.GroupVersionKind{Group: "gloo.solo.io", Version: "v1", Kind: "UpstreamGroup"}
// Get takes name of the upstreamGroup, and returns the corresponding upstreamGroup object, and an error if there is any.
func (c *FakeUpstreamGroups) Get(name string, options v1.GetOptions) (result *gloov1.UpstreamGroup, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(upstreamgroupsResource, c.ns, name), &gloov1.UpstreamGroup{})
if obj == nil {
return nil, err
}
return obj.(*gloov1.UpstreamGroup), err
}
// List takes label and field selectors, and returns the list of UpstreamGroups that match those selectors.
func (c *FakeUpstreamGroups) List(opts v1.ListOptions) (result *gloov1.UpstreamGroupList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(upstreamgroupsResource, upstreamgroupsKind, c.ns, opts), &gloov1.UpstreamGroupList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &gloov1.UpstreamGroupList{ListMeta: obj.(*gloov1.UpstreamGroupList).ListMeta}
for _, item := range obj.(*gloov1.UpstreamGroupList).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 upstreamGroups.
func (c *FakeUpstreamGroups) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(upstreamgroupsResource, c.ns, opts))
}
// Create takes the representation of a upstreamGroup and creates it. Returns the server's representation of the upstreamGroup, and an error, if there is any.
func (c *FakeUpstreamGroups) Create(upstreamGroup *gloov1.UpstreamGroup) (result *gloov1.UpstreamGroup, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(upstreamgroupsResource, c.ns, upstreamGroup), &gloov1.UpstreamGroup{})
if obj == nil {
return nil, err
}
return obj.(*gloov1.UpstreamGroup), err
}
// Update takes the representation of a upstreamGroup and updates it. Returns the server's representation of the upstreamGroup, and an error, if there is any.
func (c *FakeUpstreamGroups) Update(upstreamGroup *gloov1.UpstreamGroup) (result *gloov1.UpstreamGroup, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(upstreamgroupsResource, c.ns, upstreamGroup), &gloov1.UpstreamGroup{})
if obj == nil {
return nil, err
}
return obj.(*gloov1.UpstreamGroup), err
}
// Delete takes name of the upstreamGroup and deletes it. Returns an error if one occurs.
func (c *FakeUpstreamGroups) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(upstreamgroupsResource, c.ns, name), &gloov1.UpstreamGroup{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeUpstreamGroups) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(upstreamgroupsResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &gloov1.UpstreamGroupList{})
return err
}
// Patch applies the patch and returns the patched upstreamGroup.
func (c *FakeUpstreamGroups) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *gloov1.UpstreamGroup, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(upstreamgroupsResource, c.ns, name, pt, data, subresources...), &gloov1.UpstreamGroup{})
if obj == nil {
return nil, err
}
return obj.(*gloov1.UpstreamGroup), err
}
@@ -0,0 +1,21 @@
/*
Copyright The Flagger 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
type UpstreamGroupExpansion interface{}
@@ -0,0 +1,89 @@
/*
Copyright The Flagger 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 (
v1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
"github.com/weaveworks/flagger/pkg/client/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type GlooV1Interface interface {
RESTClient() rest.Interface
UpstreamGroupsGetter
}
// GlooV1Client is used to interact with features provided by the gloo.solo.io group.
type GlooV1Client struct {
restClient rest.Interface
}
func (c *GlooV1Client) UpstreamGroups(namespace string) UpstreamGroupInterface {
return newUpstreamGroups(c, namespace)
}
// NewForConfig creates a new GlooV1Client for the given config.
func NewForConfig(c *rest.Config) (*GlooV1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &GlooV1Client{client}, nil
}
// NewForConfigOrDie creates a new GlooV1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *GlooV1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new GlooV1Client for the given RESTClient.
func New(c rest.Interface) *GlooV1Client {
return &GlooV1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *GlooV1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}
@@ -0,0 +1,174 @@
/*
Copyright The Flagger 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 (
"time"
v1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
scheme "github.com/weaveworks/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"
)
// UpstreamGroupsGetter has a method to return a UpstreamGroupInterface.
// A group's client should implement this interface.
type UpstreamGroupsGetter interface {
UpstreamGroups(namespace string) UpstreamGroupInterface
}
// UpstreamGroupInterface has methods to work with UpstreamGroup resources.
type UpstreamGroupInterface interface {
Create(*v1.UpstreamGroup) (*v1.UpstreamGroup, error)
Update(*v1.UpstreamGroup) (*v1.UpstreamGroup, error)
Delete(name string, options *metav1.DeleteOptions) error
DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error
Get(name string, options metav1.GetOptions) (*v1.UpstreamGroup, error)
List(opts metav1.ListOptions) (*v1.UpstreamGroupList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.UpstreamGroup, err error)
UpstreamGroupExpansion
}
// upstreamGroups implements UpstreamGroupInterface
type upstreamGroups struct {
client rest.Interface
ns string
}
// newUpstreamGroups returns a UpstreamGroups
func newUpstreamGroups(c *GlooV1Client, namespace string) *upstreamGroups {
return &upstreamGroups{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the upstreamGroup, and returns the corresponding upstreamGroup object, and an error if there is any.
func (c *upstreamGroups) Get(name string, options metav1.GetOptions) (result *v1.UpstreamGroup, err error) {
result = &v1.UpstreamGroup{}
err = c.client.Get().
Namespace(c.ns).
Resource("upstreamgroups").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of UpstreamGroups that match those selectors.
func (c *upstreamGroups) List(opts metav1.ListOptions) (result *v1.UpstreamGroupList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.UpstreamGroupList{}
err = c.client.Get().
Namespace(c.ns).
Resource("upstreamgroups").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested upstreamGroups.
func (c *upstreamGroups) Watch(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("upstreamgroups").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
}
// Create takes the representation of a upstreamGroup and creates it. Returns the server's representation of the upstreamGroup, and an error, if there is any.
func (c *upstreamGroups) Create(upstreamGroup *v1.UpstreamGroup) (result *v1.UpstreamGroup, err error) {
result = &v1.UpstreamGroup{}
err = c.client.Post().
Namespace(c.ns).
Resource("upstreamgroups").
Body(upstreamGroup).
Do().
Into(result)
return
}
// Update takes the representation of a upstreamGroup and updates it. Returns the server's representation of the upstreamGroup, and an error, if there is any.
func (c *upstreamGroups) Update(upstreamGroup *v1.UpstreamGroup) (result *v1.UpstreamGroup, err error) {
result = &v1.UpstreamGroup{}
err = c.client.Put().
Namespace(c.ns).
Resource("upstreamgroups").
Name(upstreamGroup.Name).
Body(upstreamGroup).
Do().
Into(result)
return
}
// Delete takes name of the upstreamGroup and deletes it. Returns an error if one occurs.
func (c *upstreamGroups) Delete(name string, options *metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("upstreamgroups").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *upstreamGroups) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("upstreamgroups").
VersionedParams(&listOptions, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Error()
}
// Patch applies the patch and returns the patched upstreamGroup.
func (c *upstreamGroups) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.UpstreamGroup, err error) {
result = &v1.UpstreamGroup{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("upstreamgroups").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}
@@ -26,6 +26,7 @@ import (
versioned "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
appmesh "github.com/weaveworks/flagger/pkg/client/informers/externalversions/appmesh"
flagger "github.com/weaveworks/flagger/pkg/client/informers/externalversions/flagger"
gloo "github.com/weaveworks/flagger/pkg/client/informers/externalversions/gloo"
internalinterfaces "github.com/weaveworks/flagger/pkg/client/informers/externalversions/internalinterfaces"
istio "github.com/weaveworks/flagger/pkg/client/informers/externalversions/istio"
smi "github.com/weaveworks/flagger/pkg/client/informers/externalversions/smi"
@@ -177,6 +178,7 @@ type SharedInformerFactory interface {
Appmesh() appmesh.Interface
Flagger() flagger.Interface
Gloo() gloo.Interface
Networking() istio.Interface
Split() smi.Interface
}
@@ -189,6 +191,10 @@ func (f *sharedInformerFactory) Flagger() flagger.Interface {
return flagger.New(f, f.namespace, f.tweakListOptions)
}
func (f *sharedInformerFactory) Gloo() gloo.Interface {
return gloo.New(f, f.namespace, f.tweakListOptions)
}
func (f *sharedInformerFactory) Networking() istio.Interface {
return istio.New(f, f.namespace, f.tweakListOptions)
}
@@ -23,6 +23,7 @@ import (
v1beta1 "github.com/weaveworks/flagger/pkg/apis/appmesh/v1beta1"
v1alpha3 "github.com/weaveworks/flagger/pkg/apis/flagger/v1alpha3"
v1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
istiov1alpha3 "github.com/weaveworks/flagger/pkg/apis/istio/v1alpha3"
v1alpha1 "github.com/weaveworks/flagger/pkg/apis/smi/v1alpha1"
schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -67,6 +68,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
case v1alpha3.SchemeGroupVersion.WithResource("canaries"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Flagger().V1alpha3().Canaries().Informer()}, nil
// Group=gloo.solo.io, Version=v1
case v1.SchemeGroupVersion.WithResource("upstreamgroups"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Gloo().V1().UpstreamGroups().Informer()}, nil
// Group=networking.istio.io, Version=v1alpha3
case istiov1alpha3.SchemeGroupVersion.WithResource("destinationrules"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha3().DestinationRules().Informer()}, nil
@@ -0,0 +1,46 @@
/*
Copyright The Flagger 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 gloo
import (
v1 "github.com/weaveworks/flagger/pkg/client/informers/externalversions/gloo/v1"
internalinterfaces "github.com/weaveworks/flagger/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.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}
}
// V1 returns a new v1.Interface.
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
@@ -0,0 +1,45 @@
/*
Copyright The Flagger 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 (
internalinterfaces "github.com/weaveworks/flagger/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// UpstreamGroups returns a UpstreamGroupInformer.
UpstreamGroups() UpstreamGroupInformer
}
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}
}
// UpstreamGroups returns a UpstreamGroupInformer.
func (v *version) UpstreamGroups() UpstreamGroupInformer {
return &upstreamGroupInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
@@ -0,0 +1,89 @@
/*
Copyright The Flagger 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 (
time "time"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
versioned "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
internalinterfaces "github.com/weaveworks/flagger/pkg/client/informers/externalversions/internalinterfaces"
v1 "github.com/weaveworks/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"
)
// UpstreamGroupInformer provides access to a shared informer and lister for
// UpstreamGroups.
type UpstreamGroupInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.UpstreamGroupLister
}
type upstreamGroupInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewUpstreamGroupInformer constructs a new informer for UpstreamGroup 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 NewUpstreamGroupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredUpstreamGroupInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredUpstreamGroupInformer constructs a new informer for UpstreamGroup 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 NewFilteredUpstreamGroupInformer(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.GlooV1().UpstreamGroups(namespace).List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GlooV1().UpstreamGroups(namespace).Watch(options)
},
},
&gloov1.UpstreamGroup{},
resyncPeriod,
indexers,
)
}
func (f *upstreamGroupInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredUpstreamGroupInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *upstreamGroupInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&gloov1.UpstreamGroup{}, f.defaultInformer)
}
func (f *upstreamGroupInformer) Lister() v1.UpstreamGroupLister {
return v1.NewUpstreamGroupLister(f.Informer().GetIndexer())
}
@@ -0,0 +1,27 @@
/*
Copyright The Flagger 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
// UpstreamGroupListerExpansion allows custom methods to be added to
// UpstreamGroupLister.
type UpstreamGroupListerExpansion interface{}
// UpstreamGroupNamespaceListerExpansion allows custom methods to be added to
// UpstreamGroupNamespaceLister.
type UpstreamGroupNamespaceListerExpansion interface{}
@@ -0,0 +1,94 @@
/*
Copyright The Flagger 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/weaveworks/flagger/pkg/apis/gloo/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// UpstreamGroupLister helps list UpstreamGroups.
type UpstreamGroupLister interface {
// List lists all UpstreamGroups in the indexer.
List(selector labels.Selector) (ret []*v1.UpstreamGroup, err error)
// UpstreamGroups returns an object that can list and get UpstreamGroups.
UpstreamGroups(namespace string) UpstreamGroupNamespaceLister
UpstreamGroupListerExpansion
}
// upstreamGroupLister implements the UpstreamGroupLister interface.
type upstreamGroupLister struct {
indexer cache.Indexer
}
// NewUpstreamGroupLister returns a new UpstreamGroupLister.
func NewUpstreamGroupLister(indexer cache.Indexer) UpstreamGroupLister {
return &upstreamGroupLister{indexer: indexer}
}
// List lists all UpstreamGroups in the indexer.
func (s *upstreamGroupLister) List(selector labels.Selector) (ret []*v1.UpstreamGroup, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.UpstreamGroup))
})
return ret, err
}
// UpstreamGroups returns an object that can list and get UpstreamGroups.
func (s *upstreamGroupLister) UpstreamGroups(namespace string) UpstreamGroupNamespaceLister {
return upstreamGroupNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// UpstreamGroupNamespaceLister helps list and get UpstreamGroups.
type UpstreamGroupNamespaceLister interface {
// List lists all UpstreamGroups in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1.UpstreamGroup, err error)
// Get retrieves the UpstreamGroup from the indexer for a given namespace and name.
Get(name string) (*v1.UpstreamGroup, error)
UpstreamGroupNamespaceListerExpansion
}
// upstreamGroupNamespaceLister implements the UpstreamGroupNamespaceLister
// interface.
type upstreamGroupNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all UpstreamGroups in the indexer for a given namespace.
func (s upstreamGroupNamespaceLister) List(selector labels.Selector) (ret []*v1.UpstreamGroup, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.UpstreamGroup))
})
return ret, err
}
// Get retrieves the UpstreamGroup from the indexer for a given namespace and name.
func (s upstreamGroupNamespaceLister) Get(name string) (*v1.UpstreamGroup, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1.Resource("upstreamgroup"), name)
}
return obj.(*v1.UpstreamGroup), nil
}
+32 -11
View File
@@ -1,7 +1,6 @@
package router
import (
"context"
"strings"
"go.uber.org/zap"
@@ -84,18 +83,40 @@ func (factory *Factory) MeshRouter(provider string) Interface {
smiClient: factory.meshClient,
targetMesh: "linkerd",
}
case strings.HasPrefix(provider, "supergloo"):
supergloo, err := NewSuperglooRouter(context.TODO(), provider, factory.flaggerClient, factory.logger, factory.kubeConfig)
if err != nil {
panic("failed creating supergloo client")
}
return supergloo
case strings.HasPrefix(provider, "gloo"):
gloo, err := NewGlooRouter(context.TODO(), provider, factory.flaggerClient, factory.logger, factory.kubeConfig)
if err != nil {
panic("failed creating gloo client")
upstreamDiscoveryNs := "gloo-system"
if strings.HasPrefix(provider, "gloo:") {
upstreamDiscoveryNs = strings.TrimPrefix(provider, "gloo:")
}
return &GlooRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
glooClient: factory.meshClient,
upstreamDiscoveryNs: upstreamDiscoveryNs,
}
case strings.HasPrefix(provider, "supergloo:appmesh"):
return &AppMeshRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
appmeshClient: factory.meshClient,
}
case strings.HasPrefix(provider, "supergloo:istio"):
return &IstioRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
istioClient: factory.meshClient,
}
case strings.HasPrefix(provider, "supergloo:linkerd"):
return &SmiRouter{
logger: factory.logger,
flaggerClient: factory.flaggerClient,
kubeClient: factory.kubeClient,
smiClient: factory.meshClient,
targetMesh: "linkerd",
}
return gloo
default:
return &IstioRouter{
logger: factory.logger,
+137 -131
View File
@@ -1,21 +1,16 @@
package router
import (
"context"
"fmt"
"strings"
gloov1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
solokitclients "github.com/solo-io/solo-kit/pkg/api/v1/clients"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/factory"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/kube"
crdv1 "github.com/solo-io/solo-kit/pkg/api/v1/clients/kube/crd/solo.io/v1"
solokitcore "github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
solokiterror "github.com/solo-io/solo-kit/pkg/errors"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"k8s.io/client-go/kubernetes"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1alpha3"
clientset "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
@@ -23,54 +18,92 @@ import (
// GlooRouter is managing Istio virtual services
type GlooRouter struct {
ugClient gloov1.UpstreamGroupClient
kubeClient kubernetes.Interface
glooClient clientset.Interface
flaggerClient clientset.Interface
logger *zap.SugaredLogger
upstreamDiscoveryNs string
}
func NewGlooRouter(ctx context.Context, provider string, flaggerClient clientset.Interface, logger *zap.SugaredLogger, cfg *rest.Config) (*GlooRouter, error) {
// TODO if cfg is nil use memory client instead?
sharedCache := kube.NewKubeCache(ctx)
upstreamGroupClient, err := gloov1.NewUpstreamGroupClient(&factory.KubeResourceClientFactory{
Crd: gloov1.UpstreamGroupCrd,
Cfg: cfg,
SharedCache: sharedCache,
SkipCrdCreation: true,
})
if err != nil {
// this should never happen.
return nil, fmt.Errorf("creating UpstreamGroup client %v", err)
}
if err := upstreamGroupClient.Register(); err != nil {
return nil, err
}
upstreamDiscoveryNs := ""
if strings.HasPrefix(provider, "gloo:") {
upstreamDiscoveryNs = strings.TrimPrefix(provider, "gloo:")
}
return NewGlooRouterWithClient(ctx, upstreamGroupClient, upstreamDiscoveryNs, logger), nil
}
func NewGlooRouterWithClient(ctx context.Context, routingRuleClient gloov1.UpstreamGroupClient, upstreamDiscoveryNs string, logger *zap.SugaredLogger) *GlooRouter {
if upstreamDiscoveryNs == "" {
upstreamDiscoveryNs = "gloo-system"
}
return &GlooRouter{ugClient: routingRuleClient, logger: logger, upstreamDiscoveryNs: upstreamDiscoveryNs}
}
// Reconcile creates or updates the Istio virtual service
func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
// do we have routes already?
if _, _, _, err := gr.GetRoutes(canary); err == nil {
// we have routes, no need to do anything else
return nil
} else if solokiterror.IsNotExist(err) {
return gr.SetRoutes(canary, 100, 0, false)
} else {
return err
targetName := canary.Spec.TargetRef.Name
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
newSpec := gloov1.UpstreamGroupSpec{
Destinations: []gloov1.WeightedDestination{
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: primaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: 100,
},
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: canaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: 0,
},
},
}
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
if errors.IsNotFound(err) {
upstreamGroup = &gloov1.UpstreamGroup{
ObjectMeta: metav1.ObjectMeta{
Name: targetName,
Namespace: canary.Namespace,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryKind,
}),
},
},
Spec: newSpec,
}
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Create(upstreamGroup)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s create error %v", targetName, canary.Namespace, err)
}
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Infof("UpstreamGroup %s.%s created", upstreamGroup.GetName(), canary.Namespace)
return nil
}
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
}
// update upstreamGroup but keep the original destination weights
if upstreamGroup != nil {
if diff := cmp.Diff(
newSpec,
upstreamGroup.Spec,
cmpopts.IgnoreFields(gloov1.WeightedDestination{}, "Weight"),
); diff != "" {
clone := upstreamGroup.DeepCopy()
clone.Spec = newSpec
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(clone)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s update error %v", targetName, canary.Namespace, err)
}
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Infof("UpstreamGroup %s.%s updated", upstreamGroup.GetName(), canary.Namespace)
}
}
return nil
}
// GetRoutes returns the destinations weight for primary and canary
@@ -81,29 +114,31 @@ func (gr *GlooRouter) GetRoutes(canary *flaggerv1.Canary) (
err error,
) {
targetName := canary.Spec.TargetRef.Name
var ug *gloov1.UpstreamGroup
ug, err = gr.ugClient.Read(canary.Namespace, targetName, solokitclients.ReadOpts{})
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
err = fmt.Errorf("UpstreamGroup %s.%s not found", targetName, canary.Namespace)
return
}
err = fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
return
}
dests := ug.GetDestinations()
for _, dest := range dests {
if dest.GetDestination().GetUpstream().Name == upstreamName(canary.Namespace, fmt.Sprintf("%s-primary", targetName), canary.Spec.Service.Port) {
primaryWeight = int(dest.Weight)
}
if dest.GetDestination().GetUpstream().Name == upstreamName(canary.Namespace, fmt.Sprintf("%s-canary", targetName), canary.Spec.Service.Port) {
canaryWeight = int(dest.Weight)
}
if len(upstreamGroup.Spec.Destinations) < 2 {
err = fmt.Errorf("UpstreamGroup %s.%s destinations not found", targetName, canary.Namespace)
return
}
if primaryWeight == 0 && canaryWeight == 0 {
err = fmt.Errorf("RoutingRule %s.%s does not contain routes for %s-primary and %s-canary",
targetName, canary.Namespace, targetName, targetName)
for _, dst := range upstreamGroup.Spec.Destinations {
if dst.Destination.Upstream.Name == primaryName {
primaryWeight = int(dst.Weight)
canaryWeight = 100 - primaryWeight
return
}
}
mirrored = false
return
}
@@ -115,77 +150,48 @@ func (gr *GlooRouter) SetRoutes(
mirrored bool,
) error {
targetName := canary.Spec.TargetRef.Name
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
if primaryWeight == 0 && canaryWeight == 0 {
return fmt.Errorf("RoutingRule %s.%s update failed: no valid weights", targetName, canary.Namespace)
}
destinations := []*gloov1.WeightedDestination{}
destinations = append(destinations, &gloov1.WeightedDestination{
Destination: &gloov1.Destination{
Upstream: solokitcore.ResourceRef{
Name: upstreamName(canary.Namespace, fmt.Sprintf("%s-primary", targetName), canary.Spec.Service.Port),
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(primaryWeight),
})
destinations = append(destinations, &gloov1.WeightedDestination{
Destination: &gloov1.Destination{
Upstream: solokitcore.ResourceRef{
Name: upstreamName(canary.Namespace, fmt.Sprintf("%s-canary", targetName), canary.Spec.Service.Port),
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(canaryWeight),
})
upstreamGroup := &gloov1.UpstreamGroup{
Metadata: solokitcore.Metadata{
Name: canary.Spec.TargetRef.Name,
Namespace: canary.Namespace,
},
Destinations: destinations,
}
return gr.writeUpstreamGroupRuleForCanary(canary, upstreamGroup)
}
func (gr *GlooRouter) writeUpstreamGroupRuleForCanary(canary *flaggerv1.Canary, ug *gloov1.UpstreamGroup) error {
targetName := canary.Spec.TargetRef.Name
if oldUg, err := gr.ugClient.Read(ug.Metadata.Namespace, ug.Metadata.Name, solokitclients.ReadOpts{}); err != nil {
if solokiterror.IsNotExist(err) {
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Infof("UpstreamGroup %s created", ug.Metadata.Name)
} else {
return fmt.Errorf("RoutingRule %s.%s read failed: %v", targetName, canary.Namespace, err)
}
} else {
ug.Metadata.ResourceVersion = oldUg.Metadata.ResourceVersion
// if the old and the new one are equal, no need to do anything.
oldUg.Status = solokitcore.Status{}
if oldUg.Equal(ug) {
return nil
}
}
kubeWriteOpts := &kube.KubeWriteOpts{
PreWriteCallback: func(r *crdv1.Resource) {
r.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryKind,
}),
}
},
}
writeOpts := solokitclients.WriteOpts{OverwriteExisting: true, StorageWriteOpts: kubeWriteOpts}
_, err := gr.ugClient.Write(ug, writeOpts)
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s update failed: %v", targetName, canary.Namespace, err)
if errors.IsNotFound(err) {
return fmt.Errorf("UpstreamGroup %s.%s not found", targetName, canary.Namespace)
}
return fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
}
upstreamGroup.Spec = gloov1.UpstreamGroupSpec{
Destinations: []gloov1.WeightedDestination{
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: primaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(primaryWeight),
},
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: canaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(canaryWeight),
},
},
}
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(upstreamGroup)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s update error %v", targetName, canary.Namespace, err)
}
return nil
}
+33 -48
View File
@@ -1,40 +1,34 @@
package router
import (
"context"
"fmt"
"testing"
gloov1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
solokitclients "github.com/solo-io/solo-kit/pkg/api/v1/clients"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/factory"
solokitmemory "github.com/solo-io/solo-kit/pkg/api/v1/clients/memory"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
)
func TestGlooRouter_Sync(t *testing.T) {
mocks := setupfakeClients()
router := &GlooRouter{
logger: mocks.logger,
flaggerClient: mocks.flaggerClient,
glooClient: mocks.meshClient,
kubeClient: mocks.kubeClient,
}
upstreamGroupClient, err := gloov1.NewUpstreamGroupClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
}
if err := upstreamGroupClient.Register(); err != nil {
t.Fatal(err.Error())
}
router := NewGlooRouterWithClient(context.TODO(), upstreamGroupClient, "gloo-system", mocks.logger)
err = router.Reconcile(mocks.canary)
err := router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
// test insert
ug, err := upstreamGroupClient.Read("default", "podinfo", solokitclients.ReadOpts{})
ug, err := router.glooClient.GlooV1().UpstreamGroups("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
dests := ug.GetDestinations()
dests := ug.Spec.Destinations
if len(dests) != 2 {
t.Errorf("Got Destinations %v wanted %v", len(dests), 2)
}
@@ -49,21 +43,15 @@ func TestGlooRouter_Sync(t *testing.T) {
}
func TestGlooRouter_SetRoutes(t *testing.T) {
mocks := setupfakeClients()
upstreamGroupClient, err := gloov1.NewUpstreamGroupClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
router := &GlooRouter{
logger: mocks.logger,
flaggerClient: mocks.flaggerClient,
glooClient: mocks.meshClient,
kubeClient: mocks.kubeClient,
}
if err := upstreamGroupClient.Register(); err != nil {
t.Fatal(err.Error())
}
router := NewGlooRouterWithClient(context.TODO(), upstreamGroupClient, "gloo-system", mocks.logger)
err = router.Reconcile(mocks.canary)
err := router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
@@ -82,20 +70,21 @@ func TestGlooRouter_SetRoutes(t *testing.T) {
t.Fatal(err.Error())
}
ug, err := upstreamGroupClient.Read("default", "podinfo", solokitclients.ReadOpts{})
ug, err := router.glooClient.GlooV1().UpstreamGroups("default").Get("podinfo", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
var pRoute *gloov1.WeightedDestination
var cRoute *gloov1.WeightedDestination
targetName := mocks.canary.Spec.TargetRef.Name
var pRoute gloov1.WeightedDestination
var cRoute gloov1.WeightedDestination
canaryName := fmt.Sprintf("%s-%s-canary-%v", mocks.canary.Namespace, mocks.canary.Spec.TargetRef.Name, mocks.canary.Spec.Service.Port)
primaryName := fmt.Sprintf("%s-%s-primary-%v", mocks.canary.Namespace, mocks.canary.Spec.TargetRef.Name, mocks.canary.Spec.Service.Port)
for _, dest := range ug.GetDestinations() {
if dest.GetDestination().GetUpstream().Name == upstreamName(mocks.canary.Namespace, fmt.Sprintf("%s-primary", targetName), mocks.canary.Spec.Service.Port) {
for _, dest := range ug.Spec.Destinations {
if dest.Destination.Upstream.Name == primaryName {
pRoute = dest
}
if dest.GetDestination().GetUpstream().Name == upstreamName(mocks.canary.Namespace, fmt.Sprintf("%s-canary", targetName), mocks.canary.Spec.Service.Port) {
if dest.Destination.Upstream.Name == canaryName {
cRoute = dest
}
}
@@ -112,18 +101,14 @@ func TestGlooRouter_SetRoutes(t *testing.T) {
func TestGlooRouter_GetRoutes(t *testing.T) {
mocks := setupfakeClients()
router := &GlooRouter{
logger: mocks.logger,
flaggerClient: mocks.flaggerClient,
glooClient: mocks.meshClient,
kubeClient: mocks.kubeClient,
}
upstreamGroupClient, err := gloov1.NewUpstreamGroupClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
}
if err := upstreamGroupClient.Register(); err != nil {
t.Fatal(err.Error())
}
router := NewGlooRouterWithClient(context.TODO(), upstreamGroupClient, "gloo-system", mocks.logger)
err = router.Reconcile(mocks.canary)
err := router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
-349
View File
@@ -1,349 +0,0 @@
package router
import (
"context"
"fmt"
"strings"
"time"
solokitclients "github.com/solo-io/solo-kit/pkg/api/v1/clients"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/factory"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/kube"
crdv1 "github.com/solo-io/solo-kit/pkg/api/v1/clients/kube/crd/solo.io/v1"
solokitcore "github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
solokiterror "github.com/solo-io/solo-kit/pkg/errors"
"github.com/gogo/protobuf/types"
gloov1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
supergloov1alpha3 "github.com/solo-io/supergloo/pkg/api/external/istio/networking/v1alpha3"
supergloov1 "github.com/solo-io/supergloo/pkg/api/v1"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1alpha3"
istiov1alpha3 "github.com/weaveworks/flagger/pkg/apis/istio/v1alpha3"
clientset "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
)
// SuperglooRouter is managing Istio virtual services
type SuperglooRouter struct {
rrClient supergloov1.RoutingRuleClient
logger *zap.SugaredLogger
targetMesh solokitcore.ResourceRef
}
func NewSuperglooRouter(ctx context.Context, provider string, flaggerClient clientset.Interface, logger *zap.SugaredLogger, cfg *rest.Config) (*SuperglooRouter, error) {
// TODO if cfg is nil use memory client instead?
sharedCache := kube.NewKubeCache(ctx)
routingRuleClient, err := supergloov1.NewRoutingRuleClient(&factory.KubeResourceClientFactory{
Crd: supergloov1.RoutingRuleCrd,
Cfg: cfg,
SharedCache: sharedCache,
SkipCrdCreation: true,
})
if err != nil {
// this should never happen.
return nil, fmt.Errorf("creating RoutingRule client %v", err)
}
if err := routingRuleClient.Register(); err != nil {
return nil, err
}
// remove the supergloo: prefix
provider = strings.TrimPrefix(provider, "supergloo:")
// split name.namespace:
parts := strings.Split(provider, ".")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid format for supergloo provider")
}
targetMesh := solokitcore.ResourceRef{
Namespace: parts[1],
Name: parts[0],
}
return NewSuperglooRouterWithClient(ctx, routingRuleClient, targetMesh, logger), nil
}
func NewSuperglooRouterWithClient(ctx context.Context, routingRuleClient supergloov1.RoutingRuleClient, targetMesh solokitcore.ResourceRef, logger *zap.SugaredLogger) *SuperglooRouter {
return &SuperglooRouter{rrClient: routingRuleClient, logger: logger, targetMesh: targetMesh}
}
// Reconcile creates or updates the Istio virtual service
func (sr *SuperglooRouter) Reconcile(canary *flaggerv1.Canary) error {
if err := sr.setRetries(canary); err != nil {
return err
}
if err := sr.setHeaders(canary); err != nil {
return err
}
if err := sr.setCors(canary); err != nil {
return err
}
// do we have routes already?
if _, _, _, err := sr.GetRoutes(canary); err == nil {
// we have routes, no need to do anything else
return nil
} else if solokiterror.IsNotExist(err) {
return sr.SetRoutes(canary, 100, 0, false)
} else {
return err
}
}
func (sr *SuperglooRouter) setRetries(canary *flaggerv1.Canary) error {
if canary.Spec.Service.Retries == nil {
return nil
}
retries, err := convertRetries(canary.Spec.Service.Retries)
if err != nil {
return err
}
rule := sr.createRule(canary, "retries", &supergloov1.RoutingRuleSpec{
RuleType: &supergloov1.RoutingRuleSpec_Retries{
Retries: retries,
},
})
return sr.writeRuleForCanary(canary, rule)
}
func (sr *SuperglooRouter) setHeaders(canary *flaggerv1.Canary) error {
if canary.Spec.Service.Headers == nil {
return nil
}
headerManipulation, err := convertHeaders(canary.Spec.Service.Headers)
if err != nil {
return err
}
if headerManipulation == nil {
return nil
}
rule := sr.createRule(canary, "headers", &supergloov1.RoutingRuleSpec{
RuleType: &supergloov1.RoutingRuleSpec_HeaderManipulation{
HeaderManipulation: headerManipulation,
},
})
return sr.writeRuleForCanary(canary, rule)
}
func convertHeaders(headers *istiov1alpha3.Headers) (*supergloov1.HeaderManipulation, error) {
var headersMaipulation *supergloov1.HeaderManipulation
if headers.Request != nil {
headersMaipulation = &supergloov1.HeaderManipulation{}
headersMaipulation.RemoveRequestHeaders = headers.Request.Remove
headersMaipulation.AppendRequestHeaders = make(map[string]string)
for k, v := range headers.Request.Add {
headersMaipulation.AppendRequestHeaders[k] = v
}
}
if headers.Response != nil {
if headersMaipulation == nil {
headersMaipulation = &supergloov1.HeaderManipulation{}
}
headersMaipulation.RemoveResponseHeaders = headers.Response.Remove
headersMaipulation.AppendResponseHeaders = make(map[string]string)
for k, v := range headers.Response.Add {
headersMaipulation.AppendResponseHeaders[k] = v
}
}
return headersMaipulation, nil
}
func convertRetries(retries *istiov1alpha3.HTTPRetry) (*supergloov1.RetryPolicy, error) {
perTryTimeout, err := time.ParseDuration(retries.PerTryTimeout)
return &supergloov1.RetryPolicy{
MaxRetries: &supergloov1alpha3.HTTPRetry{
Attempts: int32(retries.Attempts),
PerTryTimeout: types.DurationProto(perTryTimeout),
RetryOn: retries.RetryOn,
},
}, err
}
func (sr *SuperglooRouter) setCors(canary *flaggerv1.Canary) error {
corsPolicy := canary.Spec.Service.CorsPolicy
if corsPolicy == nil {
return nil
}
var maxAgeDuration *types.Duration
if maxAge, err := time.ParseDuration(corsPolicy.MaxAge); err == nil {
maxAgeDuration = types.DurationProto(maxAge)
}
rule := sr.createRule(canary, "cors", &supergloov1.RoutingRuleSpec{
RuleType: &supergloov1.RoutingRuleSpec_CorsPolicy{
CorsPolicy: &supergloov1alpha3.CorsPolicy{
AllowOrigin: corsPolicy.AllowOrigin,
AllowMethods: corsPolicy.AllowMethods,
AllowHeaders: corsPolicy.AllowHeaders,
ExposeHeaders: corsPolicy.ExposeHeaders,
MaxAge: maxAgeDuration,
AllowCredentials: &types.BoolValue{Value: corsPolicy.AllowCredentials},
},
},
})
return sr.writeRuleForCanary(canary, rule)
}
func (sr *SuperglooRouter) createRule(canary *flaggerv1.Canary, namesuffix string, spec *supergloov1.RoutingRuleSpec) *supergloov1.RoutingRule {
if namesuffix != "" {
namesuffix = "-" + namesuffix
}
return &supergloov1.RoutingRule{
Metadata: solokitcore.Metadata{
Name: canary.Spec.TargetRef.Name + namesuffix,
Namespace: canary.Namespace,
},
TargetMesh: &sr.targetMesh,
DestinationSelector: &supergloov1.PodSelector{
SelectorType: &supergloov1.PodSelector_UpstreamSelector_{
UpstreamSelector: &supergloov1.PodSelector_UpstreamSelector{
Upstreams: []solokitcore.ResourceRef{{
Name: upstreamName(canary.Namespace, fmt.Sprintf("%s", canary.Spec.TargetRef.Name), canary.Spec.Service.Port),
Namespace: sr.targetMesh.Namespace,
}},
},
},
},
Spec: spec,
}
}
// GetRoutes returns the destinations weight for primary and canary
func (sr *SuperglooRouter) GetRoutes(canary *flaggerv1.Canary) (
primaryWeight int,
canaryWeight int,
mirrored bool,
err error,
) {
targetName := canary.Spec.TargetRef.Name
var rr *supergloov1.RoutingRule
rr, err = sr.rrClient.Read(canary.Namespace, targetName, solokitclients.ReadOpts{})
if err != nil {
return
}
traffic := rr.GetSpec().GetTrafficShifting()
if traffic == nil {
err = fmt.Errorf("target rule is not for traffic shifting")
return
}
dests := traffic.GetDestinations().GetDestinations()
for _, dest := range dests {
if dest.GetDestination().GetUpstream().Name == upstreamName(canary.Namespace, fmt.Sprintf("%s-primary", targetName), canary.Spec.Service.Port) {
primaryWeight = int(dest.Weight)
}
if dest.GetDestination().GetUpstream().Name == upstreamName(canary.Namespace, fmt.Sprintf("%s-canary", targetName), canary.Spec.Service.Port) {
canaryWeight = int(dest.Weight)
}
}
if primaryWeight == 0 && canaryWeight == 0 {
err = fmt.Errorf("RoutingRule %s.%s does not contain routes for %s-primary and %s-canary",
targetName, canary.Namespace, targetName, targetName)
}
mirrored = false
return
}
func upstreamName(serviceNamespace, serviceName string, port int32) string {
return fmt.Sprintf("%s-%s-%d", serviceNamespace, serviceName, port)
}
// SetRoutes updates the destinations weight for primary and canary
func (sr *SuperglooRouter) SetRoutes(
canary *flaggerv1.Canary,
primaryWeight int,
canaryWeight int,
mirrored bool,
) error {
// upstream name is
// in gloo-system
// and is the same as
targetName := canary.Spec.TargetRef.Name
destinations := []*gloov1.WeightedDestination{}
if primaryWeight != 0 {
destinations = append(destinations, &gloov1.WeightedDestination{
Destination: &gloov1.Destination{
Upstream: solokitcore.ResourceRef{
Name: upstreamName(canary.Namespace, fmt.Sprintf("%s-primary", targetName), canary.Spec.Service.Port),
Namespace: sr.targetMesh.Namespace,
},
},
Weight: uint32(primaryWeight),
})
}
if canaryWeight != 0 {
destinations = append(destinations, &gloov1.WeightedDestination{
Destination: &gloov1.Destination{
Upstream: solokitcore.ResourceRef{
Name: upstreamName(canary.Namespace, fmt.Sprintf("%s-canary", targetName), canary.Spec.Service.Port),
Namespace: sr.targetMesh.Namespace,
},
},
Weight: uint32(canaryWeight),
})
}
if len(destinations) == 0 {
return fmt.Errorf("RoutingRule %s.%s update failed: no valid weights", targetName, canary.Namespace)
}
rule := sr.createRule(canary, "", &supergloov1.RoutingRuleSpec{
RuleType: &supergloov1.RoutingRuleSpec_TrafficShifting{
TrafficShifting: &supergloov1.TrafficShifting{
Destinations: &gloov1.MultiDestination{
Destinations: destinations,
},
},
},
})
return sr.writeRuleForCanary(canary, rule)
}
func (sr *SuperglooRouter) writeRuleForCanary(canary *flaggerv1.Canary, rule *supergloov1.RoutingRule) error {
targetName := canary.Spec.TargetRef.Name
if oldRr, err := sr.rrClient.Read(rule.Metadata.Namespace, rule.Metadata.Name, solokitclients.ReadOpts{}); err != nil {
// ignore not exist errors..
if !solokiterror.IsNotExist(err) {
return fmt.Errorf("RoutingRule %s.%s read failed: %v", targetName, canary.Namespace, err)
}
} else {
rule.Metadata.ResourceVersion = oldRr.Metadata.ResourceVersion
// if the old and the new one are equal, no need to do anything.
oldRr.Status = solokitcore.Status{}
if oldRr.Equal(rule) {
return nil
}
}
kubeWriteOpts := &kube.KubeWriteOpts{
PreWriteCallback: func(r *crdv1.Resource) {
r.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryKind,
}),
}
},
}
writeOpts := solokitclients.WriteOpts{OverwriteExisting: true, StorageWriteOpts: kubeWriteOpts}
_, err := sr.rrClient.Write(rule, writeOpts)
if err != nil {
return fmt.Errorf("RoutingRule %s.%s update failed: %v", targetName, canary.Namespace, err)
}
return nil
}
-154
View File
@@ -1,154 +0,0 @@
package router
import (
"context"
"fmt"
"testing"
gloov1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1"
solokitclients "github.com/solo-io/solo-kit/pkg/api/v1/clients"
"github.com/solo-io/solo-kit/pkg/api/v1/clients/factory"
solokitmemory "github.com/solo-io/solo-kit/pkg/api/v1/clients/memory"
solokitcore "github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
supergloov1 "github.com/solo-io/supergloo/pkg/api/v1"
)
func TestSuperglooRouter_Sync(t *testing.T) {
mocks := setupfakeClients()
routingRuleClient, err := supergloov1.NewRoutingRuleClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
}
if err := routingRuleClient.Register(); err != nil {
t.Fatal(err.Error())
}
targetMesh := solokitcore.ResourceRef{
Namespace: "supergloo-system",
Name: "mesh",
}
router := NewSuperglooRouterWithClient(context.TODO(), routingRuleClient, targetMesh, mocks.logger)
err = router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
// test insert
rr, err := routingRuleClient.Read("default", "podinfo", solokitclients.ReadOpts{})
if err != nil {
t.Fatal(err.Error())
}
dests := rr.Spec.GetTrafficShifting().GetDestinations().GetDestinations()
if len(dests) != 1 {
t.Errorf("Got RoutingRule Destinations %v wanted %v", len(dests), 1)
}
}
func TestSuperglooRouter_SetRoutes(t *testing.T) {
mocks := setupfakeClients()
routingRuleClient, err := supergloov1.NewRoutingRuleClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
}
if err := routingRuleClient.Register(); err != nil {
t.Fatal(err.Error())
}
targetMesh := solokitcore.ResourceRef{
Namespace: "supergloo-system",
Name: "mesh",
}
router := NewSuperglooRouterWithClient(context.TODO(), routingRuleClient, targetMesh, mocks.logger)
err = router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
p, c, m, err := router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
p = 50
c = 50
m = false
err = router.SetRoutes(mocks.canary, p, c, m)
if err != nil {
t.Fatal(err.Error())
}
rr, err := routingRuleClient.Read("default", "podinfo", solokitclients.ReadOpts{})
if err != nil {
t.Fatal(err.Error())
}
var pRoute *gloov1.WeightedDestination
var cRoute *gloov1.WeightedDestination
targetName := mocks.canary.Spec.TargetRef.Name
for _, dest := range rr.GetSpec().GetTrafficShifting().GetDestinations().GetDestinations() {
if dest.GetDestination().GetUpstream().Name == upstreamName(mocks.canary.Namespace, fmt.Sprintf("%s-primary", targetName), mocks.canary.Spec.Service.Port) {
pRoute = dest
}
if dest.GetDestination().GetUpstream().Name == upstreamName(mocks.canary.Namespace, fmt.Sprintf("%s-canary", targetName), mocks.canary.Spec.Service.Port) {
cRoute = dest
}
}
if pRoute.Weight != uint32(p) {
t.Errorf("Got primary weight %v wanted %v", pRoute.Weight, p)
}
if cRoute.Weight != uint32(c) {
t.Errorf("Got canary weight %v wanted %v", cRoute.Weight, c)
}
}
func TestSuperglooRouter_GetRoutes(t *testing.T) {
mocks := setupfakeClients()
routingRuleClient, err := supergloov1.NewRoutingRuleClient(&factory.MemoryResourceClientFactory{
Cache: solokitmemory.NewInMemoryResourceCache(),
})
if err != nil {
t.Fatal(err.Error())
}
if err := routingRuleClient.Register(); err != nil {
t.Fatal(err.Error())
}
targetMesh := solokitcore.ResourceRef{
Namespace: "supergloo-system",
Name: "mesh",
}
router := NewSuperglooRouterWithClient(context.TODO(), routingRuleClient, targetMesh, mocks.logger)
err = router.Reconcile(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
p, c, m, err := router.GetRoutes(mocks.canary)
if err != nil {
t.Fatal(err.Error())
}
if p != 100 {
t.Errorf("Got primary weight %v wanted %v", p, 100)
}
if c != 0 {
t.Errorf("Got canary weight %v wanted %v", c, 0)
}
if m != false {
t.Errorf("Got mirror %v wanted %v", m, false)
}
}