Skip to content

Commit

Permalink
feat: support multiple GatewayClass per controller (envoyproxy#2298)
Browse files Browse the repository at this point in the history
* reconcile multiple gatewayclasses per controller

Signed-off-by: Karol Szwaj <[email protected]>

* filter gateway-api infra layer by gc label

Signed-off-by: Karol Szwaj <[email protected]>

* wip: modify watchable message for gatewayapi translate

Signed-off-by: Karol Szwaj <[email protected]>

* gen deepcopy for gatewayclassresources

Signed-off-by: Karol Szwaj <[email protected]>

* add comments to deepcopy gen

Signed-off-by: Karol Szwaj <[email protected]>

* fix store order

Signed-off-by: Karol Szwaj <[email protected]>

---------

Signed-off-by: Karol Szwaj <[email protected]>
Co-authored-by: zirain <[email protected]>
  • Loading branch information
cnvergence and zirain authored Feb 17, 2024
1 parent f7df0e2 commit a5125bf
Show file tree
Hide file tree
Showing 10 changed files with 643 additions and 447 deletions.
35 changes: 35 additions & 0 deletions internal/gatewayapi/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,41 @@ import (

type XdsIRMap map[string]*ir.Xds
type InfraIRMap map[string]*ir.Infra
type GatewayClassResources map[string]*Resources

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
// This was generated by controller-gen and moved over from
// zz_generated.deepcopy.go to this file.
func (in GatewayClassResources) DeepCopyInto(out *GatewayClassResources) {
{
in := &in
*out = make(GatewayClassResources, len(*in))
for key, val := range *in {
var outVal *Resources
if val == nil {
(*out)[key] = nil
} else {
inVal := (*in)[key]
in, out := &inVal, &outVal
*out = new(Resources)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayClassResources.
// This was generated by controller-gen and moved over from
// zz_generated.deepcopy.go to this file.
func (in GatewayClassResources) DeepCopy() *GatewayClassResources {
if in == nil {
return nil
}
out := new(GatewayClassResources)
in.DeepCopyInto(out)
return out
}

// Resources holds the Gateway API and related
// resources that the translators needs as inputs.
Expand Down
177 changes: 88 additions & 89 deletions internal/gatewayapi/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,118 +49,117 @@ func (r *Runner) Start(ctx context.Context) (err error) {

func (r *Runner) subscribeAndTranslate(ctx context.Context) {
message.HandleSubscription(message.Metadata{Runner: string(v1alpha1.LogComponentGatewayAPIRunner), Message: "provider-resources"}, r.ProviderResources.GatewayAPIResources.Subscribe(ctx),
func(update message.Update[string, *gatewayapi.Resources], errChan chan error) {
func(update message.Update[string, *gatewayapi.GatewayClassResources], errChan chan error) {
r.Logger.Info("received an update")

val := update.Value

if update.Delete || val == nil {
return
}

// Translate and publish IRs.
t := &gatewayapi.Translator{
GatewayControllerName: r.Server.EnvoyGateway.Gateway.ControllerName,
GatewayClassName: v1.ObjectName(update.Key),
GlobalRateLimitEnabled: r.EnvoyGateway.RateLimit != nil,
EnvoyPatchPolicyEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableEnvoyPatchPolicy,
}

// If an extension is loaded, pass its supported groups/kinds to the translator
if r.EnvoyGateway.ExtensionManager != nil {
var extGKs []schema.GroupKind
for _, gvk := range r.EnvoyGateway.ExtensionManager.Resources {
extGKs = append(extGKs, schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind})
}
t.ExtensionGroupKinds = extGKs
}
// Translate to IR
result := t.Translate(val)

var curKeys, newKeys []string
// Get current IR keys
for key := range r.InfraIR.LoadAll() {
curKeys = append(curKeys, key)
}

// Publish the IRs.
// Also validate the ir before sending it.
for key, val := range result.InfraIR {
r.Logger.WithValues("infra-ir", key).Info(val.YAMLString())
if err := val.Validate(); err != nil {
r.Logger.Error(err, "unable to validate infra ir, skipped sending it")
errChan <- err
} else {
r.InfraIR.Store(key, val)
newKeys = append(newKeys, key)
for gc, resources := range *val {
// Translate and publish IRs.
t := &gatewayapi.Translator{
GatewayControllerName: r.Server.EnvoyGateway.Gateway.ControllerName,
GatewayClassName: v1.ObjectName(gc),
GlobalRateLimitEnabled: r.EnvoyGateway.RateLimit != nil,
EnvoyPatchPolicyEnabled: r.EnvoyGateway.ExtensionAPIs != nil && r.EnvoyGateway.ExtensionAPIs.EnableEnvoyPatchPolicy,
}
}

for key, val := range result.XdsIR {
r.Logger.WithValues("xds-ir", key).Info(val.YAMLString())
if err := val.Validate(); err != nil {
r.Logger.Error(err, "unable to validate xds ir, skipped sending it")
errChan <- err
} else {
r.XdsIR.Store(key, val)
// If an extension is loaded, pass its supported groups/kinds to the translator
if r.EnvoyGateway.ExtensionManager != nil {
var extGKs []schema.GroupKind
for _, gvk := range r.EnvoyGateway.ExtensionManager.Resources {
extGKs = append(extGKs, schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind})
}
t.ExtensionGroupKinds = extGKs
}
// Translate to IR
result := t.Translate(resources)

// Publish the IRs.
// Also validate the ir before sending it.
for key, val := range result.InfraIR {
r.Logger.WithValues("infra-ir", key).Info(val.YAMLString())
if err := val.Validate(); err != nil {
r.Logger.Error(err, "unable to validate infra ir, skipped sending it")
errChan <- err
} else {
r.InfraIR.Store(key, val)
newKeys = append(newKeys, key)
}
}

for key, val := range result.XdsIR {
r.Logger.WithValues("xds-ir", key).Info(val.YAMLString())
if err := val.Validate(); err != nil {
r.Logger.Error(err, "unable to validate xds ir, skipped sending it")
errChan <- err
} else {
r.XdsIR.Store(key, val)
}
}

// Update Status
for _, gateway := range result.Gateways {
gateway := gateway
key := utils.NamespacedName(gateway)
r.ProviderResources.GatewayStatuses.Store(key, &gateway.Status)
}
for _, httpRoute := range result.HTTPRoutes {
httpRoute := httpRoute
key := utils.NamespacedName(httpRoute)
r.ProviderResources.HTTPRouteStatuses.Store(key, &httpRoute.Status)
}
for _, grpcRoute := range result.GRPCRoutes {
grpcRoute := grpcRoute
key := utils.NamespacedName(grpcRoute)
r.ProviderResources.GRPCRouteStatuses.Store(key, &grpcRoute.Status)
}
}

for _, tlsRoute := range result.TLSRoutes {
tlsRoute := tlsRoute
key := utils.NamespacedName(tlsRoute)
r.ProviderResources.TLSRouteStatuses.Store(key, &tlsRoute.Status)
}
for _, tcpRoute := range result.TCPRoutes {
tcpRoute := tcpRoute
key := utils.NamespacedName(tcpRoute)
r.ProviderResources.TCPRouteStatuses.Store(key, &tcpRoute.Status)
}
for _, udpRoute := range result.UDPRoutes {
udpRoute := udpRoute
key := utils.NamespacedName(udpRoute)
r.ProviderResources.UDPRouteStatuses.Store(key, &udpRoute.Status)
}
for _, clientTrafficPolicy := range result.ClientTrafficPolicies {
clientTrafficPolicy := clientTrafficPolicy
key := utils.NamespacedName(clientTrafficPolicy)
r.ProviderResources.ClientTrafficPolicyStatuses.Store(key, &clientTrafficPolicy.Status)
}
for _, backendTrafficPolicy := range result.BackendTrafficPolicies {
backendTrafficPolicy := backendTrafficPolicy
key := utils.NamespacedName(backendTrafficPolicy)
r.ProviderResources.BackendTrafficPolicyStatuses.Store(key, &backendTrafficPolicy.Status)
}
for _, securityPolicy := range result.SecurityPolicies {
securityPolicy := securityPolicy
key := utils.NamespacedName(securityPolicy)
r.ProviderResources.SecurityPolicyStatuses.Store(key, &securityPolicy.Status)
}
}
// Delete keys
// There is a 1:1 mapping between infra and xds IR keys
delKeys := getIRKeysToDelete(curKeys, newKeys)
for _, key := range delKeys {
r.InfraIR.Delete(key)
r.XdsIR.Delete(key)
}

// Update Status
for _, gateway := range result.Gateways {
gateway := gateway
key := utils.NamespacedName(gateway)
r.ProviderResources.GatewayStatuses.Store(key, &gateway.Status)
}
for _, httpRoute := range result.HTTPRoutes {
httpRoute := httpRoute
key := utils.NamespacedName(httpRoute)
r.ProviderResources.HTTPRouteStatuses.Store(key, &httpRoute.Status)
}
for _, grpcRoute := range result.GRPCRoutes {
grpcRoute := grpcRoute
key := utils.NamespacedName(grpcRoute)
r.ProviderResources.GRPCRouteStatuses.Store(key, &grpcRoute.Status)
}

for _, tlsRoute := range result.TLSRoutes {
tlsRoute := tlsRoute
key := utils.NamespacedName(tlsRoute)
r.ProviderResources.TLSRouteStatuses.Store(key, &tlsRoute.Status)
}
for _, tcpRoute := range result.TCPRoutes {
tcpRoute := tcpRoute
key := utils.NamespacedName(tcpRoute)
r.ProviderResources.TCPRouteStatuses.Store(key, &tcpRoute.Status)
}
for _, udpRoute := range result.UDPRoutes {
udpRoute := udpRoute
key := utils.NamespacedName(udpRoute)
r.ProviderResources.UDPRouteStatuses.Store(key, &udpRoute.Status)
}
for _, clientTrafficPolicy := range result.ClientTrafficPolicies {
clientTrafficPolicy := clientTrafficPolicy
key := utils.NamespacedName(clientTrafficPolicy)
r.ProviderResources.ClientTrafficPolicyStatuses.Store(key, &clientTrafficPolicy.Status)
}
for _, backendTrafficPolicy := range result.BackendTrafficPolicies {
backendTrafficPolicy := backendTrafficPolicy
key := utils.NamespacedName(backendTrafficPolicy)
r.ProviderResources.BackendTrafficPolicyStatuses.Store(key, &backendTrafficPolicy.Status)
}
for _, securityPolicy := range result.SecurityPolicies {
securityPolicy := securityPolicy
key := utils.NamespacedName(securityPolicy)
r.ProviderResources.SecurityPolicyStatuses.Store(key, &securityPolicy.Status)
}
},
)
r.Logger.Info("shutting down")
Expand Down
4 changes: 2 additions & 2 deletions internal/message/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
type ProviderResources struct {
// GatewayAPIResources is a map from a GatewayClass name to
// a group of gateway API and other related resources.
GatewayAPIResources watchable.Map[string, *gatewayapi.Resources]
GatewayAPIResources watchable.Map[string, *gatewayapi.GatewayClassResources]

// GatewayAPIStatuses is a group of gateway api
// resource statuses maps.
Expand All @@ -31,7 +31,7 @@ type ProviderResources struct {
PolicyStatuses
}

func (p *ProviderResources) GetResources() *gatewayapi.Resources {
func (p *ProviderResources) GetResources() *gatewayapi.GatewayClassResources {
if p.GatewayAPIResources.Len() == 0 {
return nil
}
Expand Down
Loading

0 comments on commit a5125bf

Please sign in to comment.