Skip to content

Commit 774406b

Browse files
Use Default Backend pool and HTTP settings when Service not present (#59)
1 parent cda03a2 commit 774406b

File tree

12 files changed

+182
-91
lines changed

12 files changed

+182
-91
lines changed

cmd/appgw-ingress/main.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,18 @@ import (
1212
"time"
1313

1414
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
15-
16-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/appgw"
17-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/controller"
18-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/k8scontext"
19-
2015
"github.com/Azure/go-autorest/autorest"
2116
"github.com/Azure/go-autorest/autorest/azure/auth"
22-
2317
"github.com/golang/glog"
2418
flag "github.com/spf13/pflag"
2519
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2620
"k8s.io/client-go/kubernetes"
2721
"k8s.io/client-go/rest"
2822
"k8s.io/client-go/tools/clientcmd"
23+
24+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/appgw"
25+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/controller"
26+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/k8scontext"
2927
)
3028

3129
var (

docs/build.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
## Building
2-
3-
This is a CMake-based project. Build targets include:
4-
5-
- `ALL_BUILD` (default target) builds `appgw-ingress` and `dockerize` target
6-
- `devenv` builds a docker image with configured development environment
7-
- `vendor` installs dependency using `glide` in a docker container with image from `devenv` target
8-
- `appgw-ingress` builds the binary for this controller in a docker container with image from `devenv` target
9-
- `dockerize` builds a docker image with the binary from `appgw-ingress` target
10-
- `dockerpush` pushes the docker image to a container registry with prefix defined in CMake variable `<deployment_push_prefix>`
11-
12-
To run the CMake targets:
13-
14-
1. `mkdir build && cd build` creates and enters a build directory
15-
2. `cmake ..` generates project configuration in the build directory
16-
3. `cmake --build .` to build the default target,
1+
## Building
2+
3+
This is a CMake-based project. Build targets include:
4+
5+
- `ALL_BUILD` (default target) builds `appgw-ingress` and `dockerize` target
6+
- `devenv` builds a docker image with configured development environment
7+
- `vendor` installs dependency using `glide` in a docker container with image from `devenv` target
8+
- `appgw-ingress` builds the binary for this controller in a docker container with image from `devenv` target
9+
- `dockerize` builds a docker image with the binary from `appgw-ingress` target
10+
- `dockerpush` pushes the docker image to a container registry with prefix defined in CMake variable `<deployment_push_prefix>`
11+
12+
To run the CMake targets:
13+
14+
1. `mkdir build && cd build` creates and enters a build directory
15+
2. `cmake ..` generates project configuration in the build directory
16+
3. `cmake --build .` to build the default target,
1717
or `cmake --build . --target <target_name>` to specify a target to run from above

pkg/appgw/appgw_test.go

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import (
55
"fmt"
66
"time"
77

8+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/k8scontext"
9+
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
10+
"github.com/Azure/go-autorest/autorest/to"
811
. "github.com/onsi/ginkgo"
912
. "github.com/onsi/gomega"
1013
"k8s.io/api/core/v1"
@@ -13,10 +16,6 @@ import (
1316
"k8s.io/apimachinery/pkg/util/intstr"
1417
"k8s.io/client-go/kubernetes"
1518
testclient "k8s.io/client-go/kubernetes/fake"
16-
17-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/k8scontext"
18-
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
19-
"github.com/Azure/go-autorest/autorest/to"
2019
)
2120

2221
var _ = Describe("Tests `appgw.ConfigBuilder`", func() {
@@ -290,4 +289,111 @@ var _ = Describe("Tests `appgw.ConfigBuilder`", func() {
290289
Expect((*pathRule.Paths)[0]).To(Equal("/hi"))
291290
})
292291
})
292+
293+
Context("Tests Ingress Controller when Service doesn't exists", func() {
294+
It("Should be able to create Application Gateway Configuration from Ingress with empty backend pool.", func() {
295+
// Delete the service
296+
options := &metav1.DeleteOptions{}
297+
err := k8sClient.CoreV1().Services(ingressNS).Delete(serviceName, options)
298+
Expect(err).Should(BeNil(), "Unable to delete service resource due to: %v", err)
299+
300+
// Delete the Endpoint
301+
err = k8sClient.CoreV1().Endpoints(ingressNS).Delete(serviceName, options)
302+
Expect(err).Should(BeNil(), "Unable to delete endpoint resource due to: %v", err)
303+
304+
// Start the informers. This will sync the cache with the latest ingress.
305+
ctxt.Run()
306+
307+
// Get all the ingresses
308+
ingressList := ctxt.GetHTTPIngressList()
309+
// There should be only one ingress
310+
Expect(len(ingressList)).To(Equal(1), "Expected only one ingress resource but got: %d", len(ingressList))
311+
// Make sure it is the ingress we stored.
312+
Expect(ingressList[0]).To(Equal(ingress))
313+
314+
// Add HTTP settings.
315+
configBuilder, err := configBuilder.BackendHTTPSettingsCollection(ingressList)
316+
Expect(err).Should(BeNil(), "Error in generating the HTTP Settings: %v", err)
317+
318+
// Retrieve the implementation of the `ConfigBuilder` interface.
319+
appGW := configBuilder.Build()
320+
// We will have a default HTTP setting that gets added, and an HTTP setting corresponding to port `backendPort`
321+
Expect(len(*appGW.BackendHTTPSettingsCollection)).To(Equal(2), "Expected two HTTP setting, but got: %d", len(*appGW.BackendHTTPSettingsCollection))
322+
323+
expectedBackend := &ingress.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].Backend
324+
httpSettingsName := generateHTTPSettingsName(generateBackendID(ingress, expectedBackend).serviceFullName(), fmt.Sprintf("%d", servicePort), servicePort)
325+
httpSettings := &network.ApplicationGatewayBackendHTTPSettings{
326+
Etag: to.StringPtr("*"),
327+
Name: &httpSettingsName,
328+
ApplicationGatewayBackendHTTPSettingsPropertiesFormat: &network.ApplicationGatewayBackendHTTPSettingsPropertiesFormat{
329+
Protocol: network.HTTP,
330+
Port: &servicePort,
331+
},
332+
}
333+
334+
// Test the default backend HTTP settings.
335+
Expect((*appGW.BackendHTTPSettingsCollection)[0]).To(Equal(defaultBackendHTTPSettings()))
336+
// Test the ingress backend HTTP setting that we installed.
337+
Expect((*appGW.BackendHTTPSettingsCollection)[1]).To(Equal(*httpSettings))
338+
339+
// Add backend address pools. We need the HTTP settings before we can add the backend address pools.
340+
configBuilder, err = configBuilder.BackendAddressPools(ingressList)
341+
Expect(err).Should(BeNil(), "Error in generating the backend address pools: %v", err)
342+
343+
// Retrieve the implementation of the `ConfigBuilder` interface.
344+
appGW = configBuilder.Build()
345+
// We will have a default backend address pool that gets added, and a backend pool corresponding to our service.
346+
Expect(len(*appGW.BackendAddressPools)).To(Equal(1), "Expected two backend address pools, but got: %d", len(*appGW.BackendAddressPools))
347+
348+
// Test the default backend address pool.
349+
Expect((*appGW.BackendAddressPools)[0]).To(Equal(defaultBackendAddressPool()))
350+
351+
// Add the listeners. We need the backend address pools before we can add HTTP listeners.
352+
configBuilder, err = configBuilder.HTTPListeners(ingressList)
353+
Expect(err).Should(BeNil(), "Error in generating the HTTP listeners: %v", err)
354+
355+
// Retrieve the implementation of the `ConfigBuilder` interface.
356+
appGW = configBuilder.Build()
357+
// Ingress allows listners on port 80 or port 443. Therefore in this particular case we would have only a single listener
358+
Expect(len(*appGW.HTTPListeners)).To(Equal(1), "Expected a single HTTP listener, but got: %d", len(*appGW.HTTPListeners))
359+
360+
// Test the listener.
361+
appGwIdentifier := Identifier{}
362+
frontendPortID := appGwIdentifier.frontendPortID(generateFrontendPortName(80))
363+
httpListenerName := generateHTTPListenerName(frontendListenerIdentifier{80, domainName})
364+
httpListener := &network.ApplicationGatewayHTTPListener{
365+
Etag: to.StringPtr("*"),
366+
Name: &httpListenerName,
367+
ApplicationGatewayHTTPListenerPropertiesFormat: &network.ApplicationGatewayHTTPListenerPropertiesFormat{
368+
FrontendIPConfiguration: resourceRef("*"),
369+
FrontendPort: resourceRef(frontendPortID),
370+
Protocol: network.HTTP,
371+
HostName: &domainName,
372+
},
373+
}
374+
375+
Expect((*appGW.HTTPListeners)[0]).To(Equal(*httpListener))
376+
377+
// RequestRoutingRules depends on the previous operations
378+
configBuilder, err = configBuilder.RequestRoutingRules(ingressList)
379+
Expect(err).Should(BeNil(), "Error in generating the routing rules: %v", err)
380+
381+
// Retrieve the implementation of the `ConfigBuilder` interface.
382+
appGW = configBuilder.Build()
383+
Expect(len(*appGW.RequestRoutingRules)).To(Equal(1), "Expected one routing rule, but got: %d", len(*appGW.RequestRoutingRules))
384+
Expect(*((*appGW.RequestRoutingRules)[0].Name)).To(Equal(generateRequestRoutingRuleName(frontendListenerIdentifier{80, domainName})))
385+
Expect((*appGW.RequestRoutingRules)[0].RuleType).To(Equal(network.PathBasedRouting))
386+
387+
// Check the `urlPathMaps`
388+
Expect(len(*appGW.URLPathMaps)).To(Equal(1), "Expected one URL path map routing, but got: %d", len(*appGW.URLPathMaps))
389+
Expect(*((*appGW.URLPathMaps)[0].Name)).To(Equal(generateURLPathMapName(frontendListenerIdentifier{80, domainName})))
390+
// Check the `pathRule` stored within the `urlPathMap`.
391+
Expect(len(*((*appGW.URLPathMaps)[0].PathRules))).To(Equal(1), "Expected one path based rule, but got: %d", len(*((*appGW.URLPathMaps)[0].PathRules)))
392+
393+
pathRule := (*((*appGW.URLPathMaps)[0].PathRules))[0]
394+
Expect(len(*(pathRule.Paths))).To(Equal(1), "Expected a single path in path-based rules, but got: %d", len(*(pathRule.Paths)))
395+
// Check the exact path that was set.
396+
Expect((*pathRule.Paths)[0]).To(Equal("/hi"))
397+
})
398+
})
293399
})

