Skip to content

Commit

Permalink
Merge pull request #3788 from nelljerram/oss-gateway-api
Browse files Browse the repository at this point in the history
Add Gateway API to OSS as well as Enterprise
  • Loading branch information
nelljerram authored Feb 28, 2025
2 parents 753ac20 + fcb9651 commit d86f158
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 22 deletions.
6 changes: 6 additions & 0 deletions config/calico_versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ components:
version: master
calico/whisker-backend:
version: master
calico/envoy-gateway:
version: master
calico/envoy-proxy:
version: master
calico/envoy-ratelimit:
version: master
24 changes: 24 additions & 0 deletions hack/gen-versions/calico.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,27 @@ var (
Registry: "{{ .Registry }}",
}
{{- end }}
{{ with index .Components "calico/envoy-gateway"}}
ComponentCalicoEnvoyGateway = Component{
Version: "{{ .Version }}",
Image: "{{ .Image }}",
Registry: "{{ .Registry }}",
}
{{- end }}
{{ with index .Components "calico/envoy-proxy"}}
ComponentCalicoEnvoyProxy = Component{
Version: "{{ .Version }}",
Image: "{{ .Image }}",
Registry: "{{ .Registry }}",
}
{{- end }}
{{ with index .Components "calico/envoy-ratelimit"}}
ComponentCalicoEnvoyRatelimit = Component{
Version: "{{ .Version }}",
Image: "{{ .Image }}",
Registry: "{{ .Registry }}",
}
{{- end }}
{{ with index .Components "calico/guardian" }}
ComponentCalicoGuardian = Component{
Version: "{{ .Version }}",
Expand Down Expand Up @@ -202,5 +223,8 @@ var (
ComponentCalicoGoldmane,
ComponentCalicoWhisker,
ComponentCalicoWhiskerBackend,
ComponentCalicoEnvoyGateway,
ComponentCalicoEnvoyProxy,
ComponentCalicoEnvoyRatelimit,
}
)
21 changes: 21 additions & 0 deletions pkg/components/calico.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ var (
Registry: "",
}

ComponentCalicoEnvoyGateway = Component{
Version: "master",
Image: "calico/envoy-gateway",
Registry: "",
}

ComponentCalicoEnvoyProxy = Component{
Version: "master",
Image: "calico/envoy-proxy",
Registry: "",
}

ComponentCalicoEnvoyRatelimit = Component{
Version: "master",
Image: "calico/envoy-ratelimit",
Registry: "",
}

ComponentOperatorInit = Component{
Version: version.VERSION,
Image: "tigera/operator",
Expand Down Expand Up @@ -175,5 +193,8 @@ var (
ComponentCalicoGoldmane,
ComponentCalicoWhisker,
ComponentCalicoWhiskerBackend,
ComponentCalicoEnvoyGateway,
ComponentCalicoEnvoyProxy,
ComponentCalicoEnvoyRatelimit,
}
)
43 changes: 33 additions & 10 deletions pkg/controller/gatewayapi/gatewayapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"

"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

Expand Down Expand Up @@ -112,17 +111,14 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R
reqLogger.Info("Reconciling GatewayAPI")

