Skip to content

Commit

Permalink
feat: Gateway filtering based on labels (knative-extensions#1248)
Browse files Browse the repository at this point in the history
  • Loading branch information
pastequo committed Feb 8, 2024
1 parent 708e6d3 commit 4985d97
Show file tree
Hide file tree
Showing 12 changed files with 982 additions and 120 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ require (
go.uber.org/zap v1.26.0
golang.org/x/sync v0.6.0
google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v3 v3.0.1
istio.io/api v1.20.2
istio.io/client-go v1.20.2
k8s.io/api v0.28.5
Expand All @@ -16,6 +15,7 @@ require (
knative.dev/hack v0.0.0-20240123160146-ab9b69024c39
knative.dev/networking v0.0.0-20240130141901-060ef7acae5d
knative.dev/pkg v0.0.0-20240129160226-b6659cc45066
sigs.k8s.io/yaml v1.4.0
)

require (
Expand Down Expand Up @@ -84,6 +84,7 @@ require (
google.golang.org/grpc v1.61.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.28.5 // indirect
k8s.io/code-generator v0.28.5 // indirect
k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 // indirect
Expand All @@ -92,5 +93,4 @@ require (
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
32 changes: 26 additions & 6 deletions pkg/reconciler/ingress/config/istio.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ import (
"sort"
"strings"

"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation"
"knative.dev/pkg/network"
"knative.dev/pkg/system"
"sigs.k8s.io/yaml"
)

const (
Expand Down Expand Up @@ -76,9 +77,10 @@ func defaultLocalGateways() []Gateway {

// Gateway specifies the name of the Gateway and the K8s Service backing it.
type Gateway struct {
Namespace string
Name string
ServiceURL string `yaml:"service"`
Namespace string
Name string
ServiceURL string `json:"service"`
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
}

// QualifiedName returns gateway name in '{namespace}/{name}' format.
Expand Down Expand Up @@ -109,10 +111,10 @@ func (g Gateway) Validate() error {
// Istio contains istio related configuration defined in the
// istio config map.
type Istio struct {
// IngressGateway specifies the gateway urls for public Ingress.
// IngressGateways specifies the gateway urls for public Ingress.
IngressGateways []Gateway

// LocalGateway specifies the gateway urls for public & private Ingress.
// LocalGateways specifies the gateway urls for public & private Ingress.
LocalGateways []Gateway
}

Expand All @@ -127,11 +129,29 @@ func (i Istio) Validate() error {
if err := gtw.Validate(); err != nil {
return fmt.Errorf("invalid local gateway: %w", err)
}

if gtw.LabelSelector != nil {
return fmt.Errorf("invalid local gateway: label selector can't be specified")
}
}

return nil
}

func (i Istio) DefaultGateways() []Gateway {
ret := make([]Gateway, 0)

for _, gtw := range i.IngressGateways {
gateway := gtw

if gtw.LabelSelector == nil {
ret = append(ret, gateway)
}
}

return ret
}

// NewIstioFromConfigMap creates an Istio config from the supplied ConfigMap
func NewIstioFromConfigMap(configMap *corev1.ConfigMap) (*Istio, error) {
ret := &Istio{}
Expand Down
92 changes: 92 additions & 0 deletions pkg/reconciler/ingress/config/istio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,98 @@ func TestGatewayConfiguration(t *testing.T) {
}},
LocalGateways: defaultLocalGateways(),
},
}, {
name: "new format - label selector",
config: &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: system.Namespace(),
Name: IstioConfigName,
},
Data: map[string]string{
"external-gateways": `
- namespace: "namespace"
name: "gateway"
service: "istio-gateway.istio-system.svc.cluster.local"
labelSelector:
matchExpressions:
- key: "key"
operator: "In"
values: ["value"]`,

"local-gateways": `
- namespace: "namespace2"
name: "gateway2"
service: "istio-local-gateway.istio-system.svc.cluster.local"`,
},
},
wantIstio: &Istio{
IngressGateways: []Gateway{{
Namespace: "namespace",
Name: "gateway",
ServiceURL: "istio-gateway.istio-system.svc.cluster.local",
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value"},
},
},
},
}},
LocalGateways: []Gateway{{
Namespace: "namespace2",
Name: "gateway2",
ServiceURL: "istio-local-gateway.istio-system.svc.cluster.local",
}},
},
}, {
name: "several local gateway",
config: &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: system.Namespace(),
Name: IstioConfigName,
},
Data: map[string]string{
"local-gateways": `
- namespace: "namespace1"
name: "gateway1"
service: "istio-local-gateway.istio-system.svc.cluster.local
- namespace: "namespace2"
name: "gateway2"
service: "istio-local-gateway.istio-system.svc.cluster.local"`,
"external-gateways": `
- namespace: "namespace3"
name: "gateway3"
service: "istio-external-gateway.istio-system.svc.cluster.local"`,
},
},
wantErr: true,
}, {
name: "local gateway with selector",
config: &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: system.Namespace(),
Name: IstioConfigName,
},
Data: map[string]string{
"local-gateways": `
- namespace: "namespace"
name: "gateway"
service: "istio-gateway.istio-system.svc.cluster.local"
labelSelector:
matchExpressions:
- key: "key"
operator: "In"
values: ["value"]`,

"external-gateways": `
- namespace: "namespace2"
name: "gateway2"
service: "istio-local-gateway.istio-system.svc.cluster.local"`,
},
},
wantErr: true,
}}

