internal/manifests/collector/ingress.go (123 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package collector
import (
"fmt"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/aws/amazon-cloudwatch-agent-operator/apis/v1alpha1"
"github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests"
"github.com/aws/amazon-cloudwatch-agent-operator/internal/naming"
)
func Ingress(params manifests.Params) (*networkingv1.Ingress, error) {
if params.OtelCol.Spec.Ingress.Type != v1alpha1.IngressTypeNginx {
return nil, nil
}
ports, err := servicePortsFromCfg(params.Log, params.OtelCol)
// if we have no ports, we don't need a ingress entry
if len(ports) == 0 || err != nil {
params.Log.V(1).Info(
"the instance's configuration didn't yield any ports to open, skipping ingress",
"instance.name", params.OtelCol.Name,
"instance.namespace", params.OtelCol.Namespace,
)
return nil, err
}
var rules []networkingv1.IngressRule
switch params.OtelCol.Spec.Ingress.RuleType {
case v1alpha1.IngressRuleTypePath, "":
rules = []networkingv1.IngressRule{createPathIngressRules(params.OtelCol.Name, params.OtelCol.Spec.Ingress.Hostname, ports)}
case v1alpha1.IngressRuleTypeSubdomain:
rules = createSubdomainIngressRules(params.OtelCol.Name, params.OtelCol.Spec.Ingress.Hostname, ports)
}
return &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: naming.Ingress(params.OtelCol.Name),
Namespace: params.OtelCol.Namespace,
Annotations: params.OtelCol.Spec.Ingress.Annotations,
Labels: map[string]string{
"app.kubernetes.io/name": naming.Ingress(params.OtelCol.Name),
"app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name),
"app.kubernetes.io/managed-by": "amazon-cloudwatch-agent-operator",
},
},
Spec: networkingv1.IngressSpec{
TLS: params.OtelCol.Spec.Ingress.TLS,
Rules: rules,
IngressClassName: params.OtelCol.Spec.Ingress.IngressClassName,
},
}, nil
}
func createPathIngressRules(otelcol string, hostname string, ports []corev1.ServicePort) networkingv1.IngressRule {
pathType := networkingv1.PathTypePrefix
paths := make([]networkingv1.HTTPIngressPath, len(ports))
for i, port := range ports {
portName := naming.PortName(port.Name, port.Port)
paths[i] = networkingv1.HTTPIngressPath{
Path: "/" + port.Name,
PathType: &pathType,
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: naming.Service(otelcol),
Port: networkingv1.ServiceBackendPort{
Name: portName,
},
},
},
}
}
return networkingv1.IngressRule{
Host: hostname,
IngressRuleValue: networkingv1.IngressRuleValue{
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: paths,
},
},
}
}
func createSubdomainIngressRules(otelcol string, hostname string, ports []corev1.ServicePort) []networkingv1.IngressRule {
var rules []networkingv1.IngressRule
pathType := networkingv1.PathTypePrefix
for _, port := range ports {
portName := naming.PortName(port.Name, port.Port)
host := fmt.Sprintf("%s.%s", portName, hostname)
// This should not happen due to validation in the webhook.
if hostname == "" || hostname == "*" {
host = portName
}
rules = append(rules, networkingv1.IngressRule{
Host: host,
IngressRuleValue: networkingv1.IngressRuleValue{
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: []networkingv1.HTTPIngressPath{
{
Path: "/",
PathType: &pathType,
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: naming.Service(otelcol),
Port: networkingv1.ServiceBackendPort{
Name: portName,
},
},
},
},
},
},
},
})
}
return rules
}
func servicePortsFromCfg(logger logr.Logger, otelcol v1alpha1.AmazonCloudWatchAgent) ([]corev1.ServicePort, error) {
var ports []corev1.ServicePort
if len(otelcol.Spec.Ports) > 0 {
// we should add all the ports from the CR
// there are two cases where problems might occur:
// 1) when the port number is already being used by a receiver
// 2) same, but for the port name
//
// in the first case, we remove the port we inferred from the list
// in the second case, we rename our inferred port to something like "port-%d"
portNumbers, portNames := extractPortNumbersAndNames(otelcol.Spec.Ports)
var resultingInferredPorts []corev1.ServicePort
for _, inferred := range ports {
if filtered := filterPort(logger, inferred, portNumbers, portNames); filtered != nil {
resultingInferredPorts = append(resultingInferredPorts, *filtered)
}
}
ports = append(otelcol.Spec.Ports, resultingInferredPorts...)
}
return ports, nil
}