// Get the GatewayAPI CR.
gatewayAPI := &operatorv1.GatewayAPI{}
err := r.client.Get(ctx, utils.DefaultTSEEInstanceKey, gatewayAPI)
gatewayAPI, msg, err := GetGatewayAPI(ctx, r.client)
if err != nil {
if apierrors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
if errors.IsNotFound(err) {
reqLogger.Info("GatewayAPI object not found")
r.status.OnCRNotFound()
return reconcile.Result{}, nil
}
r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying for GatewayAPI CR", err, reqLogger)
r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying for GatewayAPI CR: "+msg, err, reqLogger)
return reconcile.Result{}, err
}
r.status.OnCRFound()
Expand All @@ -133,16 +129,16 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R
// Get the Installation, for private registry and pull secret config.
variant, installation, err := utils.GetInstallation(ctx, r.client)
if err != nil {
if apierrors.IsNotFound(err) {
if errors.IsNotFound(err) {
r.status.SetDegraded(operatorv1.ResourceNotFound, "Installation not found", err, reqLogger)
return reconcile.Result{}, nil
}
r.status.SetDegraded(operatorv1.ResourceReadError, "Error querying installation", err, reqLogger)
return reconcile.Result{}, err
}

if variant != operatorv1.TigeraSecureEnterprise {
r.status.SetDegraded(operatorv1.ResourceNotReady, fmt.Sprintf("Waiting for network to be %s", operatorv1.TigeraSecureEnterprise), nil, reqLogger)
if variant == "" {
r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for Installation Variant to be set", nil, reqLogger)
return reconcile.Result{}, nil
}

Expand Down Expand Up @@ -226,3 +222,30 @@ func (r *ReconcileGatewayAPI) Reconcile(ctx context.Context, request reconcile.R
// Update the status of the GatewayAPI instance and StatusManager.
return reconcile.Result{}, nil
}

// GetGatewayAPI finds the correct GatewayAPI resource and returns a message and error in the case of an error.
func GetGatewayAPI(ctx context.Context, client client.Client) (*operatorv1.GatewayAPI, string, error) {
// Fetch the GatewayAPI resource. Look for "default" first.
resource := &operatorv1.GatewayAPI{}
err := client.Get(ctx, utils.DefaultInstanceKey, resource)
if err != nil {
if !errors.IsNotFound(err) {
return nil, "failed to get GatewayAPI 'default'", err
}

// Default resource doesn't exist. Check for the legacy (enterprise only) CR.
err = client.Get(ctx, utils.DefaultTSEEInstanceKey, resource)
if err != nil {
return nil, "failed to get GatewayAPI 'tigera-secure'", err
}
} else {
// Assert there is no legacy "tigera-secure" resource present.
err = client.Get(ctx, utils.DefaultTSEEInstanceKey, resource)
if err == nil {
return nil,
"Duplicate configuration detected",
fmt.Errorf("multiple GatewayAPI CRs provided. To fix, run \"kubectl delete gatewayapi tigera-secure\"")
}
}
return resource, "", nil
}
37 changes: 26 additions & 11 deletions pkg/render/gateway_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,17 +350,32 @@ func (pr *gatewayAPIImplementationComponent) ResolveImages(is *operatorv1.ImageS
prefix := pr.cfg.Installation.ImagePrefix

var err error
pr.envoyGatewayImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyGateway, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyProxyImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyProxy, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyRatelimitImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyRatelimit, reg, path, prefix, is)
if err != nil {
return err
if pr.cfg.Installation.Variant == operatorv1.TigeraSecureEnterprise {
pr.envoyGatewayImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyGateway, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyProxyImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyProxy, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyRatelimitImage, err = components.GetReference(components.ComponentGatewayAPIEnvoyRatelimit, reg, path, prefix, is)
if err != nil {
return err
}
} else {
pr.envoyGatewayImage, err = components.GetReference(components.ComponentCalicoEnvoyGateway, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyProxyImage, err = components.GetReference(components.ComponentCalicoEnvoyProxy, reg, path, prefix, is)
if err != nil {
return err
}
pr.envoyRatelimitImage, err = components.GetReference(components.ComponentCalicoEnvoyRatelimit, reg, path, prefix, is)
if err != nil {
return err
}
}
return nil
}
Expand Down
86 changes: 85 additions & 1 deletion pkg/render/gateway_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ var _ = Describe("Gateway API rendering tests", func() {
Expect(proxy.Spec.Provider.Kubernetes.EnvoyDeployment.Strategy.RollingUpdate).To(Equal(rollingUpdate))
})

It("should honour private registry", func() {
It("should honour private registry (OSS)", func() {
pullSecretRefs := []corev1.LocalObjectReference{{
Name: "secret1",
}}
Expand All @@ -250,6 +250,90 @@ var _ = Describe("Gateway API rendering tests", func() {
PullSecrets: pullSecrets,
})

Expect(gatewayComp.ResolveImages(nil)).NotTo(HaveOccurred())
Expect(gatewayComp.(*gatewayAPIImplementationComponent).envoyGatewayImage).To(Equal("myregistry.io/calico/envoy-gateway:" + components.ComponentCalicoEnvoyGateway.Version))
Expect(gatewayComp.(*gatewayAPIImplementationComponent).envoyRatelimitImage).To(Equal("myregistry.io/calico/envoy-ratelimit:" + components.ComponentCalicoEnvoyRatelimit.Version))
Expect(gatewayComp.(*gatewayAPIImplementationComponent).envoyProxyImage).To(Equal("myregistry.io/calico/envoy-proxy:" + components.ComponentCalicoEnvoyProxy.Version))

objsToCreate, objsToDelete := gatewayComp.Objects()
Expect(objsToDelete).To(HaveLen(0))
rtest.ExpectResources(objsToCreate, []client.Object{
&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway"}},
&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "tigera-operator-secrets", Namespace: "tigera-gateway"}},
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "envoy-gateway", Namespace: "tigera-gateway"}},
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "envoy-gateway-config", Namespace: "tigera-gateway"}},
&rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-envoy-gateway-role"}},
&rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-envoy-gateway-rolebinding"}},
&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-infra-manager", Namespace: "tigera-gateway"}},
&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-leader-election-role", Namespace: "tigera-gateway"}},
&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-infra-manager", Namespace: "tigera-gateway"}},
&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-leader-election-rolebinding", Namespace: "tigera-gateway"}},
&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "envoy-gateway", Namespace: "tigera-gateway"}},
&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "envoy-gateway", Namespace: "tigera-gateway"}},
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-certgen", Namespace: "tigera-gateway"}},
&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-certgen", Namespace: "tigera-gateway"}},
&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-certgen", Namespace: "tigera-gateway"}},
&batchv1.Job{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-api-gateway-helm-certgen", Namespace: "tigera-gateway"}},
&envoyapi.EnvoyProxy{ObjectMeta: metav1.ObjectMeta{Name: "envoy-proxy-config", Namespace: "tigera-gateway"}},
&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "secret1", Namespace: "tigera-gateway"}},
&gapi.GatewayClass{ObjectMeta: metav1.ObjectMeta{Name: "tigera-gateway-class", Namespace: "tigera-gateway"}},
})