for _, tt := range gatewayConfigTests {
Expand Down
17 changes: 15 additions & 2 deletions pkg/reconciler/ingress/config/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 22 additions & 43 deletions pkg/reconciler/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,13 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
ing.Status.InitializeConditions()
logger.Infof("Reconciling ingress: %#v", ing)

defaultGateways, err := resources.QualifiedGatewayNamesFromContext(ctx, ing)
if err != nil {
return err
}

gatewayNames := map[v1alpha1.IngressVisibility]sets.Set[string]{}
gatewayNames[v1alpha1.IngressVisibilityClusterLocal] = qualifiedGatewayNamesFromContext(ctx)[v1alpha1.IngressVisibilityClusterLocal]
gatewayNames[v1alpha1.IngressVisibilityClusterLocal] = defaultGateways[v1alpha1.IngressVisibilityClusterLocal]
gatewayNames[v1alpha1.IngressVisibilityExternalIP] = sets.New[string]()

externalIngressGateways := []*v1beta1.Gateway{}
Expand All @@ -131,7 +136,7 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
if err != nil {
return err
}
targetWildcardSecrets, err := resources.MakeWildcardSecrets(ctx, wildcardSecrets)
targetWildcardSecrets, err := resources.MakeWildcardSecrets(ctx, wildcardSecrets, ing)
if err != nil {
return err
}
Expand All @@ -154,7 +159,7 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
// same wildcard host. We need to handle wildcard certificate specially because Istio does
// not fully support multiple TLS Servers (or Gateways) share the same certificate.
// https://istio.io/docs/ops/common-problems/network-issues/
desiredWildcardGateways, err := resources.MakeWildcardTLSGateways(ctx, wildcardSecrets, r.svcLister)
desiredWildcardGateways, err := resources.MakeWildcardTLSGateways(ctx, ing, wildcardSecrets, r.svcLister)
if err != nil {
return err
}
Expand Down Expand Up @@ -201,8 +206,7 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
} else {
// Otherwise, we fall back to the default global Gateways for HTTP behavior.
// We need this for the backward compatibility.
defaultGlobalHTTPGateways := qualifiedGatewayNamesFromContext(ctx)[v1alpha1.IngressVisibilityExternalIP]
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(sets.List(defaultGlobalHTTPGateways)...)
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(sets.List(defaultGateways[v1alpha1.IngressVisibilityExternalIP])...)
}

if err := r.reconcileIngressGateways(ctx, externalIngressGateways); err != nil {
Expand Down Expand Up @@ -258,8 +262,18 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
}

