mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
feat(source/istio): support version 1.25+ (#5611)
* feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.22 Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * feat(source/istio): support version 1.25+ Co-authored-by: mthemis-provenir <168411899+mthemis-provenir@users.noreply.github.com> --------- Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> Co-authored-by: mthemis-provenir <168411899+mthemis-provenir@users.noreply.github.com>
This commit is contained in:
parent
5c42ed00c7
commit
252a5e016c
@ -5,9 +5,13 @@ It is meant to supplement the other provider-specific setup tutorials.
|
|||||||
|
|
||||||
**Note:** Using the Istio Gateway source requires Istio >=1.0.0.
|
**Note:** Using the Istio Gateway source requires Istio >=1.0.0.
|
||||||
|
|
||||||
* Manifest (for clusters without RBAC enabled)
|
**Note:** Currently supported versions are `1.25` and `1.26` with `v1beta1` stored version.
|
||||||
* Manifest (for clusters with RBAC enabled)
|
|
||||||
* Update existing ExternalDNS Deployment
|
- [Support status of Istio releases](https://istio.io/latest/docs/releases/supported-releases/)
|
||||||
|
|
||||||
|
- Manifest (for clusters without RBAC enabled)
|
||||||
|
- Manifest (for clusters with RBAC enabled)
|
||||||
|
- Update existing ExternalDNS Deployment
|
||||||
|
|
||||||
## Manifest (for clusters without RBAC enabled)
|
## Manifest (for clusters without RBAC enabled)
|
||||||
|
|
||||||
@ -119,9 +123,9 @@ spec:
|
|||||||
|
|
||||||
## Update existing ExternalDNS Deployment
|
## Update existing ExternalDNS Deployment
|
||||||
|
|
||||||
* For clusters with running `external-dns`, you can just update the deployment.
|
- For clusters with running `external-dns`, you can just update the deployment.
|
||||||
* With access to the `kube-system` namespace, update the existing `external-dns` deployment.
|
- With access to the `kube-system` namespace, update the existing `external-dns` deployment.
|
||||||
* Add a parameter to the arguments of the container to create dns entries with `--source=istio-gateway`.
|
- Add a parameter to the arguments of the container to create dns entries with `--source=istio-gateway`.
|
||||||
|
|
||||||
Execute the following command or update the argument.
|
Execute the following command or update the argument.
|
||||||
|
|
||||||
@ -148,13 +152,13 @@ The following are relevant snippets from that tutorial.
|
|||||||
With automatic sidecar injection:
|
With automatic sidecar injection:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml
|
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.25/samples/httpbin/httpbin.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Otherwise:
|
Otherwise:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f <(istioctl kube-inject -f https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml)
|
kubectl apply -f <(istioctl kube-inject -f https://raw.githubusercontent.com/istio/istio/release-1.25/samples/httpbin/httpbin.yaml)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using a Gateway as a source
|
### Using a Gateway as a source
|
||||||
@ -320,13 +324,13 @@ EOF
|
|||||||
|
|
||||||
## Debug ExternalDNS
|
## Debug ExternalDNS
|
||||||
|
|
||||||
* Look for the deployment pod to see the status
|
- Look for the deployment pod to see the status
|
||||||
|
|
||||||
```console$ kubectl get pods | grep external-dns
|
```console$ kubectl get pods | grep external-dns
|
||||||
external-dns-6b84999479-4knv9 1/1 Running 0 3h29m
|
external-dns-6b84999479-4knv9 1/1 Running 0 3h29m
|
||||||
```
|
```
|
||||||
|
|
||||||
* Watch for the logs as follows
|
- Watch for the logs as follows
|
||||||
|
|
||||||
```console
|
```console
|
||||||
kubectl logs -f external-dns-6b84999479-4knv9
|
kubectl logs -f external-dns-6b84999479-4knv9
|
||||||
@ -336,7 +340,7 @@ At this point, you can `create` or `update` any `Istio Gateway` object with `hos
|
|||||||
|
|
||||||
> **ATTENTION**: Make sure to specify those whose account is related to the DNS record.
|
> **ATTENTION**: Make sure to specify those whose account is related to the DNS record.
|
||||||
|
|
||||||
* Successful executions will print the following
|
- Successful executions will print the following
|
||||||
|
|
||||||
```console
|
```console
|
||||||
time="2020-01-17T06:08:08Z" level=info msg="Desired change: CREATE httpbin.example.com A"
|
time="2020-01-17T06:08:08Z" level=info msg="Desired change: CREATE httpbin.example.com A"
|
||||||
@ -345,7 +349,7 @@ time="2020-01-17T06:08:08Z" level=info msg="2 record(s) in zone example.com. wer
|
|||||||
time="2020-01-17T06:09:08Z" level=info msg="All records are already up to date, there are no changes for the matching hosted zones"
|
time="2020-01-17T06:09:08Z" level=info msg="All records are already up to date, there are no changes for the matching hosted zones"
|
||||||
```
|
```
|
||||||
|
|
||||||
* If there's any problem around `clusterrole`, you would see the errors showing wrong permissions:
|
- If there's any problem around `clusterrole`, you would see the errors showing wrong permissions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
source \"gateways\" in API group \"networking.istio.io\" at the cluster scope"
|
source \"gateways\" in API group \"networking.istio.io\" at the cluster scope"
|
||||||
|
@ -18,7 +18,6 @@ package registry
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -1511,7 +1510,6 @@ func TestNewTXTScheme(t *testing.T) {
|
|||||||
assert.Nil(t, ctx.Value(provider.RecordsContextKey))
|
assert.Nil(t, ctx.Value(provider.RecordsContextKey))
|
||||||
}
|
}
|
||||||
err := r.ApplyChanges(ctx, changes)
|
err := r.ApplyChanges(ctx, changes)
|
||||||
fmt.Println(err)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,10 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
networkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
|
networkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
||||||
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
||||||
istioinformers "istio.io/client-go/pkg/informers/externalversions"
|
istioinformers "istio.io/client-go/pkg/informers/externalversions"
|
||||||
networkingv1alpha3informer "istio.io/client-go/pkg/informers/externalversions/networking/v1alpha3"
|
networkingv1beta1informer "istio.io/client-go/pkg/informers/externalversions/networking/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
kubeinformers "k8s.io/client-go/informers"
|
kubeinformers "k8s.io/client-go/informers"
|
||||||
@ -57,7 +57,7 @@ type gatewaySource struct {
|
|||||||
combineFQDNAnnotation bool
|
combineFQDNAnnotation bool
|
||||||
ignoreHostnameAnnotation bool
|
ignoreHostnameAnnotation bool
|
||||||
serviceInformer coreinformers.ServiceInformer
|
serviceInformer coreinformers.ServiceInformer
|
||||||
gatewayInformer networkingv1alpha3informer.GatewayInformer
|
gatewayInformer networkingv1beta1informer.GatewayInformer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIstioGatewaySource creates a new gatewaySource with the given config.
|
// NewIstioGatewaySource creates a new gatewaySource with the given config.
|
||||||
@ -81,10 +81,10 @@ func NewIstioGatewaySource(
|
|||||||
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
|
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
|
||||||
serviceInformer := informerFactory.Core().V1().Services()
|
serviceInformer := informerFactory.Core().V1().Services()
|
||||||
istioInformerFactory := istioinformers.NewSharedInformerFactory(istioClient, 0)
|
istioInformerFactory := istioinformers.NewSharedInformerFactory(istioClient, 0)
|
||||||
gatewayInformer := istioInformerFactory.Networking().V1alpha3().Gateways()
|
gatewayInformer := istioInformerFactory.Networking().V1beta1().Gateways()
|
||||||
|
|
||||||
// Add default resource event handlers to properly initialize informer.
|
// Add default resource event handlers to properly initialize informer.
|
||||||
serviceInformer.Informer().AddEventHandler(
|
_, _ = serviceInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
log.Debug("service added")
|
log.Debug("service added")
|
||||||
@ -92,7 +92,7 @@ func NewIstioGatewaySource(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
gatewayInformer.Informer().AddEventHandler(
|
_, _ = gatewayInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
log.Debug("gateway added")
|
log.Debug("gateway added")
|
||||||
@ -127,7 +127,7 @@ func NewIstioGatewaySource(
|
|||||||
// Endpoints returns endpoint objects for each host-target combination that should be processed.
|
// Endpoints returns endpoint objects for each host-target combination that should be processed.
|
||||||
// Retrieves all gateway resources in the source's namespace(s).
|
// Retrieves all gateway resources in the source's namespace(s).
|
||||||
func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
||||||
gwList, err := sc.istioClient.NetworkingV1alpha3().Gateways(sc.namespace).List(ctx, metav1.ListOptions{})
|
gwList, err := sc.istioClient.NetworkingV1beta1().Gateways(sc.namespace).List(ctx, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -140,12 +140,14 @@ func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e
|
|||||||
|
|
||||||
var endpoints []*endpoint.Endpoint
|
var endpoints []*endpoint.Endpoint
|
||||||
|
|
||||||
|
log.Debugf("Found %d gateways in namespace %s", len(gateways), sc.namespace)
|
||||||
|
|
||||||
for _, gateway := range gateways {
|
for _, gateway := range gateways {
|
||||||
// Check controller annotation to see if we are responsible.
|
// Check controller annotation to see if we are responsible.
|
||||||
controller, ok := gateway.Annotations[controllerAnnotationKey]
|
controller, ok := gateway.Annotations[controllerAnnotationKey]
|
||||||
if ok && controller != controllerAnnotationValue {
|
if ok && controller != controllerAnnotationValue {
|
||||||
log.Debugf("Skipping gateway %s/%s because controller value does not match, found: %s, required: %s",
|
log.Debugf("Skipping gateway %s/%s,%s because controller value does not match, found: %s, required: %s",
|
||||||
gateway.Namespace, gateway.Name, controller, controllerAnnotationValue)
|
gateway.Namespace, gateway.APIVersion, gateway.Name, controller, controllerAnnotationValue)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +170,8 @@ func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("Processing gateway '%s/%s.%s' and hosts %q", gateway.Namespace, gateway.APIVersion, gateway.Name, strings.Join(gwHostnames, ","))
|
||||||
|
|
||||||
if len(gwHostnames) == 0 {
|
if len(gwHostnames) == 0 {
|
||||||
log.Debugf("No hostnames could be generated from gateway %s/%s", gateway.Namespace, gateway.Name)
|
log.Debugf("No hostnames could be generated from gateway %s/%s", gateway.Namespace, gateway.Name)
|
||||||
continue
|
continue
|
||||||
@ -183,10 +187,11 @@ func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Endpoints generated from gateway: %s/%s: %v", gateway.Namespace, gateway.Name, gwEndpoints)
|
log.Debugf("Endpoints generated from %q '%s/%s.%s': %q", gateway.Kind, gateway.Namespace, gateway.APIVersion, gateway.Name, gwEndpoints)
|
||||||
endpoints = append(endpoints, gwEndpoints...)
|
endpoints = append(endpoints, gwEndpoints...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: sort on endpoint creation
|
||||||
for _, ep := range endpoints {
|
for _, ep := range endpoints {
|
||||||
sort.Sort(ep.Targets)
|
sort.Sort(ep.Targets)
|
||||||
}
|
}
|
||||||
@ -198,11 +203,11 @@ func (sc *gatewaySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e
|
|||||||
func (sc *gatewaySource) AddEventHandler(ctx context.Context, handler func()) {
|
func (sc *gatewaySource) AddEventHandler(ctx context.Context, handler func()) {
|
||||||
log.Debug("Adding event handler for Istio Gateway")
|
log.Debug("Adding event handler for Istio Gateway")
|
||||||
|
|
||||||
sc.gatewayInformer.Informer().AddEventHandler(eventHandlerFunc(handler))
|
_, _ = sc.gatewayInformer.Informer().AddEventHandler(eventHandlerFunc(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterByAnnotations filters a list of configs by a given annotation selector.
|
// filterByAnnotations filters a list of configs by a given annotation selector.
|
||||||
func (sc *gatewaySource) filterByAnnotations(gateways []*networkingv1alpha3.Gateway) ([]*networkingv1alpha3.Gateway, error) {
|
func (sc *gatewaySource) filterByAnnotations(gateways []*networkingv1beta1.Gateway) ([]*networkingv1beta1.Gateway, error) {
|
||||||
selector, err := annotations.ParseFilter(sc.annotationFilter)
|
selector, err := annotations.ParseFilter(sc.annotationFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -213,7 +218,7 @@ func (sc *gatewaySource) filterByAnnotations(gateways []*networkingv1alpha3.Gate
|
|||||||
return gateways, nil
|
return gateways, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredList []*networkingv1alpha3.Gateway
|
var filteredList []*networkingv1beta1.Gateway
|
||||||
|
|
||||||
for _, gw := range gateways {
|
for _, gw := range gateways {
|
||||||
// include if the annotations match the selector
|
// include if the annotations match the selector
|
||||||
@ -225,7 +230,7 @@ func (sc *gatewaySource) filterByAnnotations(gateways []*networkingv1alpha3.Gate
|
|||||||
return filteredList, nil
|
return filteredList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *gatewaySource) targetsFromIngress(ctx context.Context, ingressStr string, gateway *networkingv1alpha3.Gateway) (endpoint.Targets, error) {
|
func (sc *gatewaySource) targetsFromIngress(ctx context.Context, ingressStr string, gateway *networkingv1beta1.Gateway) (endpoint.Targets, error) {
|
||||||
namespace, name, err := ParseIngress(ingressStr)
|
namespace, name, err := ParseIngress(ingressStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse Ingress annotation on Gateway (%s/%s): %w", gateway.Namespace, gateway.Name, err)
|
return nil, fmt.Errorf("failed to parse Ingress annotation on Gateway (%s/%s): %w", gateway.Namespace, gateway.Name, err)
|
||||||
@ -251,7 +256,7 @@ func (sc *gatewaySource) targetsFromIngress(ctx context.Context, ingressStr stri
|
|||||||
return targets, nil
|
return targets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *gatewaySource) targetsFromGateway(ctx context.Context, gateway *networkingv1alpha3.Gateway) (endpoint.Targets, error) {
|
func (sc *gatewaySource) targetsFromGateway(ctx context.Context, gateway *networkingv1beta1.Gateway) (endpoint.Targets, error) {
|
||||||
targets := annotations.TargetsFromTargetAnnotation(gateway.Annotations)
|
targets := annotations.TargetsFromTargetAnnotation(gateway.Annotations)
|
||||||
if len(targets) > 0 {
|
if len(targets) > 0 {
|
||||||
return targets, nil
|
return targets, nil
|
||||||
@ -266,22 +271,21 @@ func (sc *gatewaySource) targetsFromGateway(ctx context.Context, gateway *networ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// endpointsFromGatewayConfig extracts the endpoints from an Istio Gateway Config object
|
// endpointsFromGatewayConfig extracts the endpoints from an Istio Gateway Config object
|
||||||
func (sc *gatewaySource) endpointsFromGateway(ctx context.Context, hostnames []string, gateway *networkingv1alpha3.Gateway) ([]*endpoint.Endpoint, error) {
|
func (sc *gatewaySource) endpointsFromGateway(ctx context.Context, hostnames []string, gateway *networkingv1beta1.Gateway) ([]*endpoint.Endpoint, error) {
|
||||||
var endpoints []*endpoint.Endpoint
|
var endpoints []*endpoint.Endpoint
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
resource := fmt.Sprintf("gateway/%s/%s", gateway.Namespace, gateway.Name)
|
targets, err := sc.targetsFromGateway(ctx, gateway)
|
||||||
|
if err != nil {
|
||||||
ttl := annotations.TTLFromAnnotations(gateway.Annotations, resource)
|
return nil, err
|
||||||
|
|
||||||
targets := annotations.TargetsFromTargetAnnotation(gateway.Annotations)
|
|
||||||
if len(targets) == 0 {
|
|
||||||
targets, err = sc.targetsFromGateway(ctx, gateway)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(targets) == 0 {
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resource := fmt.Sprintf("gateway/%s/%s", gateway.Namespace, gateway.Name)
|
||||||
|
ttl := annotations.TTLFromAnnotations(gateway.Annotations, resource)
|
||||||
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(gateway.Annotations)
|
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(gateway.Annotations)
|
||||||
|
|
||||||
for _, host := range hostnames {
|
for _, host := range hostnames {
|
||||||
@ -291,7 +295,7 @@ func (sc *gatewaySource) endpointsFromGateway(ctx context.Context, hostnames []s
|
|||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *gatewaySource) hostNamesFromGateway(gateway *networkingv1alpha3.Gateway) ([]string, error) {
|
func (sc *gatewaySource) hostNamesFromGateway(gateway *networkingv1beta1.Gateway) ([]string, error) {
|
||||||
var hostnames []string
|
var hostnames []string
|
||||||
for _, server := range gateway.Spec.Servers {
|
for _, server := range gateway.Spec.Servers {
|
||||||
for _, host := range server.Hosts {
|
for _, host := range server.Hosts {
|
||||||
|
@ -24,8 +24,8 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
networkingv1alpha3api "istio.io/api/networking/v1alpha3"
|
networkingv1alpha3api "istio.io/api/networking/v1beta1"
|
||||||
networkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
|
networkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
||||||
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
|
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
networkv1 "k8s.io/api/networking/v1"
|
networkv1 "k8s.io/api/networking/v1"
|
||||||
@ -1494,7 +1494,7 @@ func testGatewayEndpoints(t *testing.T) {
|
|||||||
fakeIstioClient := istiofake.NewSimpleClientset()
|
fakeIstioClient := istiofake.NewSimpleClientset()
|
||||||
for _, config := range ti.configItems {
|
for _, config := range ti.configItems {
|
||||||
gatewayCfg := config.Config()
|
gatewayCfg := config.Config()
|
||||||
_, err := fakeIstioClient.NetworkingV1alpha3().Gateways(ti.targetNamespace).Create(context.Background(), gatewayCfg, metav1.CreateOptions{})
|
_, err := fakeIstioClient.NetworkingV1beta1().Gateways(ti.targetNamespace).Create(context.Background(), gatewayCfg, metav1.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,15 +20,16 @@ import (
|
|||||||
"cmp"
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
networkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
|
v1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
||||||
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
||||||
istioinformers "istio.io/client-go/pkg/informers/externalversions"
|
istioinformers "istio.io/client-go/pkg/informers/externalversions"
|
||||||
networkingv1alpha3informer "istio.io/client-go/pkg/informers/externalversions/networking/v1alpha3"
|
networkingv1beta1informer "istio.io/client-go/pkg/informers/externalversions/networking/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
@ -58,8 +59,8 @@ type virtualServiceSource struct {
|
|||||||
combineFQDNAnnotation bool
|
combineFQDNAnnotation bool
|
||||||
ignoreHostnameAnnotation bool
|
ignoreHostnameAnnotation bool
|
||||||
serviceInformer coreinformers.ServiceInformer
|
serviceInformer coreinformers.ServiceInformer
|
||||||
virtualserviceInformer networkingv1alpha3informer.VirtualServiceInformer
|
vServiceInformer networkingv1beta1informer.VirtualServiceInformer
|
||||||
gatewayInformer networkingv1alpha3informer.GatewayInformer
|
gatewayInformer networkingv1beta1informer.GatewayInformer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIstioVirtualServiceSource creates a new virtualServiceSource with the given config.
|
// NewIstioVirtualServiceSource creates a new virtualServiceSource with the given config.
|
||||||
@ -83,11 +84,11 @@ func NewIstioVirtualServiceSource(
|
|||||||
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
|
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
|
||||||
serviceInformer := informerFactory.Core().V1().Services()
|
serviceInformer := informerFactory.Core().V1().Services()
|
||||||
istioInformerFactory := istioinformers.NewSharedInformerFactoryWithOptions(istioClient, 0, istioinformers.WithNamespace(namespace))
|
istioInformerFactory := istioinformers.NewSharedInformerFactoryWithOptions(istioClient, 0, istioinformers.WithNamespace(namespace))
|
||||||
virtualServiceInformer := istioInformerFactory.Networking().V1alpha3().VirtualServices()
|
virtualServiceInformer := istioInformerFactory.Networking().V1beta1().VirtualServices()
|
||||||
gatewayInformer := istioInformerFactory.Networking().V1alpha3().Gateways()
|
gatewayInformer := istioInformerFactory.Networking().V1beta1().Gateways()
|
||||||
|
|
||||||
// Add default resource event handlers to properly initialize informer.
|
// Add default resource event handlers to properly initialize informer.
|
||||||
serviceInformer.Informer().AddEventHandler(
|
_, _ = serviceInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
log.Debug("service added")
|
log.Debug("service added")
|
||||||
@ -95,7 +96,7 @@ func NewIstioVirtualServiceSource(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
virtualServiceInformer.Informer().AddEventHandler(
|
_, _ = virtualServiceInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
log.Debug("virtual service added")
|
log.Debug("virtual service added")
|
||||||
@ -103,7 +104,7 @@ func NewIstioVirtualServiceSource(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
gatewayInformer.Informer().AddEventHandler(
|
_, _ = gatewayInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
log.Debug("gateway added")
|
log.Debug("gateway added")
|
||||||
@ -131,7 +132,7 @@ func NewIstioVirtualServiceSource(
|
|||||||
combineFQDNAnnotation: combineFQDNAnnotation,
|
combineFQDNAnnotation: combineFQDNAnnotation,
|
||||||
ignoreHostnameAnnotation: ignoreHostnameAnnotation,
|
ignoreHostnameAnnotation: ignoreHostnameAnnotation,
|
||||||
serviceInformer: serviceInformer,
|
serviceInformer: serviceInformer,
|
||||||
virtualserviceInformer: virtualServiceInformer,
|
vServiceInformer: virtualServiceInformer,
|
||||||
gatewayInformer: gatewayInformer,
|
gatewayInformer: gatewayInformer,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ func NewIstioVirtualServiceSource(
|
|||||||
// Endpoints returns endpoint objects for each host-target combination that should be processed.
|
// Endpoints returns endpoint objects for each host-target combination that should be processed.
|
||||||
// Retrieves all VirtualService resources in the source's namespace(s).
|
// Retrieves all VirtualService resources in the source's namespace(s).
|
||||||
func (sc *virtualServiceSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
func (sc *virtualServiceSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
||||||
virtualServices, err := sc.virtualserviceInformer.Lister().VirtualServices(sc.namespace).List(labels.Everything())
|
virtualServices, err := sc.vServiceInformer.Lister().VirtualServices(sc.namespace).List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -150,23 +151,25 @@ func (sc *virtualServiceSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
|
|||||||
|
|
||||||
var endpoints []*endpoint.Endpoint
|
var endpoints []*endpoint.Endpoint
|
||||||
|
|
||||||
for _, virtualService := range virtualServices {
|
log.Debugf("Found %d virtualservice in namespace %s", len(virtualServices), sc.namespace)
|
||||||
|
|
||||||
|
for _, vService := range virtualServices {
|
||||||
// Check controller annotation to see if we are responsible.
|
// Check controller annotation to see if we are responsible.
|
||||||
controller, ok := virtualService.Annotations[controllerAnnotationKey]
|
controller, ok := vService.Annotations[controllerAnnotationKey]
|
||||||
if ok && controller != controllerAnnotationValue {
|
if ok && controller != controllerAnnotationValue {
|
||||||
log.Debugf("Skipping VirtualService %s/%s because controller value does not match, found: %s, required: %s",
|
log.Debugf("Skipping VirtualService %s/%s.%s because controller value does not match, found: %s, required: %s",
|
||||||
virtualService.Namespace, virtualService.Name, controller, controllerAnnotationValue)
|
vService.Namespace, vService.APIVersion, vService.Name, controller, controllerAnnotationValue)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
gwEndpoints, err := sc.endpointsFromVirtualService(ctx, virtualService)
|
gwEndpoints, err := sc.endpointsFromVirtualService(ctx, vService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply template if host is missing on VirtualService
|
// apply template if host is missing on VirtualService
|
||||||
if (sc.combineFQDNAnnotation || len(gwEndpoints) == 0) && sc.fqdnTemplate != nil {
|
if (sc.combineFQDNAnnotation || len(gwEndpoints) == 0) && sc.fqdnTemplate != nil {
|
||||||
iEndpoints, err := sc.endpointsFromTemplate(ctx, virtualService)
|
iEndpoints, err := sc.endpointsFromTemplate(ctx, vService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -179,14 +182,15 @@ func (sc *virtualServiceSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(gwEndpoints) == 0 {
|
if len(gwEndpoints) == 0 {
|
||||||
log.Debugf("No endpoints could be generated from VirtualService %s/%s", virtualService.Namespace, virtualService.Name)
|
log.Debugf("No endpoints could be generated from VirtualService %s/%s", vService.Namespace, vService.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Endpoints generated from VirtualService: %s/%s: %v", virtualService.Namespace, virtualService.Name, gwEndpoints)
|
log.Debugf("Endpoints generated from %q '%s/%s.%s': %q", vService.Kind, vService.Namespace, vService.APIVersion, vService.Name, gwEndpoints)
|
||||||
endpoints = append(endpoints, gwEndpoints...)
|
endpoints = append(endpoints, gwEndpoints...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: sort on endpoint creation
|
||||||
for _, ep := range endpoints {
|
for _, ep := range endpoints {
|
||||||
sort.Sort(ep.Targets)
|
sort.Sort(ep.Targets)
|
||||||
}
|
}
|
||||||
@ -198,16 +202,16 @@ func (sc *virtualServiceSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
|
|||||||
func (sc *virtualServiceSource) AddEventHandler(_ context.Context, handler func()) {
|
func (sc *virtualServiceSource) AddEventHandler(_ context.Context, handler func()) {
|
||||||
log.Debug("Adding event handler for Istio VirtualService")
|
log.Debug("Adding event handler for Istio VirtualService")
|
||||||
|
|
||||||
sc.virtualserviceInformer.Informer().AddEventHandler(eventHandlerFunc(handler))
|
_, _ = sc.vServiceInformer.Informer().AddEventHandler(eventHandlerFunc(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *virtualServiceSource) getGateway(_ context.Context, gatewayStr string, virtualService *networkingv1alpha3.VirtualService) (*networkingv1alpha3.Gateway, error) {
|
func (sc *virtualServiceSource) getGateway(_ context.Context, gatewayStr string, virtualService *v1beta1.VirtualService) (*v1beta1.Gateway, error) {
|
||||||
if gatewayStr == "" || gatewayStr == IstioMeshGateway {
|
if gatewayStr == "" || gatewayStr == IstioMeshGateway {
|
||||||
// This refers to "all sidecars in the mesh"; ignore.
|
// This refers to "all sidecars in the mesh"; ignore.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace, name, err := parseGateway(gatewayStr)
|
namespace, name, err := ParseIngress(gatewayStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Failed parsing gatewayStr %s of VirtualService %s/%s", gatewayStr, virtualService.Namespace, virtualService.Name)
|
log.Debugf("Failed parsing gatewayStr %s of VirtualService %s/%s", gatewayStr, virtualService.Namespace, virtualService.Name)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -229,7 +233,7 @@ func (sc *virtualServiceSource) getGateway(_ context.Context, gatewayStr string,
|
|||||||
return gateway, nil
|
return gateway, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *virtualServiceSource) endpointsFromTemplate(ctx context.Context, virtualService *networkingv1alpha3.VirtualService) ([]*endpoint.Endpoint, error) {
|
func (sc *virtualServiceSource) endpointsFromTemplate(ctx context.Context, virtualService *v1beta1.VirtualService) ([]*endpoint.Endpoint, error) {
|
||||||
hostnames, err := fqdn.ExecTemplate(sc.fqdnTemplate, virtualService)
|
hostnames, err := fqdn.ExecTemplate(sc.fqdnTemplate, virtualService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -253,7 +257,7 @@ func (sc *virtualServiceSource) endpointsFromTemplate(ctx context.Context, virtu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filterByAnnotations filters a list of configs by a given annotation selector.
|
// filterByAnnotations filters a list of configs by a given annotation selector.
|
||||||
func (sc *virtualServiceSource) filterByAnnotations(virtualservices []*networkingv1alpha3.VirtualService) ([]*networkingv1alpha3.VirtualService, error) {
|
func (sc *virtualServiceSource) filterByAnnotations(vServices []*v1beta1.VirtualService) ([]*v1beta1.VirtualService, error) {
|
||||||
selector, err := annotations.ParseFilter(sc.annotationFilter)
|
selector, err := annotations.ParseFilter(sc.annotationFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -261,12 +265,12 @@ func (sc *virtualServiceSource) filterByAnnotations(virtualservices []*networkin
|
|||||||
|
|
||||||
// empty filter returns original list
|
// empty filter returns original list
|
||||||
if selector.Empty() {
|
if selector.Empty() {
|
||||||
return virtualservices, nil
|
return vServices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredList []*networkingv1alpha3.VirtualService
|
var filteredList []*v1beta1.VirtualService
|
||||||
|
|
||||||
for _, vs := range virtualservices {
|
for _, vs := range vServices {
|
||||||
// include if the annotations match the selector
|
// include if the annotations match the selector
|
||||||
if selector.Matches(labels.Set(vs.Annotations)) {
|
if selector.Matches(labels.Set(vs.Annotations)) {
|
||||||
filteredList = append(filteredList, vs)
|
filteredList = append(filteredList, vs)
|
||||||
@ -278,26 +282,24 @@ func (sc *virtualServiceSource) filterByAnnotations(virtualservices []*networkin
|
|||||||
|
|
||||||
// append a target to the list of targets unless it's already in the list
|
// append a target to the list of targets unless it's already in the list
|
||||||
func appendUnique(targets []string, target string) []string {
|
func appendUnique(targets []string, target string) []string {
|
||||||
for _, element := range targets {
|
if slices.Contains(targets, target) {
|
||||||
if element == target {
|
return targets
|
||||||
return targets
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return append(targets, target)
|
return append(targets, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, virtualService *networkingv1alpha3.VirtualService, vsHost string) ([]string, error) {
|
func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, vService *v1beta1.VirtualService, vsHost string) ([]string, error) {
|
||||||
var targets []string
|
var targets []string
|
||||||
// for each host we need to iterate through the gateways because each host might match for only one of the gateways
|
// for each host we need to iterate through the gateways because each host might match for only one of the gateways
|
||||||
for _, gateway := range virtualService.Spec.Gateways {
|
for _, gateway := range vService.Spec.Gateways {
|
||||||
gw, err := sc.getGateway(ctx, gateway, virtualService)
|
gw, err := sc.getGateway(ctx, gateway, vService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if gw == nil {
|
if gw == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !virtualServiceBindsToGateway(virtualService, gw, vsHost) {
|
if !virtualServiceBindsToGateway(vService, gw, vsHost) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tgs, err := sc.targetsFromGateway(ctx, gw)
|
tgs, err := sc.targetsFromGateway(ctx, gw)
|
||||||
@ -308,24 +310,23 @@ func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, v
|
|||||||
targets = appendUnique(targets, target)
|
targets = appendUnique(targets, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return targets, nil
|
return targets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// endpointsFromVirtualService extracts the endpoints from an Istio VirtualService Config object
|
// endpointsFromVirtualService extracts the endpoints from an Istio VirtualService Config object
|
||||||
func (sc *virtualServiceSource) endpointsFromVirtualService(ctx context.Context, virtualservice *networkingv1alpha3.VirtualService) ([]*endpoint.Endpoint, error) {
|
func (sc *virtualServiceSource) endpointsFromVirtualService(ctx context.Context, vService *v1beta1.VirtualService) ([]*endpoint.Endpoint, error) {
|
||||||
var endpoints []*endpoint.Endpoint
|
var endpoints []*endpoint.Endpoint
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
resource := fmt.Sprintf("virtualservice/%s/%s", virtualservice.Namespace, virtualservice.Name)
|
resource := fmt.Sprintf("virtualservice/%s/%s", vService.Namespace, vService.Name)
|
||||||
|
|
||||||
ttl := annotations.TTLFromAnnotations(virtualservice.Annotations, resource)
|
ttl := annotations.TTLFromAnnotations(vService.Annotations, resource)
|
||||||
|
|
||||||
targetsFromAnnotation := annotations.TargetsFromTargetAnnotation(virtualservice.Annotations)
|
targetsFromAnnotation := annotations.TargetsFromTargetAnnotation(vService.Annotations)
|
||||||
|
|
||||||
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(virtualservice.Annotations)
|
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(vService.Annotations)
|
||||||
|
|
||||||
for _, host := range virtualservice.Spec.Hosts {
|
for _, host := range vService.Spec.Hosts {
|
||||||
if host == "" || host == "*" {
|
if host == "" || host == "*" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -340,7 +341,7 @@ func (sc *virtualServiceSource) endpointsFromVirtualService(ctx context.Context,
|
|||||||
|
|
||||||
targets := targetsFromAnnotation
|
targets := targetsFromAnnotation
|
||||||
if len(targets) == 0 {
|
if len(targets) == 0 {
|
||||||
targets, err = sc.targetsFromVirtualService(ctx, virtualservice, host)
|
targets, err = sc.targetsFromVirtualService(ctx, vService, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return endpoints, err
|
return endpoints, err
|
||||||
}
|
}
|
||||||
@ -351,11 +352,11 @@ func (sc *virtualServiceSource) endpointsFromVirtualService(ctx context.Context,
|
|||||||
|
|
||||||
// Skip endpoints if we do not want entries from annotations
|
// Skip endpoints if we do not want entries from annotations
|
||||||
if !sc.ignoreHostnameAnnotation {
|
if !sc.ignoreHostnameAnnotation {
|
||||||
hostnameList := annotations.HostnamesFromAnnotations(virtualservice.Annotations)
|
hostnameList := annotations.HostnamesFromAnnotations(vService.Annotations)
|
||||||
for _, hostname := range hostnameList {
|
for _, hostname := range hostnameList {
|
||||||
targets := targetsFromAnnotation
|
targets := targetsFromAnnotation
|
||||||
if len(targets) == 0 {
|
if len(targets) == 0 {
|
||||||
targets, err = sc.targetsFromVirtualService(ctx, virtualservice, hostname)
|
targets, err = sc.targetsFromVirtualService(ctx, vService, hostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return endpoints, err
|
return endpoints, err
|
||||||
}
|
}
|
||||||
@ -369,13 +370,13 @@ func (sc *virtualServiceSource) endpointsFromVirtualService(ctx context.Context,
|
|||||||
|
|
||||||
// checks if the given VirtualService should actually bind to the given gateway
|
// checks if the given VirtualService should actually bind to the given gateway
|
||||||
// see requirements here: https://istio.io/docs/reference/config/networking/gateway/#Server
|
// see requirements here: https://istio.io/docs/reference/config/networking/gateway/#Server
|
||||||
func virtualServiceBindsToGateway(virtualService *networkingv1alpha3.VirtualService, gateway *networkingv1alpha3.Gateway, vsHost string) bool {
|
func virtualServiceBindsToGateway(vService *v1beta1.VirtualService, gateway *v1beta1.Gateway, vsHost string) bool {
|
||||||
isValid := false
|
isValid := false
|
||||||
if len(virtualService.Spec.ExportTo) == 0 {
|
if len(vService.Spec.ExportTo) == 0 {
|
||||||
isValid = true
|
isValid = true
|
||||||
} else {
|
} else {
|
||||||
for _, ns := range virtualService.Spec.ExportTo {
|
for _, ns := range vService.Spec.ExportTo {
|
||||||
if ns == "*" || ns == gateway.Namespace || (ns == "." && gateway.Namespace == virtualService.Namespace) {
|
if ns == "*" || ns == gateway.Namespace || (ns == "." && gateway.Namespace == vService.Namespace) {
|
||||||
isValid = true
|
isValid = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +397,7 @@ func virtualServiceBindsToGateway(virtualService *networkingv1alpha3.VirtualServ
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if namespace == "*" || namespace == virtualService.Namespace || (namespace == "." && virtualService.Namespace == gateway.Namespace) {
|
if namespace == "*" || namespace == vService.Namespace || (namespace == "." && vService.Namespace == gateway.Namespace) {
|
||||||
if host == "*" {
|
if host == "*" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -416,23 +417,7 @@ func virtualServiceBindsToGateway(virtualService *networkingv1alpha3.VirtualServ
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: similar to ParseIngress
|
func (sc *virtualServiceSource) targetsFromIngress(ctx context.Context, ingressStr string, gateway *v1beta1.Gateway) (endpoint.Targets, error) {
|
||||||
func parseGateway(gateway string) (string, string, error) {
|
|
||||||
var namespace, name string
|
|
||||||
var err error
|
|
||||||
parts := strings.Split(gateway, "/")
|
|
||||||
if len(parts) == 2 {
|
|
||||||
namespace, name = parts[0], parts[1]
|
|
||||||
} else if len(parts) == 1 {
|
|
||||||
name = parts[0]
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("invalid gateway name (name or namespace/name) found '%v'", gateway)
|
|
||||||
}
|
|
||||||
|
|
||||||
return namespace, name, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sc *virtualServiceSource) targetsFromIngress(ctx context.Context, ingressStr string, gateway *networkingv1alpha3.Gateway) (endpoint.Targets, error) {
|
|
||||||
namespace, name, err := ParseIngress(ingressStr)
|
namespace, name, err := ParseIngress(ingressStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse Ingress annotation on Gateway (%s/%s): %w", gateway.Namespace, gateway.Name, err)
|
return nil, fmt.Errorf("failed to parse Ingress annotation on Gateway (%s/%s): %w", gateway.Namespace, gateway.Name, err)
|
||||||
@ -459,7 +444,7 @@ func (sc *virtualServiceSource) targetsFromIngress(ctx context.Context, ingressS
|
|||||||
return targets, nil
|
return targets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *virtualServiceSource) targetsFromGateway(ctx context.Context, gateway *networkingv1alpha3.Gateway) (endpoint.Targets, error) {
|
func (sc *virtualServiceSource) targetsFromGateway(ctx context.Context, gateway *v1beta1.Gateway) (endpoint.Targets, error) {
|
||||||
targets := annotations.TargetsFromTargetAnnotation(gateway.Annotations)
|
targets := annotations.TargetsFromTargetAnnotation(gateway.Annotations)
|
||||||
if len(targets) > 0 {
|
if len(targets) > 0 {
|
||||||
return targets, nil
|
return targets, nil
|
||||||
|
@ -25,8 +25,8 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"istio.io/api/meta/v1alpha1"
|
"istio.io/api/meta/v1alpha1"
|
||||||
istionetworking "istio.io/api/networking/v1alpha3"
|
istionetworking "istio.io/api/networking/v1beta1"
|
||||||
networkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
|
networkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
||||||
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
|
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
networkv1 "k8s.io/api/networking/v1"
|
networkv1 "k8s.io/api/networking/v1"
|
||||||
@ -44,8 +44,8 @@ type VirtualServiceSuite struct {
|
|||||||
source Source
|
source Source
|
||||||
lbServices []*v1.Service
|
lbServices []*v1.Service
|
||||||
ingresses []*networkv1.Ingress
|
ingresses []*networkv1.Ingress
|
||||||
gwconfig *networkingv1alpha3.Gateway
|
gwconfig *networkingv1beta1.Gateway
|
||||||
vsconfig *networkingv1alpha3.VirtualService
|
vsconfig *networkingv1beta1.VirtualService
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *VirtualServiceSuite) SetupTest() {
|
func (suite *VirtualServiceSuite) SetupTest() {
|
||||||
@ -98,7 +98,7 @@ func (suite *VirtualServiceSuite) SetupTest() {
|
|||||||
namespace: "istio-system",
|
namespace: "istio-system",
|
||||||
dnsnames: [][]string{{"*"}},
|
dnsnames: [][]string{{"*"}},
|
||||||
}).Config()
|
}).Config()
|
||||||
_, err = fakeIstioClient.NetworkingV1alpha3().Gateways(suite.gwconfig.Namespace).Create(context.Background(), suite.gwconfig, metav1.CreateOptions{})
|
_, err = fakeIstioClient.NetworkingV1beta1().Gateways(suite.gwconfig.Namespace).Create(context.Background(), suite.gwconfig, metav1.CreateOptions{})
|
||||||
suite.NoError(err, "should succeed")
|
suite.NoError(err, "should succeed")
|
||||||
|
|
||||||
suite.vsconfig = (fakeVirtualServiceConfig{
|
suite.vsconfig = (fakeVirtualServiceConfig{
|
||||||
@ -107,7 +107,7 @@ func (suite *VirtualServiceSuite) SetupTest() {
|
|||||||
gateways: []string{"istio-system/foo-gateway-with-targets"},
|
gateways: []string{"istio-system/foo-gateway-with-targets"},
|
||||||
dnsnames: []string{"foo"},
|
dnsnames: []string{"foo"},
|
||||||
}).Config()
|
}).Config()
|
||||||
_, err = fakeIstioClient.NetworkingV1alpha3().VirtualServices(suite.vsconfig.Namespace).Create(context.Background(), suite.vsconfig, metav1.CreateOptions{})
|
_, err = fakeIstioClient.NetworkingV1beta1().VirtualServices(suite.vsconfig.Namespace).Create(context.Background(), suite.vsconfig, metav1.CreateOptions{})
|
||||||
suite.NoError(err, "should succeed")
|
suite.NoError(err, "should succeed")
|
||||||
|
|
||||||
suite.source, err = NewIstioVirtualServiceSource(
|
suite.source, err = NewIstioVirtualServiceSource(
|
||||||
@ -1948,8 +1948,8 @@ func testVirtualServiceEndpoints(t *testing.T) {
|
|||||||
t.Run(ti.title, func(t *testing.T) {
|
t.Run(ti.title, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
var gateways []*networkingv1alpha3.Gateway
|
var gateways []*networkingv1beta1.Gateway
|
||||||
var virtualservices []*networkingv1alpha3.VirtualService
|
var virtualservices []*networkingv1beta1.VirtualService
|
||||||
|
|
||||||
for _, gwItem := range ti.gwConfigs {
|
for _, gwItem := range ti.gwConfigs {
|
||||||
gateways = append(gateways, gwItem.Config())
|
gateways = append(gateways, gwItem.Config())
|
||||||
@ -1958,7 +1958,7 @@ func testVirtualServiceEndpoints(t *testing.T) {
|
|||||||
virtualservices = append(virtualservices, vsItem.Config())
|
virtualservices = append(virtualservices, vsItem.Config())
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeKubernetesClient := fake.NewSimpleClientset()
|
fakeKubernetesClient := fake.NewClientset()
|
||||||
|
|
||||||
for _, lb := range ti.lbServices {
|
for _, lb := range ti.lbServices {
|
||||||
service := lb.Service()
|
service := lb.Service()
|
||||||
@ -1975,12 +1975,12 @@ func testVirtualServiceEndpoints(t *testing.T) {
|
|||||||
fakeIstioClient := istiofake.NewSimpleClientset()
|
fakeIstioClient := istiofake.NewSimpleClientset()
|
||||||
|
|
||||||
for _, gateway := range gateways {
|
for _, gateway := range gateways {
|
||||||
_, err := fakeIstioClient.NetworkingV1alpha3().Gateways(gateway.Namespace).Create(context.Background(), gateway, metav1.CreateOptions{})
|
_, err := fakeIstioClient.NetworkingV1beta1().Gateways(gateway.Namespace).Create(context.Background(), gateway, metav1.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, virtualservice := range virtualservices {
|
for _, vService := range virtualservices {
|
||||||
_, err := fakeIstioClient.NetworkingV1alpha3().VirtualServices(virtualservice.Namespace).Create(context.Background(), virtualservice, metav1.CreateOptions{})
|
_, err := fakeIstioClient.NetworkingV1beta1().VirtualServices(vService.Namespace).Create(context.Background(), vService, metav1.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2041,7 +2041,7 @@ func testGatewaySelectorMatchesService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTestVirtualServiceSource(loadBalancerList []fakeIngressGatewayService, ingressList []fakeIngress, gwList []fakeGatewayConfig) (*virtualServiceSource, error) {
|
func newTestVirtualServiceSource(loadBalancerList []fakeIngressGatewayService, ingressList []fakeIngress, gwList []fakeGatewayConfig) (*virtualServiceSource, error) {
|
||||||
fakeKubernetesClient := fake.NewSimpleClientset()
|
fakeKubernetesClient := fake.NewClientset()
|
||||||
fakeIstioClient := istiofake.NewSimpleClientset()
|
fakeIstioClient := istiofake.NewSimpleClientset()
|
||||||
|
|
||||||
for _, lb := range loadBalancerList {
|
for _, lb := range loadBalancerList {
|
||||||
@ -2064,7 +2064,7 @@ func newTestVirtualServiceSource(loadBalancerList []fakeIngressGatewayService, i
|
|||||||
gwObj := gw.Config()
|
gwObj := gw.Config()
|
||||||
// use create instead of add
|
// use create instead of add
|
||||||
// https://github.com/kubernetes/client-go/blob/92512ee2b8cf6696e9909245624175b7f0c971d9/testing/fixture.go#LL336C3-L336C52
|
// https://github.com/kubernetes/client-go/blob/92512ee2b8cf6696e9909245624175b7f0c971d9/testing/fixture.go#LL336C3-L336C52
|
||||||
_, err := fakeIstioClient.NetworkingV1alpha3().Gateways(gw.namespace).Create(context.Background(), gwObj, metav1.CreateOptions{})
|
_, err := fakeIstioClient.NetworkingV1beta1().Gateways(gw.namespace).Create(context.Background(), gwObj, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -2101,7 +2101,7 @@ type fakeVirtualServiceConfig struct {
|
|||||||
exportTo string
|
exportTo string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c fakeVirtualServiceConfig) Config() *networkingv1alpha3.VirtualService {
|
func (c fakeVirtualServiceConfig) Config() *networkingv1beta1.VirtualService {
|
||||||
vs := istionetworking.VirtualService{
|
vs := istionetworking.VirtualService{
|
||||||
Gateways: c.gateways,
|
Gateways: c.gateways,
|
||||||
Hosts: c.dnsnames,
|
Hosts: c.dnsnames,
|
||||||
@ -2110,7 +2110,7 @@ func (c fakeVirtualServiceConfig) Config() *networkingv1alpha3.VirtualService {
|
|||||||
vs.ExportTo = []string{c.exportTo}
|
vs.ExportTo = []string{c.exportTo}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &networkingv1alpha3.VirtualService{
|
return &networkingv1beta1.VirtualService{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: c.name,
|
Name: c.name,
|
||||||
Namespace: c.namespace,
|
Namespace: c.namespace,
|
||||||
@ -2127,13 +2127,13 @@ func TestVirtualServiceSourceGetGateway(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
gatewayStr string
|
gatewayStr string
|
||||||
virtualService *networkingv1alpha3.VirtualService
|
virtualService *networkingv1beta1.VirtualService
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fields fields
|
fields fields
|
||||||
args args
|
args args
|
||||||
want *networkingv1alpha3.Gateway
|
want *networkingv1beta1.Gateway
|
||||||
expectedErrStr string
|
expectedErrStr string
|
||||||
}{
|
}{
|
||||||
{name: "EmptyGateway", fields: fields{
|
{name: "EmptyGateway", fields: fields{
|
||||||
@ -2155,7 +2155,7 @@ func TestVirtualServiceSourceGetGateway(t *testing.T) {
|
|||||||
}, args: args{
|
}, args: args{
|
||||||
ctx: context.TODO(),
|
ctx: context.TODO(),
|
||||||
gatewayStr: "doesnt/exist",
|
gatewayStr: "doesnt/exist",
|
||||||
virtualService: &networkingv1alpha3.VirtualService{
|
virtualService: &networkingv1beta1.VirtualService{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "exist", Namespace: "doesnt"},
|
ObjectMeta: metav1.ObjectMeta{Name: "exist", Namespace: "doesnt"},
|
||||||
Spec: istionetworking.VirtualService{},
|
Spec: istionetworking.VirtualService{},
|
||||||
@ -2167,8 +2167,8 @@ func TestVirtualServiceSourceGetGateway(t *testing.T) {
|
|||||||
}, args: args{
|
}, args: args{
|
||||||
ctx: context.TODO(),
|
ctx: context.TODO(),
|
||||||
gatewayStr: "1/2/3/",
|
gatewayStr: "1/2/3/",
|
||||||
virtualService: &networkingv1alpha3.VirtualService{},
|
virtualService: &networkingv1beta1.VirtualService{},
|
||||||
}, want: nil, expectedErrStr: "invalid gateway name (name or namespace/name) found '1/2/3/'"},
|
}, want: nil, expectedErrStr: "invalid ingress name (name or namespace/name) found \"1/2/3/\""},
|
||||||
{name: "ExistingGateway", fields: fields{
|
{name: "ExistingGateway", fields: fields{
|
||||||
virtualServiceSource: func() *virtualServiceSource {
|
virtualServiceSource: func() *virtualServiceSource {
|
||||||
vs, _ := newTestVirtualServiceSource(nil, nil, []fakeGatewayConfig{{
|
vs, _ := newTestVirtualServiceSource(nil, nil, []fakeGatewayConfig{{
|
||||||
@ -2180,13 +2180,13 @@ func TestVirtualServiceSourceGetGateway(t *testing.T) {
|
|||||||
}, args: args{
|
}, args: args{
|
||||||
ctx: context.TODO(),
|
ctx: context.TODO(),
|
||||||
gatewayStr: "bar/foo",
|
gatewayStr: "bar/foo",
|
||||||
virtualService: &networkingv1alpha3.VirtualService{
|
virtualService: &networkingv1beta1.VirtualService{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||||
Spec: istionetworking.VirtualService{},
|
Spec: istionetworking.VirtualService{},
|
||||||
Status: v1alpha1.IstioStatus{},
|
Status: v1alpha1.IstioStatus{},
|
||||||
},
|
},
|
||||||
}, want: &networkingv1alpha3.Gateway{
|
}, want: &networkingv1beta1.Gateway{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||||
Spec: istionetworking.Gateway{},
|
Spec: istionetworking.Gateway{},
|
||||||
|
Loading…
Reference in New Issue
Block a user