pkg/appgw/backendaddresspools.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,27 @@
66
package appgw
77

88
import (
9-
"errors"
10-
9+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/utils"
1110
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
1211
"github.com/Azure/go-autorest/autorest/to"
1312
"github.com/golang/glog"
1413
"k8s.io/api/core/v1"
1514
"k8s.io/api/extensions/v1beta1"
16-
17-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/utils"
1815
)
1916

2017
func (builder *appGwConfigBuilder) BackendAddressPools(ingressList [](*v1beta1.Ingress)) (ConfigBuilder, error) {
2118
addressPools := make([](network.ApplicationGatewayBackendAddressPool), 0)
22-
addressPools = append(addressPools, defaultBackendAddressPool())
19+
emptyPool := defaultBackendAddressPool()
20+
addressPools = append(addressPools, emptyPool)
2321

2422
for backendID, serviceBackendPair := range builder.serviceBackendPairMap {
2523
endpoints := builder.k8sContext.GetEndpointsByService(backendID.serviceKey())
2624
if endpoints == nil {
2725
glog.Warningf("unable to get endpoints for service key [%s]", backendID.serviceKey())
28-
return builder, errors.New("unable to get endpoints for service")
26+
builder.backendPoolMap[backendID] = &emptyPool
27+
continue
2928
}
29+
3030
for _, subset := range endpoints.Subsets {
3131
endpointsPortsSet := utils.NewUnorderedSet()
3232
for _, endpointsPort := range subset.Ports {

pkg/appgw/backendhttpsettings.go

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ import (
99
"errors"
1010
"fmt"
1111

12+
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/utils"
1213
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
1314
"github.com/Azure/go-autorest/autorest/to"
1415
"github.com/golang/glog"
15-
16-
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/utils"
17-
1816
"k8s.io/api/core/v1"
1917
"k8s.io/api/extensions/v1beta1"
2018
"k8s.io/apimachinery/pkg/util/intstr"
@@ -44,56 +42,58 @@ func (builder *appGwConfigBuilder) BackendHTTPSettingsCollection(ingressList [](
4442
unresolvedBackendID := make([]backendIdentifier, 0)
4543
backendIDs.ForEach(func(backendIDInterface interface{}) {
4644
backendID := backendIDInterface.(backendIdentifier)
45+
resolvedBackendPorts := utils.NewUnorderedSet()
4746

4847
service := builder.k8sContext.GetService(backendID.serviceKey())
4948
if service == nil {
5049
glog.V(1).Infof("unable to get the service [%s]", backendID.serviceKey())
51-
unresolvedBackendID = append(unresolvedBackendID, backendID)
52-
return
53-
}
50+
resolvedBackendPorts.Insert(serviceBackendPortPair{
51+
ServicePort: backendID.ServicePort.IntVal,
52+
BackendPort: backendID.ServicePort.IntVal,
53+
})
54+
} else {
55+
for _, sp := range service.Spec.Ports {
56+
// find the backend port number
57+
// check if any service ports matches the specified ports
58+
if sp.Protocol != v1.ProtocolTCP {
59+
// ignore UDP ports
60+
continue
61+
}
62+
if fmt.Sprint(sp.Port) == backendID.ServicePort.String() ||
63+
sp.Name == backendID.ServicePort.String() ||
64+
sp.TargetPort.String() == backendID.ServicePort.String() {
65+
// matched a service port with a port from the service
5466

55-
// find the backend port number
56-
resolvedBackendPorts := utils.NewUnorderedSet()
57-
for _, sp := range service.Spec.Ports {
58-
// check if any service ports matches the specified ports
59-
if sp.Protocol != v1.ProtocolTCP {
60-
// ignore UDP ports
61-
continue
62-
}
63-
if fmt.Sprint(sp.Port) == backendID.ServicePort.String() ||
64-
sp.Name == backendID.ServicePort.String() ||
65-
sp.TargetPort.String() == backendID.ServicePort.String() {
66-
// matched a service port with a port from the service
67-
68-
if sp.TargetPort.String() == "" {
69-
// targetPort is not defined, by default targetPort == port
70-
resolvedBackendPorts.Insert(serviceBackendPortPair{
71-
ServicePort: sp.Port,
72-
BackendPort: sp.Port,
73-
})
74-
} else {
75-
// target port is defined as name or port number
76-
if sp.TargetPort.Type == intstr.Int {
77-
// port is defined as port number
67+
if sp.TargetPort.String() == "" {
68+
// targetPort is not defined, by default targetPort == port
7869
resolvedBackendPorts.Insert(serviceBackendPortPair{
7970
ServicePort: sp.Port,
80-
BackendPort: sp.TargetPort.IntVal,
71+
BackendPort: sp.Port,
8172
})
8273
} else {
83-
// if service port is defined by name, need to resolve
84-
targetPortName := sp.TargetPort.StrVal
85-
glog.V(1).Infof("resolving port name %s", targetPortName)
86-
targetPortsResolved := builder.resolvePortName(targetPortName, &backendID)
87-
targetPortsResolved.ForEach(func(targetPortInterface interface{}) {
88-
targetPort := targetPortInterface.(int32)
74+
// target port is defined as name or port number
75+
if sp.TargetPort.Type == intstr.Int {
76+
// port is defined as port number
8977
resolvedBackendPorts.Insert(serviceBackendPortPair{
9078
ServicePort: sp.Port,
91-
BackendPort: targetPort,
79+
BackendPort: sp.TargetPort.IntVal,
9280
})
93-
})
81+
} else {
82+
// if service port is defined by name, need to resolve
83+
targetPortName := sp.TargetPort.StrVal
84+
glog.V(1).Infof("resolving port name %s", targetPortName)
85+
targetPortsResolved := builder.resolvePortName(targetPortName, &backendID)
86+
targetPortsResolved.ForEach(func(targetPortInterface interface{}) {
87+
targetPort := targetPortInterface.(int32)
88+
resolvedBackendPorts.Insert(serviceBackendPortPair{
89+
ServicePort: sp.Port,
90+
BackendPort: targetPort,
91+
})
92+
})
93+
}
9494
}
95+
break
9596
}
96-
break
9797
}
9898
}
9999

pkg/appgw/configbuilder.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ package appgw
77

88
import (
99
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
10+
"k8s.io/api/extensions/v1beta1"
1011

1112
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/k8scontext"
1213
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/utils"
13-
14-
"k8s.io/api/extensions/v1beta1"
1514
)
1615

1716
// ConfigBuilder is a builder for application gateway configuration

pkg/appgw/identifier.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"os"
1111

1212
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
13-
1413
"github.com/Azure/go-autorest/autorest/to"
1514
"github.com/golang/glog"
1615
)

pkg/appgw/internaltypes.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ package appgw
88
import (
99
"fmt"
1010

11-
"github.com/Azure/go-autorest/autorest/to"
12-
1311
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
1412
"k8s.io/apimachinery/pkg/util/intstr"
1513
)
@@ -109,11 +107,7 @@ func defaultBackendAddressPool() network.ApplicationGatewayBackendAddressPool {
109107
return network.ApplicationGatewayBackendAddressPool{
110108
Name: &defBackendAddressPool,
111109
ApplicationGatewayBackendAddressPoolPropertiesFormat: &network.ApplicationGatewayBackendAddressPoolPropertiesFormat{
112-
BackendAddresses: &[]network.ApplicationGatewayBackendAddress{
113-
network.ApplicationGatewayBackendAddress{
114-
Fqdn: to.StringPtr("nonexistent.placeholder"),
115-
},
116-
},
110+
BackendAddresses: &[]network.ApplicationGatewayBackendAddress{},
117111
},
118112
}
119113
}

pkg/appgw/requestroutingrules.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010

1111
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network"
1212
"github.com/Azure/go-autorest/autorest/to"
13-
1413
"k8s.io/api/extensions/v1beta1"
1514
)
1615

0 commit comments

Comments
 (0)