if ready {
publicLbs := getLBStatus(publicGatewayServiceURLFromContext(ctx))
privateLbs := getLBStatus(privateGatewayServiceURLFromContext(ctx))
publicGateways, err := resources.PublicGatewayServiceURLFromContext(ctx, ing)
if err != nil {
return fmt.Errorf("failed to get public gateways: %w", err)
}
publicLbs := getLBStatus(publicGateways)

privateGateways, err := resources.PrivateGatewayServiceURLFromContext(ctx, ing)
if err != nil {
return fmt.Errorf("failed to get private gateways: %w", err)
}
privateLbs := getLBStatus(privateGateways)

ing.Status.MarkLoadBalancerReady(publicLbs, privateLbs)
} else {
ing.Status.MarkLoadBalancerNotReady()
Expand Down Expand Up @@ -446,7 +460,7 @@ func (r *Reconciler) cleanupCertificateSecrets(ctx context.Context, ing *v1alpha

errs := []error{}
for _, tls := range ing.Spec.TLS {
nameNamespaces, err := resources.GetIngressGatewaySvcNameNamespaces(ctx)
nameNamespaces, err := resources.GetIngressGatewaySvcNameNamespaces(ctx, ing)
if err != nil {
errs = append(errs, err)
continue
Expand Down Expand Up @@ -518,41 +532,6 @@ func (r *Reconciler) GetDestinationRuleLister() istiolisters.DestinationRuleList
return r.destinationRuleLister
}

// qualifiedGatewayNamesFromContext get gateway names from context
func qualifiedGatewayNamesFromContext(ctx context.Context) map[v1alpha1.IngressVisibility]sets.Set[string] {
ci := config.FromContext(ctx).Istio
publicGateways := sets.New[string]()
for _, gw := range ci.IngressGateways {
publicGateways.Insert(gw.QualifiedName())
}

privateGateways := sets.New[string]()
for _, gw := range ci.LocalGateways {
privateGateways.Insert(gw.QualifiedName())
}

return map[v1alpha1.IngressVisibility]sets.Set[string]{
v1alpha1.IngressVisibilityExternalIP: publicGateways,
v1alpha1.IngressVisibilityClusterLocal: privateGateways,
}
}

func publicGatewayServiceURLFromContext(ctx context.Context) string {
cfg := config.FromContext(ctx).Istio
if len(cfg.IngressGateways) > 0 {
return cfg.IngressGateways[0].ServiceURL
}
return ""
}

func privateGatewayServiceURLFromContext(ctx context.Context) string {
cfg := config.FromContext(ctx).Istio
if len(cfg.LocalGateways) > 0 {
return cfg.LocalGateways[0].ServiceURL
}
return ""
}

// getLBStatus gets the LB Status.
func getLBStatus(gatewayServiceURL string) []v1alpha1.LoadBalancerIngressStatus {
// The Ingress isn't load-balanced by any particular
Expand Down
7 changes: 6 additions & 1 deletion pkg/reconciler/ingress/lister.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
istiolisters "knative.dev/net-istio/pkg/client/istio/listers/networking/v1beta1"
"knative.dev/net-istio/pkg/reconciler/ingress/resources"
"knative.dev/networking/pkg/apis/networking/v1alpha1"
"knative.dev/networking/pkg/ingress"
"knative.dev/networking/pkg/k8s"
Expand Down Expand Up @@ -60,7 +61,11 @@ type gatewayPodTargetLister struct {

func (l *gatewayPodTargetLister) ListProbeTargets(ctx context.Context, ing *v1alpha1.Ingress) ([]status.ProbeTarget, error) {
results := []status.ProbeTarget{}
hostsByGateway := ingress.HostsPerVisibility(ing, qualifiedGatewayNamesFromContext(ctx))
gatewayQualifiedNames, err := resources.QualifiedGatewayNamesFromContext(ctx, ing)
if err != nil {
return nil, fmt.Errorf("failed to get gateways for ingress: %w", err)
}
hostsByGateway := ingress.HostsPerVisibility(ing, gatewayQualifiedNames)
gatewayNames := make([]string, 0, len(hostsByGateway))
for gatewayName := range hostsByGateway {
gatewayNames = append(gatewayNames, gatewayName)
Expand Down
Loading

0 comments on commit 4985d97

Please sign in to comment.