deploy, err := rtest.GetResourceOfType[*appsv1.Deployment](objsToCreate, "envoy-gateway", "tigera-gateway")
Expect(err).NotTo(HaveOccurred())
Expect(deploy.Spec.Template.Spec.Containers).To(ContainElement(And(
HaveField("Name", "envoy-gateway"),
HaveField("Image", "myregistry.io/calico/envoy-gateway:"+components.ComponentCalicoEnvoyGateway.Version),
)))
Expect(deploy.Spec.Template.Spec.ImagePullSecrets).To(ContainElement(pullSecretRefs[0]))

job, err := rtest.GetResourceOfType[*batchv1.Job](objsToCreate, "tigera-gateway-api-gateway-helm-certgen", "tigera-gateway")
Expect(err).NotTo(HaveOccurred())
Expect(job.Spec.Template.Spec.Containers).To(ContainElement(And(
HaveField("Name", "envoy-gateway-certgen"),
HaveField("Image", "myregistry.io/calico/envoy-gateway:"+components.ComponentCalicoEnvoyGateway.Version),
)))
Expect(job.Spec.Template.Spec.ImagePullSecrets).To(ContainElement(pullSecretRefs[0]))

proxy, err := rtest.GetResourceOfType[*envoyapi.EnvoyProxy](objsToCreate, "envoy-proxy-config", "tigera-gateway")
Expect(err).NotTo(HaveOccurred())
Expect(*proxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.Image).To(Equal("myregistry.io/calico/envoy-proxy:" + components.ComponentCalicoEnvoyProxy.Version))
Expect(proxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.ImagePullSecrets).To(ContainElement(pullSecretRefs[0]))

gatewayCM, err := rtest.GetResourceOfType[*corev1.ConfigMap](objsToCreate, "envoy-gateway-config", "tigera-gateway")
Expect(err).NotTo(HaveOccurred())
gatewayConfig := &envoyapi.EnvoyGateway{}
Expect(yaml.Unmarshal([]byte(gatewayCM.Data[EnvoyGatewayConfigKey]), gatewayConfig)).NotTo(HaveOccurred())
Expect(gatewayConfig.APIVersion).NotTo(Equal(""), fmt.Sprintf("gatewayConfig = %#v", *gatewayConfig))
Expect(gatewayConfig.Provider.Kubernetes.RateLimitDeployment).NotTo(BeNil())
Expect(gatewayConfig.Provider.Kubernetes.RateLimitDeployment.Container).NotTo(BeNil())
Expect(*gatewayConfig.Provider.Kubernetes.RateLimitDeployment.Container.Image).To(Equal("myregistry.io/calico/envoy-ratelimit:" + components.ComponentCalicoEnvoyRatelimit.Version))
Expect(gatewayConfig.Provider.Kubernetes.RateLimitDeployment.Pod.ImagePullSecrets).To(ContainElement(pullSecretRefs[0]))
Expect(*gatewayConfig.Provider.Kubernetes.ShutdownManager.Image).To(Equal("myregistry.io/calico/envoy-gateway:" + components.ComponentCalicoEnvoyGateway.Version))
})

It("should honour private registry (Enterprise)", func() {
pullSecretRefs := []corev1.LocalObjectReference{{
Name: "secret1",
}}
pullSecrets := []*corev1.Secret{}
for _, ref := range pullSecretRefs {
pullSecrets = append(pullSecrets, &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: ref.Name, Namespace: "tigera-gateway"},
})
}
installation := &operatorv1.InstallationSpec{
Registry: "myregistry.io/",
ImagePullSecrets: pullSecretRefs,
Variant: operatorv1.TigeraSecureEnterprise,
}
gatewayAPI := &operatorv1.GatewayAPI{}
gatewayComp := GatewayAPIImplementationComponent(&GatewayAPIImplementationConfig{
Installation: installation,
GatewayAPI: gatewayAPI,
PullSecrets: pullSecrets,
})

Expect(gatewayComp.ResolveImages(nil)).NotTo(HaveOccurred())
Expect(gatewayComp.(*gatewayAPIImplementationComponent).envoyGatewayImage).To(Equal("myregistry.io/tigera/envoy-gateway:" + components.ComponentGatewayAPIEnvoyGateway.Version))
Expect(gatewayComp.(*gatewayAPIImplementationComponent).envoyRatelimitImage).To(Equal("myregistry.io/tigera/envoy-ratelimit:" + components.ComponentGatewayAPIEnvoyRatelimit.Version))
Expand Down

0 comments on commit d86f158

Please sign in to comment.