Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow user to configure annotations on infra #1115

Merged
merged 3 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions api/config/v1alpha1/envoyproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ type KubernetesResourceProvider struct {
//
// +optional
EnvoyDeployment *KubernetesDeploymentSpec `json:"envoyDeployment,omitempty"`

// EnvoyService defines the desired state of the Envoy service resource.
// If unspecified, default settings for the manged Envoy service resource
// are applied.
arkodg marked this conversation as resolved.
Show resolved Hide resolved
//
// +optional
EnvoyService *KubernetesServiceSpec `json:"envoyService,omitempty"`
}

// ProxyLogging defines logging parameters for managed proxies. This type is not
Expand Down
24 changes: 21 additions & 3 deletions api/config/v1alpha1/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,28 @@ func (e *EnvoyProxy) GetProvider() *ResourceProvider {
func DefaultKubeResourceProvider() *KubernetesResourceProvider {
return &KubernetesResourceProvider{
EnvoyDeployment: DefaultKubernetesDeployment(),
EnvoyService: DefaultKubernetesService(),
}
}

// DefaultKubernetesDeploymentReplicas returns the default replica settings.
func DefaultKubernetesDeploymentReplicas() *int32 {
repl := int32(DefaultEnvoyReplicas)
return &repl
}

// DefaultKubernetesDeployment returns a new KubernetesDeploymentSpec with default settings.
func DefaultKubernetesDeployment() *KubernetesDeploymentSpec {
repl := int32(DefaultEnvoyReplicas)
return &KubernetesDeploymentSpec{
Replicas: &repl,
Replicas: DefaultKubernetesDeploymentReplicas(),
}
}

// DefaultKubernetesService returns a new KubernetesServiceSpec with default settings.
func DefaultKubernetesService() *KubernetesServiceSpec {
return &KubernetesServiceSpec{}
}

// GetKubeResourceProvider returns the KubernetesResourceProvider of ResourceProvider or
// a default KubernetesResourceProvider if unspecified. If ResourceProvider is not of
// type "Kubernetes", a nil KubernetesResourceProvider is returned.
Expand All @@ -113,7 +124,14 @@ func (r *ResourceProvider) GetKubeResourceProvider() *KubernetesResourceProvider

if r.Kubernetes.EnvoyDeployment == nil {
r.Kubernetes.EnvoyDeployment = DefaultKubernetesDeployment()
return r.Kubernetes
}

if r.Kubernetes.EnvoyDeployment.Replicas == nil {
r.Kubernetes.EnvoyDeployment.Replicas = DefaultKubernetesDeploymentReplicas()
}

if r.Kubernetes.EnvoyService == nil {
r.Kubernetes.EnvoyService = DefaultKubernetesService()
}

return r.Kubernetes
Expand Down
17 changes: 17 additions & 0 deletions api/config/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,22 @@ type KubernetesDeploymentSpec struct {
// +optional
Replicas *int32 `json:"replicas,omitempty"`

// PodAnnotations are the annotations that should be appended to the pods.
// By default, no pod annotations are appended.
//
// +optional
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`

// TODO: Expose config as use cases are better understood, e.g. labels.
}

// KubernetesServiceSpec defines the desired state of the Kubernetes service resource.
type KubernetesServiceSpec struct {
// Annotations that should be appended to the service.
// By default, no annotations are appended.
//
// +optional
Annotations map[string]string `json:"annotations,omitempty"`

// TODO: Expose config as use cases are better understood, e.g. labels.
}
34 changes: 34 additions & 0 deletions api/config/v1alpha1/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,31 @@ spec:
the Envoy deployment resource. If unspecified, default settings
for the manged Envoy deployment resource are applied.
properties:
podAnnotations:
additionalProperties:
type: string
description: PodAnnotations are the annotations that should
be appended to the pods. By default, no pod annotations
are appended.
type: object
replicas:
description: Replicas is the number of desired pods. Defaults
to 1.
format: int32
type: integer
type: object
envoyService:
description: EnvoyService defines the desired state of the
Envoy service resource. If unspecified, default settings
for the manged Envoy service resource are applied.
properties:
annotations:
additionalProperties:
type: string
description: Annotations that should be appended to the
service. By default, no annotations are appended.
type: object
type: object
type: object
type:
description: Type is the type of resource provider to use. A resource
Expand Down
9 changes: 8 additions & 1 deletion internal/infrastructure/kubernetes/proxy_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ func (i *Infra) expectedProxyDeployment(infra *ir.Infra) (*appsv1.Deployment, er
}
deployCfg := provider.GetKubeResourceProvider().EnvoyDeployment

// Get annotations
var annotations map[string]string
if deployCfg != nil {
annotations = deployCfg.PodAnnotations
}

deployment := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
Expand All @@ -69,7 +75,8 @@ func (i *Infra) expectedProxyDeployment(infra *ir.Infra) (*appsv1.Deployment, er
Selector: selector,
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: selector.MatchLabels,
Labels: selector.MatchLabels,
Annotations: annotations,
},
Spec: corev1.PodSpec{
Containers: containers,
Expand Down
51 changes: 51 additions & 0 deletions internal/infrastructure/kubernetes/proxy_deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ func checkContainerHasPort(t *testing.T, deploy *appsv1.Deployment, port int32)
t.Errorf("container is missing containerPort %q", port)
}

func checkPodAnnotations(t *testing.T, deploy *appsv1.Deployment, expected map[string]string) {
t.Helper()

if apiequality.Semantic.DeepEqual(deploy.Spec.Template.Annotations, expected) {
return
}

t.Errorf("deployment has unexpected %q pod annotations ", deploy.Spec.Template.Annotations)
}

func checkContainerImage(t *testing.T, container *corev1.Container, image string) {
t.Helper()

Expand Down Expand Up @@ -151,6 +161,9 @@ func TestExpectedProxyDeployment(t *testing.T) {

// Check the number of replicas is as expected.
assert.Equal(t, repl, *deploy.Spec.Replicas)

// Make sure no pod annotations are set by default
checkPodAnnotations(t, deploy, nil)
}

func TestExpectedBootstrap(t *testing.T) {
Expand Down Expand Up @@ -182,6 +195,44 @@ func TestExpectedBootstrap(t *testing.T) {
checkContainerHasArg(t, container, fmt.Sprintf("--config-yaml %s", bstrap))
}

func TestExpectedPodAnnotations(t *testing.T) {
svrCfg, err := config.New()
require.NoError(t, err)
cli := fakeclient.NewClientBuilder().WithScheme(envoygateway.GetScheme()).WithObjects().Build()
kube := NewInfra(cli, svrCfg)
infra := ir.NewInfra()

infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default"
infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name

// Set service annotations into EnvoyProxy API and ensure the same
// value is set in the generated service.
annotations := map[string]string{
"key1": "val1",
"key2": "val2",
}
infra.Proxy.Config = &egcfgv1a1.EnvoyProxy{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egcfgv1a1.EnvoyProxySpec{
Provider: &egcfgv1a1.ResourceProvider{
Type: egcfgv1a1.ProviderTypeKubernetes,
Kubernetes: &egcfgv1a1.KubernetesResourceProvider{
EnvoyDeployment: &egcfgv1a1.KubernetesDeploymentSpec{
PodAnnotations: annotations,
},
},
},
},
}

deploy, err := kube.expectedProxyDeployment(infra)
require.NoError(t, err)
checkPodAnnotations(t, deploy, annotations)
}

func deploymentWithImage(deploy *appsv1.Deployment, image string) *appsv1.Deployment {
dCopy := deploy.DeepCopy()
for i, c := range dCopy.Spec.Template.Spec.Containers {
Expand Down
16 changes: 13 additions & 3 deletions internal/infrastructure/kubernetes/proxy_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,21 @@ func (i *Infra) expectedProxyService(infra *ir.Infra) (*corev1.Service, error) {
return nil, fmt.Errorf("missing owning gateway labels")
}

// Get annotations
var annotations map[string]string
provider := infra.GetProxyInfra().GetProxyConfig().GetProvider()
svcCfg := provider.GetKubeResourceProvider().EnvoyService
if svcCfg != nil {
annotations = svcCfg.Annotations

}

svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Namespace: i.Namespace,
Name: expectedResourceHashedName(infra.Proxy.Name),
Labels: labels,
Namespace: i.Namespace,
Name: expectedResourceHashedName(infra.Proxy.Name),
Labels: labels,
Annotations: annotations,
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Expand Down
53 changes: 53 additions & 0 deletions internal/infrastructure/kubernetes/proxy_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"

egcfgv1a1 "github.com/envoyproxy/gateway/api/config/v1alpha1"
"github.com/envoyproxy/gateway/internal/envoygateway"
"github.com/envoyproxy/gateway/internal/envoygateway/config"
"github.com/envoyproxy/gateway/internal/gatewayapi"
Expand Down Expand Up @@ -66,6 +68,16 @@ func checkServiceHasLabels(t *testing.T, svc *corev1.Service, expected map[strin
t.Errorf("service has unexpected %q labels", svc.Labels)
}

func checkServiceHasAnnotations(t *testing.T, svc *corev1.Service, expected map[string]string) {
t.Helper()

if apiequality.Semantic.DeepEqual(svc.Annotations, expected) {
return
}

t.Errorf("service has unexpected %q annotations", svc.Annotations)
}

func TestDesiredProxyService(t *testing.T) {
cfg, err := config.New()
require.NoError(t, err)
Expand Down Expand Up @@ -108,6 +120,47 @@ func TestDesiredProxyService(t *testing.T) {
for _, port := range infra.Proxy.Listeners[0].Ports {
checkServiceHasPortName(t, svc, port.Name)
}

// Make sure no service annotations are set by default
checkServiceHasAnnotations(t, svc, nil)
}

func TestExpectedAnnotations(t *testing.T) {
svrCfg, err := config.New()
require.NoError(t, err)
cli := fakeclient.NewClientBuilder().WithScheme(envoygateway.GetScheme()).WithObjects().Build()
kube := NewInfra(cli, svrCfg)
infra := ir.NewInfra()

infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNamespaceLabel] = "default"
infra.Proxy.GetProxyMetadata().Labels[gatewayapi.OwningGatewayNameLabel] = infra.Proxy.Name

// Set service annotations into EnvoyProxy API and ensure the same
// value is set in the generated service.
annotations := map[string]string{
"key1": "val1",
"key2": "val2",
}
infra.Proxy.Config = &egcfgv1a1.EnvoyProxy{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egcfgv1a1.EnvoyProxySpec{
Provider: &egcfgv1a1.ResourceProvider{
Type: egcfgv1a1.ProviderTypeKubernetes,
Kubernetes: &egcfgv1a1.KubernetesResourceProvider{
EnvoyService: &egcfgv1a1.KubernetesServiceSpec{
Annotations: annotations,
},
},
},
},
}

svc, err := kube.expectedProxyService(infra)
require.NoError(t, err)
checkServiceHasAnnotations(t, svc, annotations)
}

func TestDeleteProxyService(t *testing.T) {
Expand Down