github.com/cilium/cilium@v1.16.2/operator/pkg/model/translation/ingress/dedicated_ingress_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ingress 5 6 import ( 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 "google.golang.org/protobuf/testing/protocmp" 13 corev1 "k8s.io/api/core/v1" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 16 "github.com/cilium/cilium/operator/pkg/model" 17 "github.com/cilium/cilium/operator/pkg/model/translation" 18 ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 19 slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 20 ) 21 22 func Test_getService(t *testing.T) { 23 resource := model.FullyQualifiedResource{ 24 Name: "dummy-ingress", 25 Namespace: "dummy-namespace", 26 Version: "v1", 27 Kind: "Ingress", 28 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 29 } 30 31 t.Run("Default LB service", func(t *testing.T) { 32 it := &dedicatedIngressTranslator{} 33 res := it.getService(resource, nil, false) 34 require.Equal(t, &corev1.Service{ 35 ObjectMeta: metav1.ObjectMeta{ 36 Name: "cilium-ingress-dummy-ingress", 37 Namespace: "dummy-namespace", 38 Labels: map[string]string{"cilium.io/ingress": "true"}, 39 OwnerReferences: []metav1.OwnerReference{ 40 { 41 APIVersion: "networking.k8s.io/v1", 42 Kind: "Ingress", 43 Name: "dummy-ingress", 44 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 45 Controller: model.AddressOf(true), 46 }, 47 }, 48 }, 49 Spec: corev1.ServiceSpec{ 50 Type: corev1.ServiceTypeLoadBalancer, 51 Ports: []corev1.ServicePort{ 52 { 53 Name: "http", 54 Protocol: "TCP", 55 Port: 80, 56 }, 57 { 58 Name: "https", 59 Protocol: "TCP", 60 Port: 443, 61 }, 62 }, 63 }, 64 }, res) 65 }) 66 67 t.Run("Default LB service with TLS only", func(t *testing.T) { 68 it := &dedicatedIngressTranslator{} 69 res := it.getService(resource, nil, true) 70 require.Equal(t, &corev1.Service{ 71 ObjectMeta: metav1.ObjectMeta{ 72 Name: "cilium-ingress-dummy-ingress", 73 Namespace: "dummy-namespace", 74 Labels: map[string]string{"cilium.io/ingress": "true"}, 75 OwnerReferences: []metav1.OwnerReference{ 76 { 77 APIVersion: "networking.k8s.io/v1", 78 Kind: "Ingress", 79 Name: "dummy-ingress", 80 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 81 Controller: model.AddressOf(true), 82 }, 83 }, 84 }, 85 Spec: corev1.ServiceSpec{ 86 Type: corev1.ServiceTypeLoadBalancer, 87 Ports: []corev1.ServicePort{ 88 { 89 Name: "https", 90 Protocol: "TCP", 91 Port: 443, 92 }, 93 }, 94 }, 95 }, res) 96 }) 97 98 t.Run("Invalid LB service annotation, defaults to LoadBalancer", func(t *testing.T) { 99 it := &dedicatedIngressTranslator{} 100 res := it.getService(resource, &model.Service{ 101 Type: "InvalidServiceType", 102 }, false) 103 require.Equal(t, &corev1.Service{ 104 ObjectMeta: metav1.ObjectMeta{ 105 Name: "cilium-ingress-dummy-ingress", 106 Namespace: "dummy-namespace", 107 Labels: map[string]string{"cilium.io/ingress": "true"}, 108 OwnerReferences: []metav1.OwnerReference{ 109 { 110 APIVersion: "networking.k8s.io/v1", 111 Kind: "Ingress", 112 Name: "dummy-ingress", 113 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 114 Controller: model.AddressOf(true), 115 }, 116 }, 117 }, 118 Spec: corev1.ServiceSpec{ 119 Type: corev1.ServiceTypeLoadBalancer, 120 Ports: []corev1.ServicePort{ 121 { 122 Name: "http", 123 Protocol: "TCP", 124 Port: 80, 125 }, 126 { 127 Name: "https", 128 Protocol: "TCP", 129 Port: 443, 130 }, 131 }, 132 }, 133 }, res) 134 }) 135 136 t.Run("Node Port service", func(t *testing.T) { 137 var insecureNodePort uint32 = 3000 138 var secureNodePort uint32 = 3001 139 it := &dedicatedIngressTranslator{} 140 res := it.getService(resource, &model.Service{ 141 Type: "NodePort", 142 InsecureNodePort: &insecureNodePort, 143 SecureNodePort: &secureNodePort, 144 }, false) 145 require.Equal(t, &corev1.Service{ 146 ObjectMeta: metav1.ObjectMeta{ 147 Name: "cilium-ingress-dummy-ingress", 148 Namespace: "dummy-namespace", 149 Labels: map[string]string{"cilium.io/ingress": "true"}, 150 OwnerReferences: []metav1.OwnerReference{ 151 { 152 APIVersion: "networking.k8s.io/v1", 153 Kind: "Ingress", 154 Name: "dummy-ingress", 155 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 156 Controller: model.AddressOf(true), 157 }, 158 }, 159 }, 160 Spec: corev1.ServiceSpec{ 161 Type: corev1.ServiceTypeNodePort, 162 Ports: []corev1.ServicePort{ 163 { 164 Name: "http", 165 Protocol: "TCP", 166 Port: 80, 167 NodePort: 3000, 168 }, 169 { 170 Name: "https", 171 Protocol: "TCP", 172 Port: 443, 173 NodePort: 3001, 174 }, 175 }, 176 }, 177 }, res) 178 }) 179 } 180 181 func Test_getEndpointForIngress(t *testing.T) { 182 res := getEndpoints(model.FullyQualifiedResource{ 183 Name: "dummy-ingress", 184 Namespace: "dummy-namespace", 185 Version: "v1", 186 Kind: "Ingress", 187 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 188 }) 189 190 require.Equal(t, &corev1.Endpoints{ 191 ObjectMeta: metav1.ObjectMeta{ 192 Name: "cilium-ingress-dummy-ingress", 193 Namespace: "dummy-namespace", 194 Labels: map[string]string{"cilium.io/ingress": "true"}, 195 OwnerReferences: []metav1.OwnerReference{ 196 { 197 APIVersion: "networking.k8s.io/v1", 198 Kind: "Ingress", 199 Name: "dummy-ingress", 200 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 201 Controller: model.AddressOf(true), 202 }, 203 }, 204 }, 205 Subsets: []corev1.EndpointSubset{ 206 { 207 Addresses: []corev1.EndpointAddress{{IP: "192.192.192.192"}}, 208 Ports: []corev1.EndpointPort{{Port: 9999}}, 209 }, 210 }, 211 }, res) 212 } 213 214 func Test_translator_Translate(t *testing.T) { 215 type args struct { 216 m *model.Model 217 useProxyProtocol bool 218 hostNetworkEnabled bool 219 hostNetworkNodeLabelSelector *slim_metav1.LabelSelector 220 ipv4Enabled bool 221 ipv6Enabled bool 222 } 223 tests := []struct { 224 name string 225 args args 226 want *ciliumv2.CiliumEnvoyConfig 227 wantLBSvcType corev1.ServiceType 228 wantErr bool 229 }{ 230 { 231 name: "Conformance/DefaultBackend", 232 args: args{ 233 m: &model.Model{ 234 HTTP: defaultBackendListeners, 235 }, 236 }, 237 want: defaultBackendListenersCiliumEnvoyConfig, 238 wantLBSvcType: corev1.ServiceTypeLoadBalancer, 239 }, 240 { 241 name: "Conformance/HostRules", 242 args: args{ 243 m: &model.Model{ 244 HTTP: hostRulesListenersEnforceHTTPS, 245 }, 246 }, 247 want: hostRulesListenersEnforceHTTPSCiliumEnvoyConfig, 248 wantLBSvcType: corev1.ServiceTypeLoadBalancer, 249 }, 250 { 251 name: "Conformance/HostRules,no Force HTTPS", 252 args: args{ 253 m: &model.Model{ 254 HTTP: hostRulesListeners, 255 }, 256 }, 257 want: hostRulesListenersCiliumEnvoyConfig, 258 wantLBSvcType: corev1.ServiceTypeLoadBalancer, 259 }, 260 { 261 name: "Conformance/PathRules", 262 args: args{ 263 m: &model.Model{ 264 HTTP: pathRulesListeners, 265 }, 266 }, 267 want: pathRulesListenersCiliumEnvoyConfig, 268 wantLBSvcType: corev1.ServiceTypeLoadBalancer, 269 }, 270 { 271 name: "Conformance/ProxyProtocol", 272 args: args{ 273 m: &model.Model{ 274 HTTP: proxyProtocolListeners, 275 }, 276 useProxyProtocol: true, 277 }, 278 want: proxyProtoListenersCiliumEnvoyConfig, 279 wantLBSvcType: corev1.ServiceTypeLoadBalancer, 280 }, 281 { 282 name: "Conformance/HostNetwork", 283 args: args{ 284 m: &model.Model{ 285 HTTP: hostNetworkListeners(55555), 286 }, 287 hostNetworkEnabled: true, 288 hostNetworkNodeLabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]slim_metav1.MatchLabelsValue{"a": "b"}}, 289 ipv4Enabled: true, 290 }, 291 want: hostNetworkListenersCiliumEnvoyConfig("0.0.0.0", 55555, &slim_metav1.LabelSelector{MatchLabels: map[string]slim_metav1.MatchLabelsValue{"a": "b"}}), 292 wantLBSvcType: corev1.ServiceTypeClusterIP, 293 }, 294 { 295 name: "ComplexNodePortIngress", 296 args: args{ 297 m: &model.Model{ 298 HTTP: complexNodePortIngressListeners, 299 }, 300 hostNetworkEnabled: true, 301 hostNetworkNodeLabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]slim_metav1.MatchLabelsValue{"a": "b"}}, 302 ipv4Enabled: true, 303 }, 304 want: complexNodePortIngressCiliumEnvoyConfig, 305 wantLBSvcType: corev1.ServiceTypeNodePort, 306 }, 307 } 308 309 for _, tt := range tests { 310 t.Run(tt.name, func(t *testing.T) { 311 trans := &dedicatedIngressTranslator{ 312 cecTranslator: translation.NewCECTranslator("cilium-secrets", tt.args.useProxyProtocol, false, false, 60, tt.args.hostNetworkEnabled, tt.args.hostNetworkNodeLabelSelector, tt.args.ipv4Enabled, tt.args.ipv6Enabled, 0), 313 hostNetworkEnabled: tt.args.hostNetworkEnabled, 314 } 315 316 cec, svc, ep, err := trans.Translate(tt.args.m) 317 require.Equal(t, tt.wantErr, err != nil, "Error mismatch") 318 319 diffOutput := cmp.Diff(tt.want, cec, protocmp.Transform()) 320 if len(diffOutput) != 0 { 321 t.Errorf("CiliumEnvoyConfigs did not match:\n%s\n", diffOutput) 322 } 323 324 require.NotNil(t, svc) 325 assert.Equal(t, tt.wantLBSvcType, svc.Spec.Type) 326 327 require.NotNil(t, ep) 328 }) 329 } 330 }