2016-05-29 03:54:26 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package azure
import (
2018-02-02 21:12:07 +00:00
"context"
2018-02-08 04:40:35 +00:00
"encoding/json"
2016-05-29 03:54:26 +00:00
"fmt"
2017-11-16 18:23:21 +00:00
"math"
2018-01-24 22:20:45 +00:00
"net/http"
"net/http/httptest"
2018-02-08 04:40:35 +00:00
"reflect"
2016-05-29 03:54:26 +00:00
"strings"
"testing"
2017-06-22 17:25:57 +00:00
"k8s.io/api/core/v1"
2017-11-15 01:39:55 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-06-22 18:24:23 +00:00
"k8s.io/apimachinery/pkg/types"
2016-11-18 20:58:42 +00:00
serviceapi "k8s.io/kubernetes/pkg/api/v1/service"
2017-12-19 07:18:37 +00:00
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure/auth"
2017-11-15 01:39:55 +00:00
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
2016-05-29 03:54:26 +00:00
2017-11-15 01:39:55 +00:00
"github.com/Azure/azure-sdk-for-go/arm/compute"
2016-05-29 03:54:26 +00:00
"github.com/Azure/azure-sdk-for-go/arm/network"
"github.com/Azure/go-autorest/autorest/to"
)
var testClusterName = "testCluster"
2017-11-17 00:32:02 +00:00
// Test flipServiceInternalAnnotation
func TestFlipServiceInternalAnnotation ( t * testing . T ) {
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
svcUpdated := flipServiceInternalAnnotation ( & svc )
if ! requiresInternalLoadBalancer ( svcUpdated ) {
t . Errorf ( "Expected svc to be an internal service" )
}
svcUpdated = flipServiceInternalAnnotation ( svcUpdated )
if requiresInternalLoadBalancer ( svcUpdated ) {
t . Errorf ( "Expected svc to be an external service" )
}
svc2 := getInternalTestService ( "serviceb" , 8081 )
svc2Updated := flipServiceInternalAnnotation ( & svc2 )
if requiresInternalLoadBalancer ( svc2Updated ) {
t . Errorf ( "Expected svc to be an external service" )
}
svc2Updated = flipServiceInternalAnnotation ( svc2Updated )
if ! requiresInternalLoadBalancer ( svc2Updated ) {
t . Errorf ( "Expected svc to be an internal service" )
}
}
2016-05-29 03:54:26 +00:00
// Test additional of a new service/port.
2017-11-15 01:39:55 +00:00
func TestAddPort ( t * testing . T ) {
2016-05-29 03:54:26 +00:00
az := getTestCloud ( )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2016-05-29 03:54:26 +00:00
2017-05-08 22:02:41 +00:00
svc . Spec . Ports = append ( svc . Spec . Ports , v1 . ServicePort {
Name : fmt . Sprintf ( "port-udp-%d" , 1234 ) ,
Protocol : v1 . ProtocolUDP ,
Port : 1234 ,
NodePort : getBackendPort ( 1234 ) ,
} )
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
// ensure we got a frontend ip configuration
2016-12-07 07:16:53 +00:00
if len ( * lb . FrontendIPConfigurations ) != 1 {
2016-05-29 03:54:26 +00:00
t . Error ( "Expected the loadbalancer to have a frontend ip configuration" )
}
validateLoadBalancer ( t , lb , svc )
}
2017-11-15 01:39:55 +00:00
func TestLoadBalancerInternalServiceModeSelection ( t * testing . T ) {
testLoadBalancerServiceDefaultModeSelection ( t , true )
testLoadBalancerServiceAutoModeSelection ( t , true )
testLoadBalancerServicesSpecifiedSelection ( t , true )
testLoadBalancerMaxRulesServices ( t , true )
testLoadBalancerServiceAutoModeDeleteSelection ( t , true )
}
func TestLoadBalancerExternalServiceModeSelection ( t * testing . T ) {
testLoadBalancerServiceDefaultModeSelection ( t , false )
testLoadBalancerServiceAutoModeSelection ( t , false )
testLoadBalancerServicesSpecifiedSelection ( t , false )
testLoadBalancerMaxRulesServices ( t , false )
testLoadBalancerServiceAutoModeDeleteSelection ( t , false )
}
func testLoadBalancerServiceDefaultModeSelection ( t * testing . T , isInternal bool ) {
az := getTestCloud ( )
const vmCount = 8
const availabilitySetCount = 4
const serviceCount = 9
clusterResources := getClusterResources ( az , vmCount , availabilitySetCount )
getTestSecurityGroup ( az )
for index := 1 ; index <= serviceCount ; index ++ {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
2018-02-02 21:12:07 +00:00
lbStatus , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
if lbStatus == nil {
t . Errorf ( "Unexpected error: %s" , svcName )
}
expectedLBName := testClusterName
if isInternal {
expectedLBName = testClusterName + "-internal"
}
result , _ := az . LoadBalancerClient . List ( az . Config . ResourceGroup )
lb := ( * result . Value ) [ 0 ]
lbCount := len ( * result . Value )
expectedNumOfLB := 1
if lbCount != expectedNumOfLB {
t . Errorf ( "Unexpected number of LB's: Expected (%d) Found (%d)" , expectedNumOfLB , lbCount )
}
if ! strings . EqualFold ( * lb . Name , expectedLBName ) {
t . Errorf ( "lb name should be the default LB name Extected (%s) Fouund (%s)" , expectedLBName , * lb . Name )
}
ruleCount := len ( * lb . LoadBalancingRules )
if ruleCount != index {
2017-11-16 01:34:09 +00:00
t . Errorf ( "lb rule count should be equal to nuber of services deployed, expected (%d) Found (%d)" , index , ruleCount )
2017-11-15 01:39:55 +00:00
}
}
}
2017-11-16 01:34:09 +00:00
// Validate even distribution of external services across load balancers
2017-11-15 01:39:55 +00:00
// based on number of availability sets
func testLoadBalancerServiceAutoModeSelection ( t * testing . T , isInternal bool ) {
az := getTestCloud ( )
const vmCount = 8
const availabilitySetCount = 4
const serviceCount = 9
clusterResources := getClusterResources ( az , vmCount , availabilitySetCount )
getTestSecurityGroup ( az )
for index := 1 ; index <= serviceCount ; index ++ {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
setLoadBalancerAutoModeAnnotation ( & svc )
2018-02-02 21:12:07 +00:00
lbStatus , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
if lbStatus == nil {
t . Errorf ( "Unexpected error: %s" , svcName )
}
2017-11-16 18:23:21 +00:00
// expected is MIN(index, availabilitySetCount)
expectedNumOfLB := int ( math . Min ( float64 ( index ) , float64 ( availabilitySetCount ) ) )
2017-11-15 01:39:55 +00:00
result , _ := az . LoadBalancerClient . List ( az . Config . ResourceGroup )
lbCount := len ( * result . Value )
if lbCount != expectedNumOfLB {
t . Errorf ( "Unexpected number of LB's: Expected (%d) Found (%d)" , expectedNumOfLB , lbCount )
}
maxRules := 0
minRules := serviceCount
2017-11-16 01:34:09 +00:00
for _ , lb := range * result . Value {
2017-11-15 01:39:55 +00:00
ruleCount := len ( * lb . LoadBalancingRules )
if ruleCount < minRules {
minRules = ruleCount
}
if ruleCount > maxRules {
maxRules = ruleCount
}
}
delta := maxRules - minRules
if delta > 1 {
t . Errorf ( "Unexpected min or max rule in LB's in resource group: Service Index (%d) Min (%d) Max(%d)" , index , minRules , maxRules )
}
}
}
// Validate availability set selection of services across load balancers
// based on provided availability sets through service annotation
2017-11-16 18:23:21 +00:00
// The scenario is that there are 4 availability sets in the agent pool but the
// services will be assigned load balancers that are part of the provided availability sets
// specified in service annotation
2017-11-15 01:39:55 +00:00
func testLoadBalancerServicesSpecifiedSelection ( t * testing . T , isInternal bool ) {
az := getTestCloud ( )
const vmCount = 8
const availabilitySetCount = 4
const serviceCount = 9
clusterResources := getClusterResources ( az , vmCount , availabilitySetCount )
getTestSecurityGroup ( az )
2017-11-16 18:23:21 +00:00
selectedAvailabilitySetName1 := getAvailabilitySetName ( az , 1 , availabilitySetCount )
selectedAvailabilitySetName2 := getAvailabilitySetName ( az , 2 , availabilitySetCount )
2017-11-15 01:39:55 +00:00
for index := 1 ; index <= serviceCount ; index ++ {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
lbMode := fmt . Sprintf ( "%s,%s" , selectedAvailabilitySetName1 , selectedAvailabilitySetName2 )
setLoadBalancerModeAnnotation ( & svc , lbMode )
2018-02-02 21:12:07 +00:00
lbStatus , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
if lbStatus == nil {
t . Errorf ( "Unexpected error: %s" , svcName )
}
2017-11-16 18:23:21 +00:00
// expected is MIN(index, 2)
expectedNumOfLB := int ( math . Min ( float64 ( index ) , float64 ( 2 ) ) )
2017-11-15 01:39:55 +00:00
result , _ := az . LoadBalancerClient . List ( az . Config . ResourceGroup )
lbCount := len ( * result . Value )
if lbCount != expectedNumOfLB {
t . Errorf ( "Unexpected number of LB's: Expected (%d) Found (%d)" , expectedNumOfLB , lbCount )
}
}
}
func testLoadBalancerMaxRulesServices ( t * testing . T , isInternal bool ) {
az := getTestCloud ( )
const vmCount = 1
const availabilitySetCount = 1
clusterResources := getClusterResources ( az , vmCount , availabilitySetCount )
getTestSecurityGroup ( az )
az . Config . MaximumLoadBalancerRuleCount = 1
for index := 1 ; index <= az . Config . MaximumLoadBalancerRuleCount ; index ++ {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
2018-02-02 21:12:07 +00:00
lbStatus , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
if lbStatus == nil {
t . Errorf ( "Unexpected error: %s" , svcName )
}
2017-11-16 18:23:21 +00:00
// expected is MIN(index, az.Config.MaximumLoadBalancerRuleCount)
expectedNumOfLBRules := int ( math . Min ( float64 ( index ) , float64 ( az . Config . MaximumLoadBalancerRuleCount ) ) )
2017-11-15 01:39:55 +00:00
result , _ := az . LoadBalancerClient . List ( az . Config . ResourceGroup )
lbCount := len ( * result . Value )
2017-11-16 18:23:21 +00:00
if lbCount != expectedNumOfLBRules {
t . Errorf ( "Unexpected number of LB's: Expected (%d) Found (%d)" , expectedNumOfLBRules , lbCount )
2017-11-15 01:39:55 +00:00
}
}
// validate adding a new service fails since it will exceed the max limit on LB
svcName := fmt . Sprintf ( "service-%d" , az . Config . MaximumLoadBalancerRuleCount + 1 )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
2018-02-02 21:12:07 +00:00
_ , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err == nil {
t . Errorf ( "Expect any new service to fail as max limit in lb has reached" )
2017-11-16 18:23:21 +00:00
} else {
expectedErrMessageSubString := "all available load balancers have exceeded maximum rule limit"
if ! strings . Contains ( err . Error ( ) , expectedErrMessageSubString ) {
t . Errorf ( "Error message returned is not expected, expected sub string=%s, actual error message=%v" , expectedErrMessageSubString , err )
}
2017-11-15 01:39:55 +00:00
}
}
2017-11-16 18:23:21 +00:00
// Validate service deletion in lb auto selection mode
2017-11-15 01:39:55 +00:00
func testLoadBalancerServiceAutoModeDeleteSelection ( t * testing . T , isInternal bool ) {
az := getTestCloud ( )
const vmCount = 8
const availabilitySetCount = 4
const serviceCount = 9
clusterResources := getClusterResources ( az , vmCount , availabilitySetCount )
getTestSecurityGroup ( az )
for index := 1 ; index <= serviceCount ; index ++ {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
setLoadBalancerAutoModeAnnotation ( & svc )
2018-02-02 21:12:07 +00:00
lbStatus , err := az . EnsureLoadBalancer ( context . TODO ( ) , testClusterName , & svc , clusterResources . nodes )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
if lbStatus == nil {
t . Errorf ( "Unexpected error: %s" , svcName )
}
}
for index := serviceCount ; index >= 1 ; index -- {
svcName := fmt . Sprintf ( "service-%d" , index )
var svc v1 . Service
if isInternal {
svc = getInternalTestService ( svcName , 8081 )
addTestSubnet ( t , az , & svc )
} else {
svc = getTestService ( svcName , v1 . ProtocolTCP , 8081 )
}
setLoadBalancerAutoModeAnnotation ( & svc )
2017-11-16 18:23:21 +00:00
// expected is MIN(index, availabilitySetCount)
expectedNumOfLB := int ( math . Min ( float64 ( index ) , float64 ( availabilitySetCount ) ) )
2017-11-15 01:39:55 +00:00
result , _ := az . LoadBalancerClient . List ( az . Config . ResourceGroup )
lbCount := len ( * result . Value )
if lbCount != expectedNumOfLB {
t . Errorf ( "Unexpected number of LB's: Expected (%d) Found (%d)" , expectedNumOfLB , lbCount )
}
2018-02-02 21:12:07 +00:00
err := az . EnsureLoadBalancerDeleted ( context . TODO ( ) , testClusterName , & svc )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
}
}
2017-09-06 04:51:58 +00:00
// Test addition of a new service on an internal LB with a subnet.
func TestReconcileLoadBalancerAddServiceOnInternalSubnet ( t * testing . T ) {
2017-08-30 04:00:21 +00:00
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-09-06 04:51:58 +00:00
svc := getInternalTestService ( "servicea" , 80 )
2017-11-15 01:39:55 +00:00
addTestSubnet ( t , az , & svc )
2017-08-30 04:00:21 +00:00
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-08-30 04:00:21 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
// ensure we got a frontend ip configuration
if len ( * lb . FrontendIPConfigurations ) != 1 {
t . Error ( "Expected the loadbalancer to have a frontend ip configuration" )
}
validateLoadBalancer ( t , lb , svc )
}
2017-11-21 19:28:47 +00:00
func TestReconcileSecurityGroupFromAnyDestinationAddressPrefixToLoadBalancerIP ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "serviceea" , v1 . ProtocolTCP , 80 )
svc1 . Spec . LoadBalancerIP = "192.168.0.0"
sg := getTestSecurityGroup ( az )
// Simulate a pre-Kubernetes 1.8 NSG, where we do not specify the destination address prefix
2017-11-21 20:44:15 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( "" ) , true )
2017-11-21 19:28:47 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 )
}
func TestReconcileSecurityGroupDynamicLoadBalancerIP ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
svc1 . Spec . LoadBalancerIP = ""
sg := getTestSecurityGroup ( az )
dynamicallyAssignedIP := "192.168.0.0"
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( dynamicallyAssignedIP ) , true )
if err != nil {
t . Errorf ( "unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 )
}
2017-08-30 04:00:21 +00:00
// Test addition of services on an internal LB using both default and explicit subnets.
func TestReconcileLoadBalancerAddServicesOnMultipleSubnets ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-08-30 04:00:21 +00:00
svc1 := getTestService ( "service1" , v1 . ProtocolTCP , 8081 )
2017-09-06 04:51:58 +00:00
svc2 := getInternalTestService ( "service2" , 8081 )
2017-08-30 04:00:21 +00:00
2017-11-15 01:39:55 +00:00
// Internal and External service cannot reside on the same LB resource
addTestSubnet ( t , az , & svc2 )
// svc1 is using LB without "-internal" suffix
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc1 , clusterResources . nodes , true /* wantLb */ )
2017-08-30 04:00:21 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling svc1: %q" , err )
}
2017-11-15 01:39:55 +00:00
// ensure we got a frontend ip configuration for each service
if len ( * lb . FrontendIPConfigurations ) != 1 {
t . Error ( "Expected the loadbalancer to have 1 frontend ip configurations" )
2017-08-30 04:00:21 +00:00
}
2017-11-15 01:39:55 +00:00
validateLoadBalancer ( t , lb , svc1 )
// svc2 is using LB with "-internal" suffix
lb , err = az . reconcileLoadBalancer ( testClusterName , & svc2 , nil , true /* wantLb */ )
if err != nil {
t . Errorf ( "Unexpected error reconciling svc2: %q" , err )
2017-08-30 04:00:21 +00:00
}
// ensure we got a frontend ip configuration for each service
2017-11-15 01:39:55 +00:00
if len ( * lb . FrontendIPConfigurations ) != 1 {
t . Error ( "Expected the loadbalancer to have 1 frontend ip configurations" )
2017-08-30 04:00:21 +00:00
}
2017-11-15 01:39:55 +00:00
validateLoadBalancer ( t , lb , svc2 )
2017-08-30 04:00:21 +00:00
}
// Test moving a service exposure from one subnet to another.
func TestReconcileLoadBalancerEditServiceSubnet ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-09-06 04:51:58 +00:00
svc := getInternalTestService ( "service1" , 8081 )
2017-11-15 01:39:55 +00:00
addTestSubnet ( t , az , & svc )
2017-08-30 04:00:21 +00:00
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-08-30 04:00:21 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling initial svc: %q" , err )
}
2017-09-06 04:51:58 +00:00
validateLoadBalancer ( t , lb , svc )
2017-08-30 04:00:21 +00:00
svc . Annotations [ ServiceAnnotationLoadBalancerInternalSubnet ] = "NewSubnet"
2017-11-15 01:39:55 +00:00
addTestSubnet ( t , az , & svc )
2017-08-30 04:00:21 +00:00
2017-11-15 01:39:55 +00:00
lb , err = az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-08-30 04:00:21 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling edits to svc: %q" , err )
}
// ensure we got a frontend ip configuration for the service
if len ( * lb . FrontendIPConfigurations ) != 1 {
t . Error ( "Expected the loadbalancer to have 1 frontend ip configuration" )
}
validateLoadBalancer ( t , lb , svc )
}
2016-08-22 05:53:55 +00:00
func TestReconcileLoadBalancerNodeHealth ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2017-05-07 16:30:40 +00:00
svc . Spec . ExternalTrafficPolicy = v1 . ServiceExternalTrafficPolicyTypeLocal
svc . Spec . HealthCheckNodePort = int32 ( 32456 )
2016-08-22 05:53:55 +00:00
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2016-08-22 05:53:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
// ensure we got a frontend ip configuration
2016-12-07 07:16:53 +00:00
if len ( * lb . FrontendIPConfigurations ) != 1 {
2016-08-22 05:53:55 +00:00
t . Error ( "Expected the loadbalancer to have a frontend ip configuration" )
}
validateLoadBalancer ( t , lb , svc )
}
2016-05-29 03:54:26 +00:00
// Test removing all services results in removing the frontend ip configuration
2017-03-22 05:27:33 +00:00
func TestReconcileLoadBalancerRemoveService ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
2017-03-22 05:27:33 +00:00
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-03-22 05:27:33 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2017-11-15 01:39:55 +00:00
lb , err = az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , false /* wantLb */ )
2017-03-22 05:27:33 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
// ensure we abandoned the frontend ip configuration
if len ( * lb . FrontendIPConfigurations ) != 0 {
t . Error ( "Expected the loadbalancer to have no frontend ip configuration" )
}
validateLoadBalancer ( t , lb )
}
// Test removing all service ports results in removing the frontend ip configuration
2016-05-29 03:54:26 +00:00
func TestReconcileLoadBalancerRemoveAllPortsRemovesFrontendConfig ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2016-05-29 03:54:26 +00:00
2017-11-15 01:39:55 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2017-03-22 05:27:33 +00:00
validateLoadBalancer ( t , lb , svc )
2016-05-29 03:54:26 +00:00
2017-05-08 22:02:41 +00:00
svcUpdated := getTestService ( "servicea" , v1 . ProtocolTCP )
2017-11-15 01:39:55 +00:00
lb , err = az . reconcileLoadBalancer ( testClusterName , & svcUpdated , clusterResources . nodes , false /* wantLb*/ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2016-10-13 21:29:50 +00:00
// ensure we abandoned the frontend ip configuration
2016-12-07 07:16:53 +00:00
if len ( * lb . FrontendIPConfigurations ) != 0 {
2016-05-29 03:54:26 +00:00
t . Error ( "Expected the loadbalancer to have no frontend ip configuration" )
}
validateLoadBalancer ( t , lb , svcUpdated )
}
// Test removal of a port from an existing service.
func TestReconcileLoadBalancerRemovesPort ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2016-05-29 03:54:26 +00:00
2017-11-15 01:39:55 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2016-05-29 03:54:26 +00:00
2017-05-08 22:02:41 +00:00
svcUpdated := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2017-11-15 01:39:55 +00:00
lb , err = az . reconcileLoadBalancer ( testClusterName , & svcUpdated , clusterResources . nodes , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2017-11-15 01:39:55 +00:00
validateLoadBalancer ( t , lb , svcUpdated )
2016-05-29 03:54:26 +00:00
}
// Test reconciliation of multiple services on same port
func TestReconcileLoadBalancerMultipleServices ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-05-08 22:02:41 +00:00
svc1 := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
svc2 := getTestService ( "serviceb" , v1 . ProtocolTCP , 80 )
2016-05-29 03:54:26 +00:00
2017-11-15 01:39:55 +00:00
updatedLoadBalancer , err := az . reconcileLoadBalancer ( testClusterName , & svc1 , clusterResources . nodes , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2017-11-15 01:39:55 +00:00
updatedLoadBalancer , err = az . reconcileLoadBalancer ( testClusterName , & svc2 , clusterResources . nodes , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateLoadBalancer ( t , updatedLoadBalancer , svc1 , svc2 )
}
2017-10-19 21:10:19 +00:00
func findLBRuleForPort ( lbRules [ ] network . LoadBalancingRule , port int32 ) ( network . LoadBalancingRule , error ) {
for _ , lbRule := range lbRules {
if * lbRule . FrontendPort == port {
return lbRule , nil
}
}
return network . LoadBalancingRule { } , fmt . Errorf ( "Expected LB rule with port %d but none found" , port )
}
func TestServiceDefaultsToNoSessionPersistence ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "service-sa-omitted" , v1 . ProtocolTCP , 7170 )
2017-11-20 17:53:34 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-10-19 21:10:19 +00:00
2017-11-20 17:53:34 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-10-19 21:10:19 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling svc1: %q" , err )
}
validateLoadBalancer ( t , lb , svc )
lbRule , err := findLBRuleForPort ( * lb . LoadBalancingRules , 7170 )
if err != nil {
t . Error ( err )
}
if lbRule . LoadDistribution != network . Default {
t . Errorf ( "Expected LB rule to have default load distribution but was %s" , lbRule . LoadDistribution )
}
}
func TestServiceRespectsNoSessionAffinity ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "service-sa-none" , v1 . ProtocolTCP , 7170 )
svc . Spec . SessionAffinity = v1 . ServiceAffinityNone
2017-11-20 17:53:34 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-10-19 21:10:19 +00:00
2017-11-20 17:53:34 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-10-19 21:10:19 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling svc1: %q" , err )
}
validateLoadBalancer ( t , lb , svc )
lbRule , err := findLBRuleForPort ( * lb . LoadBalancingRules , 7170 )
if err != nil {
t . Error ( err )
}
if lbRule . LoadDistribution != network . Default {
t . Errorf ( "Expected LB rule to have default load distribution but was %s" , lbRule . LoadDistribution )
}
}
func TestServiceRespectsClientIPSessionAffinity ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "service-sa-clientip" , v1 . ProtocolTCP , 7170 )
svc . Spec . SessionAffinity = v1 . ServiceAffinityClientIP
2017-11-20 17:53:34 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2017-10-19 21:10:19 +00:00
2017-11-20 17:53:34 +00:00
lb , err := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true /* wantLb */ )
2017-10-19 21:10:19 +00:00
if err != nil {
t . Errorf ( "Unexpected error reconciling svc1: %q" , err )
}
validateLoadBalancer ( t , lb , svc )
lbRule , err := findLBRuleForPort ( * lb . LoadBalancingRules , 7170 )
if err != nil {
t . Error ( err )
}
if lbRule . LoadDistribution != network . SourceIP {
t . Errorf ( "Expected LB rule to have SourceIP load distribution but was %s" , lbRule . LoadDistribution )
}
}
2016-05-29 03:54:26 +00:00
func TestReconcileSecurityGroupNewServiceAddsPort ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
getTestSecurityGroup ( az )
svc1 := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
clusterResources := getClusterResources ( az , 1 , 1 )
lb , _ := az . reconcileLoadBalancer ( testClusterName , & svc1 , clusterResources . nodes , true )
lbStatus , _ := az . getServiceLoadBalancerStatus ( & svc1 , lb )
2016-05-29 03:54:26 +00:00
2017-11-17 01:05:51 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , & lbStatus . Ingress [ 0 ] . IP , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 )
}
2017-03-22 05:27:33 +00:00
func TestReconcileSecurityGroupNewInternalServiceAddsPort ( t * testing . T ) {
az := getTestCloud ( )
2017-11-15 01:39:55 +00:00
getTestSecurityGroup ( az )
2017-03-22 05:27:33 +00:00
svc1 := getInternalTestService ( "serviceea" , 80 )
2017-11-15 01:39:55 +00:00
addTestSubnet ( t , az , & svc1 )
clusterResources := getClusterResources ( az , 1 , 1 )
2017-03-22 05:27:33 +00:00
2017-11-15 01:39:55 +00:00
lb , _ := az . reconcileLoadBalancer ( testClusterName , & svc1 , clusterResources . nodes , true )
lbStatus , _ := az . getServiceLoadBalancerStatus ( & svc1 , lb )
2017-11-17 01:05:51 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , & lbStatus . Ingress [ 0 ] . IP , true /* wantLb */ )
2017-03-22 05:27:33 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 )
}
func TestReconcileSecurityGroupRemoveService ( t * testing . T ) {
2017-11-15 01:39:55 +00:00
az := getTestCloud ( )
2017-05-08 22:02:41 +00:00
service1 := getTestService ( "servicea" , v1 . ProtocolTCP , 81 )
service2 := getTestService ( "serviceb" , v1 . ProtocolTCP , 82 )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
lb , _ := az . reconcileLoadBalancer ( testClusterName , & service1 , clusterResources . nodes , true )
az . reconcileLoadBalancer ( testClusterName , & service2 , clusterResources . nodes , true )
2017-03-22 05:27:33 +00:00
2017-11-15 01:39:55 +00:00
lbStatus , _ := az . getServiceLoadBalancerStatus ( & service1 , lb )
2017-03-22 05:27:33 +00:00
2017-11-15 01:39:55 +00:00
sg := getTestSecurityGroup ( az , service1 , service2 )
2017-03-22 05:27:33 +00:00
validateSecurityGroup ( t , sg , service1 , service2 )
2017-11-15 01:39:55 +00:00
2017-11-17 01:05:51 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & service1 , & lbStatus . Ingress [ 0 ] . IP , false /* wantLb */ )
2017-03-22 05:27:33 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , service2 )
}
2016-05-29 03:54:26 +00:00
func TestReconcileSecurityGroupRemoveServiceRemovesPort ( t * testing . T ) {
az := getTestCloud ( )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2016-05-29 03:54:26 +00:00
2017-11-15 01:39:55 +00:00
sg := getTestSecurityGroup ( az , svc )
2017-05-08 22:02:41 +00:00
svcUpdated := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2017-11-15 01:39:55 +00:00
lb , _ := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true )
lbStatus , _ := az . getServiceLoadBalancerStatus ( & svc , lb )
2017-11-17 01:05:51 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svcUpdated , & lbStatus . Ingress [ 0 ] . IP , true /* wantLb */ )
2016-05-29 03:54:26 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svcUpdated )
}
2016-11-12 06:55:06 +00:00
func TestReconcileSecurityWithSourceRanges ( t * testing . T ) {
az := getTestCloud ( )
2017-05-08 22:02:41 +00:00
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
2016-11-12 06:55:06 +00:00
svc . Spec . LoadBalancerSourceRanges = [ ] string {
2017-05-08 21:49:45 +00:00
"192.168.0.0/24" ,
"10.0.0.0/32" ,
2016-11-12 06:55:06 +00:00
}
2017-11-15 01:39:55 +00:00
clusterResources := getClusterResources ( az , 1 , 1 )
2016-11-12 06:55:06 +00:00
2017-11-15 01:39:55 +00:00
sg := getTestSecurityGroup ( az , svc )
lb , _ := az . reconcileLoadBalancer ( testClusterName , & svc , clusterResources . nodes , true )
lbStatus , _ := az . getServiceLoadBalancerStatus ( & svc , lb )
2017-11-17 01:05:51 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc , & lbStatus . Ingress [ 0 ] . IP , true /* wantLb */ )
2016-11-12 06:55:06 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc )
}
2017-11-15 01:39:55 +00:00
func TestReconcilePublicIPWithNewService ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
2017-11-15 17:41:13 +00:00
pip , err := az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , true )
2017-11-15 17:41:13 +00:00
pip2 , err := az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb */ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
2017-11-16 01:34:09 +00:00
validatePublicIP ( t , pip2 , & svc , true )
2017-11-15 01:39:55 +00:00
if pip . Name != pip2 . Name ||
pip . PublicIPAddressPropertiesFormat . IPAddress != pip2 . PublicIPAddressPropertiesFormat . IPAddress {
t . Errorf ( "We should get the exact same public ip resource after a second reconcile" )
}
}
func TestReconcilePublicIPRemoveService ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "servicea" , v1 . ProtocolTCP , 80 , 443 )
2017-11-15 17:41:13 +00:00
pip , err := az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , true )
// Remove the service
2017-11-15 17:41:13 +00:00
pip , err = az . reconcilePublicIP ( testClusterName , & svc , false /* wantLb */ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , false )
}
func TestReconcilePublicIPWithInternalService ( t * testing . T ) {
az := getTestCloud ( )
svc := getInternalTestService ( "servicea" , 80 , 443 )
2017-11-15 17:41:13 +00:00
pip , err := az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , true )
}
func TestReconcilePublicIPWithExternalAndInternalSwitch ( t * testing . T ) {
az := getTestCloud ( )
svc := getInternalTestService ( "servicea" , 80 , 443 )
2017-11-15 17:41:13 +00:00
pip , err := az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , true )
// Update to external service
svcUpdated := getTestService ( "servicea" , v1 . ProtocolTCP , 80 )
2017-11-15 17:41:13 +00:00
pip , err = az . reconcilePublicIP ( testClusterName , & svcUpdated , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svcUpdated , true )
// Update to internal service again
2017-11-15 17:41:13 +00:00
pip , err = az . reconcilePublicIP ( testClusterName , & svc , true /* wantLb*/ )
2017-11-15 01:39:55 +00:00
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validatePublicIP ( t , pip , & svc , true )
}
func getTestCloud ( ) ( az * Cloud ) {
az = & Cloud {
2016-05-29 03:54:26 +00:00
Config : Config {
2017-12-19 07:18:37 +00:00
AzureAuthConfig : auth . AzureAuthConfig {
TenantID : "tenant" ,
SubscriptionID : "subscription" ,
} ,
2017-11-15 01:39:55 +00:00
ResourceGroup : "rg" ,
VnetResourceGroup : "rg" ,
Location : "westus" ,
VnetName : "vnet" ,
SubnetName : "subnet" ,
SecurityGroupName : "nsg" ,
RouteTableName : "rt" ,
2017-11-16 01:34:09 +00:00
PrimaryAvailabilitySetName : "as" ,
2017-11-15 01:39:55 +00:00
MaximumLoadBalancerRuleCount : 250 ,
2018-03-01 05:48:54 +00:00
VMType : vmTypeStandard ,
2016-05-29 03:54:26 +00:00
} ,
}
2018-01-25 08:14:48 +00:00
az . DisksClient = newFakeDisksClient ( )
az . InterfacesClient = newFakeAzureInterfacesClient ( )
2017-11-16 21:23:45 +00:00
az . LoadBalancerClient = newFakeAzureLBClient ( )
az . PublicIPAddressesClient = newFakeAzurePIPClient ( az . Config . SubscriptionID )
2018-01-25 08:14:48 +00:00
az . RoutesClient = newFakeRoutesClient ( )
az . RouteTablesClient = newFakeRouteTablesClient ( )
2017-11-16 21:23:45 +00:00
az . SecurityGroupsClient = newFakeAzureNSGClient ( )
2018-01-25 08:14:48 +00:00
az . SubnetsClient = newFakeAzureSubnetsClient ( )
2017-12-22 07:10:30 +00:00
az . VirtualMachineScaleSetsClient = newFakeVirtualMachineScaleSetsClient ( )
az . VirtualMachineScaleSetVMsClient = newFakeVirtualMachineScaleSetVMsClient ( )
2018-01-25 08:14:48 +00:00
az . VirtualMachinesClient = newFakeAzureVirtualMachinesClient ( )
2017-12-13 06:21:57 +00:00
az . vmSet = newAvailabilitySet ( az )
2018-02-07 09:06:16 +00:00
az . vmCache , _ = az . newVMCache ( )
2018-02-07 09:19:34 +00:00
az . lbCache , _ = az . newLBCache ( )
2018-02-07 13:57:11 +00:00
az . nsgCache , _ = az . newNSGCache ( )
2018-02-07 14:26:03 +00:00
az . rtCache , _ = az . newRouteTableCache ( )
2017-11-15 01:39:55 +00:00
return az
}
const networkInterfacesIDTemplate = "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/networkInterfaces/%s"
const primaryIPConfigIDTemplate = "%s/ipConfigurations/ipconfig"
2017-11-16 01:34:09 +00:00
// returns the full identifier of Network Interface.
func getNetworkInterfaceID ( subscriptionID string , resourceGroupName , nicName string ) string {
2017-11-15 01:39:55 +00:00
return fmt . Sprintf (
networkInterfacesIDTemplate ,
subscriptionID ,
resourceGroupName ,
nicName )
}
// returns the full identifier of a private ipconfig of the nic
func getPrimaryIPConfigID ( nicID string ) string {
return fmt . Sprintf (
primaryIPConfigIDTemplate ,
nicID )
}
const TestResourceNameFormat = "%s-%d"
const TestVMResourceBaseName = "vm"
const TestASResourceBaseName = "as"
func getTestResourceName ( resourceBaseName string , index int ) string {
return fmt . Sprintf ( TestResourceNameFormat , resourceBaseName , index )
}
func getVMName ( vmIndex int ) string {
return getTestResourceName ( TestVMResourceBaseName , vmIndex )
}
2017-11-16 18:23:21 +00:00
func getAvailabilitySetName ( az * Cloud , vmIndex int , numAS int ) string {
2017-11-15 01:39:55 +00:00
asIndex := vmIndex % numAS
if asIndex == 0 {
return az . Config . PrimaryAvailabilitySetName
}
return getTestResourceName ( TestASResourceBaseName , asIndex )
}
2017-11-16 18:23:21 +00:00
// test supporting on 1 nic per vm
// we really dont care about the name of the nic
// just using the vm name for testing purposes
2017-11-15 01:39:55 +00:00
func getNICName ( vmIndex int ) string {
return getVMName ( vmIndex )
}
type ClusterResources struct {
nodes [ ] * v1 . Node
availabilitySetNames [ ] string
}
func getClusterResources ( az * Cloud , vmCount int , availabilitySetCount int ) ( clusterResources * ClusterResources ) {
if vmCount < availabilitySetCount {
return nil
}
clusterResources = & ClusterResources { }
clusterResources . nodes = [ ] * v1 . Node { }
clusterResources . availabilitySetNames = [ ] string { }
for vmIndex := 0 ; vmIndex < vmCount ; vmIndex ++ {
vmName := getVMName ( vmIndex )
2017-11-16 18:23:21 +00:00
asName := getAvailabilitySetName ( az , vmIndex , availabilitySetCount )
2017-11-15 01:39:55 +00:00
clusterResources . availabilitySetNames = append ( clusterResources . availabilitySetNames , asName )
nicName := getNICName ( vmIndex )
2017-11-16 01:34:09 +00:00
nicID := getNetworkInterfaceID ( az . Config . SubscriptionID , az . Config . ResourceGroup , nicName )
2017-11-15 01:39:55 +00:00
primaryIPConfigID := getPrimaryIPConfigID ( nicID )
isPrimary := true
newNIC := network . Interface {
ID : & nicID ,
Name : & nicName ,
InterfacePropertiesFormat : & network . InterfacePropertiesFormat {
IPConfigurations : & [ ] network . InterfaceIPConfiguration {
{
ID : & primaryIPConfigID ,
InterfaceIPConfigurationPropertiesFormat : & network . InterfaceIPConfigurationPropertiesFormat {
PrivateIPAddress : & nicName ,
Primary : & isPrimary ,
} ,
} ,
} ,
} ,
}
az . InterfacesClient . CreateOrUpdate ( az . Config . ResourceGroup , nicName , newNIC , nil )
// create vm
asID := az . getAvailabilitySetID ( asName )
newVM := compute . VirtualMachine {
Name : & vmName ,
Location : & az . Config . Location ,
VirtualMachineProperties : & compute . VirtualMachineProperties {
AvailabilitySet : & compute . SubResource {
ID : & asID ,
} ,
NetworkProfile : & compute . NetworkProfile {
NetworkInterfaces : & [ ] compute . NetworkInterfaceReference {
{
ID : & nicID ,
} ,
} ,
} ,
} ,
}
_ , errChan := az . VirtualMachinesClient . CreateOrUpdate ( az . Config . ResourceGroup , vmName , newVM , nil )
if err := <- errChan ; err != nil {
}
// add to kubernetes
newNode := & v1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : vmName ,
Labels : map [ string ] string {
kubeletapis . LabelHostname : vmName ,
} ,
} ,
}
clusterResources . nodes = append ( clusterResources . nodes , newNode )
}
return clusterResources
2016-05-29 03:54:26 +00:00
}
func getBackendPort ( port int32 ) int32 {
return port + 10000
}
2017-05-08 22:02:41 +00:00
func getTestService ( identifier string , proto v1 . Protocol , requestedPorts ... int32 ) v1 . Service {
2016-11-18 20:58:42 +00:00
ports := [ ] v1 . ServicePort { }
2016-05-29 03:54:26 +00:00
for _ , port := range requestedPorts {
2016-11-18 20:58:42 +00:00
ports = append ( ports , v1 . ServicePort {
2017-05-08 22:02:41 +00:00
Name : fmt . Sprintf ( "port-tcp-%d" , port ) ,
Protocol : proto ,
2016-05-29 03:54:26 +00:00
Port : port ,
NodePort : getBackendPort ( port ) ,
} )
}
2016-11-18 20:58:42 +00:00
svc := v1 . Service {
Spec : v1 . ServiceSpec {
Type : v1 . ServiceTypeLoadBalancer ,
2016-05-29 03:54:26 +00:00
Ports : ports ,
} ,
}
svc . Name = identifier
svc . Namespace = "default"
svc . UID = types . UID ( identifier )
2017-03-22 05:27:33 +00:00
svc . Annotations = make ( map [ string ] string )
return svc
}
func getInternalTestService ( identifier string , requestedPorts ... int32 ) v1 . Service {
2017-05-08 22:02:41 +00:00
svc := getTestService ( identifier , v1 . ProtocolTCP , requestedPorts ... )
2017-03-22 05:27:33 +00:00
svc . Annotations [ ServiceAnnotationLoadBalancerInternal ] = "true"
2016-05-29 03:54:26 +00:00
return svc
}
2017-11-15 01:39:55 +00:00
func setLoadBalancerModeAnnotation ( service * v1 . Service , lbMode string ) {
service . Annotations [ ServiceAnnotationLoadBalancerMode ] = lbMode
}
func setLoadBalancerAutoModeAnnotation ( service * v1 . Service ) {
setLoadBalancerModeAnnotation ( service , ServiceAnnotationLoadBalancerAutoModeValue )
}
2016-11-18 20:58:42 +00:00
func getServiceSourceRanges ( service * v1 . Service ) [ ] string {
2016-11-12 06:55:06 +00:00
if len ( service . Spec . LoadBalancerSourceRanges ) == 0 {
2017-03-22 05:27:33 +00:00
if ! requiresInternalLoadBalancer ( service ) {
return [ ] string { "Internet" }
}
2016-11-12 06:55:06 +00:00
}
2017-03-22 05:27:33 +00:00
2016-11-12 06:55:06 +00:00
return service . Spec . LoadBalancerSourceRanges
}
2017-11-15 01:39:55 +00:00
func getTestSecurityGroup ( az * Cloud , services ... v1 . Service ) * network . SecurityGroup {
2016-05-29 03:54:26 +00:00
rules := [ ] network . SecurityRule { }
for _ , service := range services {
for _ , port := range service . Spec . Ports {
2016-11-12 06:55:06 +00:00
sources := getServiceSourceRanges ( & service )
for _ , src := range sources {
2017-05-08 21:49:45 +00:00
ruleName := getSecurityRuleName ( & service , port , src )
2016-11-12 06:55:06 +00:00
rules = append ( rules , network . SecurityRule {
Name : to . StringPtr ( ruleName ) ,
2016-12-07 07:16:53 +00:00
SecurityRulePropertiesFormat : & network . SecurityRulePropertiesFormat {
2016-11-12 06:55:06 +00:00
SourceAddressPrefix : to . StringPtr ( src ) ,
DestinationPortRange : to . StringPtr ( fmt . Sprintf ( "%d" , port . Port ) ) ,
} ,
} )
}
2016-05-29 03:54:26 +00:00
}
}
sg := network . SecurityGroup {
2017-11-15 01:39:55 +00:00
Name : & az . SecurityGroupName ,
2016-12-07 07:16:53 +00:00
SecurityGroupPropertiesFormat : & network . SecurityGroupPropertiesFormat {
2016-05-29 03:54:26 +00:00
SecurityRules : & rules ,
} ,
}
2017-11-15 01:39:55 +00:00
az . SecurityGroupsClient . CreateOrUpdate (
az . ResourceGroup ,
az . SecurityGroupName ,
sg ,
nil )
return & sg
2016-05-29 03:54:26 +00:00
}
2017-11-15 01:39:55 +00:00
func validateLoadBalancer ( t * testing . T , loadBalancer * network . LoadBalancer , services ... v1 . Service ) {
2016-05-29 03:54:26 +00:00
expectedRuleCount := 0
2017-03-22 05:27:33 +00:00
expectedFrontendIPCount := 0
2017-05-08 22:02:41 +00:00
expectedProbeCount := 0
2017-09-06 04:51:58 +00:00
expectedFrontendIPs := [ ] ExpectedFrontendIPInfo { }
2016-05-29 03:54:26 +00:00
for _ , svc := range services {
2017-03-22 05:27:33 +00:00
if len ( svc . Spec . Ports ) > 0 {
expectedFrontendIPCount ++
2017-09-06 04:51:58 +00:00
expectedFrontendIP := ExpectedFrontendIPInfo {
Name : getFrontendIPConfigName ( & svc , subnet ( & svc ) ) ,
Subnet : subnet ( & svc ) ,
}
expectedFrontendIPs = append ( expectedFrontendIPs , expectedFrontendIP )
2017-03-22 05:27:33 +00:00
}
2016-05-29 03:54:26 +00:00
for _ , wantedRule := range svc . Spec . Ports {
expectedRuleCount ++
2017-08-30 04:00:21 +00:00
wantedRuleName := getLoadBalancerRuleName ( & svc , wantedRule , subnet ( & svc ) )
2016-05-29 03:54:26 +00:00
foundRule := false
2016-12-07 07:16:53 +00:00
for _ , actualRule := range * loadBalancer . LoadBalancingRules {
2016-05-29 03:54:26 +00:00
if strings . EqualFold ( * actualRule . Name , wantedRuleName ) &&
2016-12-07 07:16:53 +00:00
* actualRule . FrontendPort == wantedRule . Port &&
* actualRule . BackendPort == wantedRule . Port {
2016-05-29 03:54:26 +00:00
foundRule = true
break
}
}
if ! foundRule {
2016-08-25 08:43:43 +00:00
t . Errorf ( "Expected load balancer rule but didn't find it: %q" , wantedRuleName )
2016-05-29 03:54:26 +00:00
}
2017-05-08 22:02:41 +00:00
// if UDP rule, there is no probe
if wantedRule . Protocol == v1 . ProtocolUDP {
continue
}
expectedProbeCount ++
2016-05-29 03:54:26 +00:00
foundProbe := false
2016-08-22 05:53:55 +00:00
if serviceapi . NeedsHealthCheck ( & svc ) {
path , port := serviceapi . GetServiceHealthCheckPathPort ( & svc )
2016-12-07 07:16:53 +00:00
for _ , actualProbe := range * loadBalancer . Probes {
2016-08-22 05:53:55 +00:00
if strings . EqualFold ( * actualProbe . Name , wantedRuleName ) &&
2016-12-07 07:16:53 +00:00
* actualProbe . Port == port &&
* actualProbe . RequestPath == path &&
actualProbe . Protocol == network . ProbeProtocolHTTP {
2016-08-22 05:53:55 +00:00
foundProbe = true
break
}
}
} else {
2016-12-07 07:16:53 +00:00
for _ , actualProbe := range * loadBalancer . Probes {
2016-08-22 05:53:55 +00:00
if strings . EqualFold ( * actualProbe . Name , wantedRuleName ) &&
2016-12-07 07:16:53 +00:00
* actualProbe . Port == wantedRule . NodePort {
2016-08-22 05:53:55 +00:00
foundProbe = true
break
}
2016-05-29 03:54:26 +00:00
}
}
if ! foundProbe {
2016-12-07 07:16:53 +00:00
for _ , actualProbe := range * loadBalancer . Probes {
t . Logf ( "Probe: %s %d" , * actualProbe . Name , * actualProbe . Port )
2016-08-22 05:53:55 +00:00
}
2016-08-25 08:43:43 +00:00
t . Errorf ( "Expected loadbalancer probe but didn't find it: %q" , wantedRuleName )
2016-05-29 03:54:26 +00:00
}
}
}
2017-03-22 05:27:33 +00:00
frontendIPCount := len ( * loadBalancer . FrontendIPConfigurations )
if frontendIPCount != expectedFrontendIPCount {
t . Errorf ( "Expected the loadbalancer to have %d frontend IPs. Found %d.\n%v" , expectedFrontendIPCount , frontendIPCount , loadBalancer . FrontendIPConfigurations )
}
2017-09-06 04:51:58 +00:00
frontendIPs := * loadBalancer . FrontendIPConfigurations
for _ , expectedFrontendIP := range expectedFrontendIPs {
if ! expectedFrontendIP . existsIn ( frontendIPs ) {
t . Errorf ( "Expected the loadbalancer to have frontend IP %s/%s. Found %s" , expectedFrontendIP . Name , to . String ( expectedFrontendIP . Subnet ) , describeFIPs ( frontendIPs ) )
}
}
2016-12-07 07:16:53 +00:00
lenRules := len ( * loadBalancer . LoadBalancingRules )
2016-05-29 03:54:26 +00:00
if lenRules != expectedRuleCount {
2016-12-07 07:16:53 +00:00
t . Errorf ( "Expected the loadbalancer to have %d rules. Found %d.\n%v" , expectedRuleCount , lenRules , loadBalancer . LoadBalancingRules )
2016-05-29 03:54:26 +00:00
}
2017-05-08 22:02:41 +00:00
2016-12-07 07:16:53 +00:00
lenProbes := len ( * loadBalancer . Probes )
2017-05-08 22:02:41 +00:00
if lenProbes != expectedProbeCount {
2016-05-29 03:54:26 +00:00
t . Errorf ( "Expected the loadbalancer to have %d probes. Found %d." , expectedRuleCount , lenProbes )
}
}
2017-09-06 04:51:58 +00:00
type ExpectedFrontendIPInfo struct {
Name string
Subnet * string
}
func ( expected ExpectedFrontendIPInfo ) matches ( frontendIP network . FrontendIPConfiguration ) bool {
return strings . EqualFold ( expected . Name , to . String ( frontendIP . Name ) ) && strings . EqualFold ( to . String ( expected . Subnet ) , to . String ( subnetName ( frontendIP ) ) )
}
func ( expected ExpectedFrontendIPInfo ) existsIn ( frontendIPs [ ] network . FrontendIPConfiguration ) bool {
for _ , fip := range frontendIPs {
if expected . matches ( fip ) {
return true
}
}
return false
}
func subnetName ( frontendIP network . FrontendIPConfiguration ) * string {
if frontendIP . Subnet != nil {
return frontendIP . Subnet . Name
}
return nil
}
func describeFIPs ( frontendIPs [ ] network . FrontendIPConfiguration ) string {
description := ""
for _ , actualFIP := range frontendIPs {
actualSubnetName := ""
if actualFIP . Subnet != nil {
actualSubnetName = to . String ( actualFIP . Subnet . Name )
}
actualFIPText := fmt . Sprintf ( "%s/%s " , to . String ( actualFIP . Name ) , actualSubnetName )
description = description + actualFIPText
}
return description
}
2017-11-15 17:41:13 +00:00
func validatePublicIP ( t * testing . T , publicIP * network . PublicIPAddress , service * v1 . Service , wantLb bool ) {
2017-11-15 01:39:55 +00:00
isInternal := requiresInternalLoadBalancer ( service )
2017-11-15 17:41:13 +00:00
if isInternal || ! wantLb {
2017-11-15 01:39:55 +00:00
if publicIP != nil {
t . Errorf ( "Expected publicIP resource to be nil, when it is an internal service or doesn't want LB" )
}
return
}
// For external service
if publicIP == nil {
t . Errorf ( "Expected publicIP resource exists, when it is not an internal service" )
}
if publicIP . Tags == nil || ( * publicIP . Tags ) [ "service" ] == nil {
t . Errorf ( "Expected publicIP resource has tags[service]" )
}
serviceName := getServiceName ( service )
if serviceName != * ( * publicIP . Tags ) [ "service" ] {
t . Errorf ( "Expected publicIP resource has matching tags[service]" )
}
// We cannot use service.Spec.LoadBalancerIP to compare with
// Public IP's IPAddress
2018-02-09 06:53:53 +00:00
// Because service properties are updated outside of cloudprovider code
2017-11-15 01:39:55 +00:00
}
2017-11-17 01:05:51 +00:00
func contains ( ruleValues [ ] string , targetValue string ) bool {
for _ , ruleValue := range ruleValues {
if strings . EqualFold ( ruleValue , targetValue ) {
return true
}
}
return false
}
func securityRuleMatches ( serviceSourceRange string , servicePort v1 . ServicePort , serviceIP string , securityRule network . SecurityRule ) error {
ruleSource := securityRule . SourceAddressPrefixes
if ruleSource == nil || len ( * ruleSource ) == 0 {
if securityRule . SourceAddressPrefix == nil {
ruleSource = & [ ] string { }
} else {
ruleSource = & [ ] string { * securityRule . SourceAddressPrefix }
}
}
rulePorts := securityRule . DestinationPortRanges
if rulePorts == nil || len ( * rulePorts ) == 0 {
if securityRule . DestinationPortRange == nil {
rulePorts = & [ ] string { }
} else {
rulePorts = & [ ] string { * securityRule . DestinationPortRange }
}
}
ruleDestination := securityRule . DestinationAddressPrefixes
if ruleDestination == nil || len ( * ruleDestination ) == 0 {
if securityRule . DestinationAddressPrefix == nil {
ruleDestination = & [ ] string { }
} else {
ruleDestination = & [ ] string { * securityRule . DestinationAddressPrefix }
}
}
if ! contains ( * ruleSource , serviceSourceRange ) {
return fmt . Errorf ( "Rule does not contain source %s" , serviceSourceRange )
}
if ! contains ( * rulePorts , fmt . Sprintf ( "%d" , servicePort . Port ) ) {
return fmt . Errorf ( "Rule does not contain port %d" , servicePort . Port )
}
if serviceIP != "" && ! contains ( * ruleDestination , serviceIP ) {
return fmt . Errorf ( "Rule does not contain destination %s" , serviceIP )
}
return nil
}
2017-11-15 01:39:55 +00:00
func validateSecurityGroup ( t * testing . T , securityGroup * network . SecurityGroup , services ... v1 . Service ) {
2017-11-17 01:05:51 +00:00
seenRules := make ( map [ string ] string )
2016-05-29 03:54:26 +00:00
for _ , svc := range services {
for _ , wantedRule := range svc . Spec . Ports {
2016-11-12 06:55:06 +00:00
sources := getServiceSourceRanges ( & svc )
for _ , source := range sources {
2017-05-08 21:49:45 +00:00
wantedRuleName := getSecurityRuleName ( & svc , wantedRule , source )
2017-11-17 01:05:51 +00:00
seenRules [ wantedRuleName ] = wantedRuleName
2016-11-12 06:55:06 +00:00
foundRule := false
2016-12-07 07:16:53 +00:00
for _ , actualRule := range * securityGroup . SecurityRules {
2017-11-17 01:05:51 +00:00
if strings . EqualFold ( * actualRule . Name , wantedRuleName ) {
err := securityRuleMatches ( source , wantedRule , svc . Spec . LoadBalancerIP , actualRule )
if err != nil {
t . Errorf ( "Found matching security rule %q but properties were incorrect: %v" , wantedRuleName , err )
}
2016-11-12 06:55:06 +00:00
foundRule = true
break
}
}
if ! foundRule {
t . Errorf ( "Expected security group rule but didn't find it: %q" , wantedRuleName )
2016-05-29 03:54:26 +00:00
}
}
}
}
2016-12-07 07:16:53 +00:00
lenRules := len ( * securityGroup . SecurityRules )
2017-11-17 01:05:51 +00:00
expectedRuleCount := len ( seenRules )
2016-05-29 03:54:26 +00:00
if lenRules != expectedRuleCount {
2016-11-12 06:55:06 +00:00
t . Errorf ( "Expected the loadbalancer to have %d rules. Found %d.\n" , expectedRuleCount , lenRules )
2016-05-29 03:54:26 +00:00
}
}
func TestSecurityRulePriorityPicksNextAvailablePriority ( t * testing . T ) {
rules := [ ] network . SecurityRule { }
var expectedPriority int32 = loadBalancerMinimumPriority + 50
var i int32
for i = loadBalancerMinimumPriority ; i < expectedPriority ; i ++ {
rules = append ( rules , network . SecurityRule {
2016-12-07 07:16:53 +00:00
SecurityRulePropertiesFormat : & network . SecurityRulePropertiesFormat {
2016-05-29 03:54:26 +00:00
Priority : to . Int32Ptr ( i ) ,
} ,
} )
}
priority , err := getNextAvailablePriority ( rules )
if err != nil {
t . Errorf ( "Unexpectected error: %q" , err )
}
if priority != expectedPriority {
t . Errorf ( "Expected priority %d. Got priority %d." , expectedPriority , priority )
}
}
func TestSecurityRulePriorityFailsIfExhausted ( t * testing . T ) {
rules := [ ] network . SecurityRule { }
var i int32
for i = loadBalancerMinimumPriority ; i < loadBalancerMaximumPriority ; i ++ {
rules = append ( rules , network . SecurityRule {
2016-12-07 07:16:53 +00:00
SecurityRulePropertiesFormat : & network . SecurityRulePropertiesFormat {
2016-05-29 03:54:26 +00:00
Priority : to . Int32Ptr ( i ) ,
} ,
} )
}
_ , err := getNextAvailablePriority ( rules )
if err == nil {
t . Error ( "Expectected an error. There are no priority levels left." )
}
}
func TestProtocolTranslationTCP ( t * testing . T ) {
2016-11-18 20:58:42 +00:00
proto := v1 . ProtocolTCP
2016-05-29 03:54:26 +00:00
transportProto , securityGroupProto , probeProto , err := getProtocolsFromKubernetesProtocol ( proto )
if err != nil {
t . Error ( err )
}
2017-05-08 21:49:45 +00:00
if * transportProto != network . TransportProtocolTCP {
2016-05-29 03:54:26 +00:00
t . Errorf ( "Expected TCP LoadBalancer Rule Protocol. Got %v" , transportProto )
}
2017-06-09 05:20:01 +00:00
if * securityGroupProto != network . SecurityRuleProtocolTCP {
2016-05-29 03:54:26 +00:00
t . Errorf ( "Expected TCP SecurityGroup Protocol. Got %v" , transportProto )
}
2017-05-08 21:49:45 +00:00
if * probeProto != network . ProbeProtocolTCP {
2016-05-29 03:54:26 +00:00
t . Errorf ( "Expected TCP LoadBalancer Probe Protocol. Got %v" , transportProto )
}
}
func TestProtocolTranslationUDP ( t * testing . T ) {
2016-11-18 20:58:42 +00:00
proto := v1 . ProtocolUDP
2017-05-08 21:49:45 +00:00
transportProto , securityGroupProto , probeProto , _ := getProtocolsFromKubernetesProtocol ( proto )
if * transportProto != network . TransportProtocolUDP {
t . Errorf ( "Expected UDP LoadBalancer Rule Protocol. Got %v" , transportProto )
}
2017-06-09 05:20:01 +00:00
if * securityGroupProto != network . SecurityRuleProtocolUDP {
2017-05-08 21:49:45 +00:00
t . Errorf ( "Expected UDP SecurityGroup Protocol. Got %v" , transportProto )
}
if probeProto != nil {
t . Errorf ( "Expected UDP LoadBalancer Probe Protocol. Got %v" , transportProto )
2016-05-29 03:54:26 +00:00
}
}
// Test Configuration deserialization (json)
func TestNewCloudFromJSON ( t * testing . T ) {
config := ` {
"tenantId" : "--tenant-id--" ,
"subscriptionId" : "--subscription-id--" ,
"aadClientId" : "--aad-client-id--" ,
"aadClientSecret" : "--aad-client-secret--" ,
2017-06-14 11:28:23 +00:00
"aadClientCertPath" : "--aad-client-cert-path--" ,
"aadClientCertPassword" : "--aad-client-cert-password--" ,
2016-05-29 03:54:26 +00:00
"resourceGroup" : "--resource-group--" ,
"location" : "--location--" ,
"subnetName" : "--subnet-name--" ,
"securityGroupName" : "--security-group-name--" ,
"vnetName" : "--vnet-name--" ,
2016-10-07 06:59:14 +00:00
"routeTableName" : "--route-table-name--" ,
2017-06-05 23:06:50 +00:00
"primaryAvailabilitySetName" : "--primary-availability-set-name--" ,
"cloudProviderBackoff" : true ,
"cloudProviderRatelimit" : true ,
2017-06-07 05:21:14 +00:00
"cloudProviderRateLimitQPS" : 0.5 ,
2017-06-05 23:06:50 +00:00
"cloudProviderRateLimitBucket" : 5
2016-05-29 03:54:26 +00:00
} `
validateConfig ( t , config )
}
2017-06-06 16:50:28 +00:00
// Test Backoff and Rate Limit defaults (json)
func TestCloudDefaultConfigFromJSON ( t * testing . T ) {
2017-06-10 07:03:02 +00:00
config := ` {
"aadClientId" : "--aad-client-id--" ,
"aadClientSecret" : "--aad-client-secret--"
} `
2017-06-06 16:50:28 +00:00
validateEmptyConfig ( t , config )
}
// Test Backoff and Rate Limit defaults (yaml)
func TestCloudDefaultConfigFromYAML ( t * testing . T ) {
2017-06-10 07:03:02 +00:00
config := `
aadClientId : -- aad - client - id --
aadClientSecret : -- aad - client - secret --
`
2017-06-06 16:50:28 +00:00
validateEmptyConfig ( t , config )
}
2016-05-29 03:54:26 +00:00
// Test Configuration deserialization (yaml)
func TestNewCloudFromYAML ( t * testing . T ) {
config := `
tenantId : -- tenant - id --
subscriptionId : -- subscription - id --
aadClientId : -- aad - client - id --
aadClientSecret : -- aad - client - secret --
2017-06-08 13:05:11 +00:00
aadClientCertPath : -- aad - client - cert - path --
aadClientCertPassword : -- aad - client - cert - password --
2016-05-29 03:54:26 +00:00
resourceGroup : -- resource - group --
location : -- location --
subnetName : -- subnet - name --
securityGroupName : -- security - group - name --
vnetName : -- vnet - name --
routeTableName : -- route - table - name --
2016-10-07 06:59:14 +00:00
primaryAvailabilitySetName : -- primary - availability - set - name --
2017-06-05 23:06:50 +00:00
cloudProviderBackoff : true
cloudProviderBackoffRetries : 6
cloudProviderBackoffExponent : 1.5
cloudProviderBackoffDuration : 5
cloudProviderBackoffJitter : 1.0
cloudProviderRatelimit : true
2017-06-07 05:21:14 +00:00
cloudProviderRateLimitQPS : 0.5
2017-06-05 23:06:50 +00:00
cloudProviderRateLimitBucket : 5
2016-05-29 03:54:26 +00:00
`
validateConfig ( t , config )
}
func validateConfig ( t * testing . T , config string ) {
2017-06-06 16:50:28 +00:00
azureCloud := getCloudFromConfig ( t , config )
2016-05-29 03:54:26 +00:00
if azureCloud . TenantID != "--tenant-id--" {
t . Errorf ( "got incorrect value for TenantID" )
}
if azureCloud . SubscriptionID != "--subscription-id--" {
t . Errorf ( "got incorrect value for SubscriptionID" )
}
if azureCloud . AADClientID != "--aad-client-id--" {
t . Errorf ( "got incorrect value for AADClientID" )
}
if azureCloud . AADClientSecret != "--aad-client-secret--" {
t . Errorf ( "got incorrect value for AADClientSecret" )
}
2017-06-08 13:05:11 +00:00
if azureCloud . AADClientCertPath != "--aad-client-cert-path--" {
t . Errorf ( "got incorrect value for AADClientCertPath" )
}
if azureCloud . AADClientCertPassword != "--aad-client-cert-password--" {
t . Errorf ( "got incorrect value for AADClientCertPassword" )
}
2016-05-29 03:54:26 +00:00
if azureCloud . ResourceGroup != "--resource-group--" {
t . Errorf ( "got incorrect value for ResourceGroup" )
}
if azureCloud . Location != "--location--" {
t . Errorf ( "got incorrect value for Location" )
}
if azureCloud . SubnetName != "--subnet-name--" {
t . Errorf ( "got incorrect value for SubnetName" )
}
if azureCloud . SecurityGroupName != "--security-group-name--" {
t . Errorf ( "got incorrect value for SecurityGroupName" )
}
if azureCloud . VnetName != "--vnet-name--" {
t . Errorf ( "got incorrect value for VnetName" )
}
if azureCloud . RouteTableName != "--route-table-name--" {
t . Errorf ( "got incorrect value for RouteTableName" )
}
2016-10-07 06:59:14 +00:00
if azureCloud . PrimaryAvailabilitySetName != "--primary-availability-set-name--" {
t . Errorf ( "got incorrect value for PrimaryAvailabilitySetName" )
}
2017-06-05 23:06:50 +00:00
if azureCloud . CloudProviderBackoff != true {
t . Errorf ( "got incorrect value for CloudProviderBackoff" )
}
if azureCloud . CloudProviderBackoffRetries != 6 {
t . Errorf ( "got incorrect value for CloudProviderBackoffRetries" )
}
if azureCloud . CloudProviderBackoffExponent != 1.5 {
t . Errorf ( "got incorrect value for CloudProviderBackoffExponent" )
}
if azureCloud . CloudProviderBackoffDuration != 5 {
t . Errorf ( "got incorrect value for CloudProviderBackoffDuration" )
}
if azureCloud . CloudProviderBackoffJitter != 1.0 {
t . Errorf ( "got incorrect value for CloudProviderBackoffJitter" )
}
if azureCloud . CloudProviderRateLimit != true {
t . Errorf ( "got incorrect value for CloudProviderRateLimit" )
}
2017-06-07 05:21:14 +00:00
if azureCloud . CloudProviderRateLimitQPS != 0.5 {
2017-06-05 23:06:50 +00:00
t . Errorf ( "got incorrect value for CloudProviderRateLimitQPS" )
}
if azureCloud . CloudProviderRateLimitBucket != 5 {
t . Errorf ( "got incorrect value for CloudProviderRateLimitBucket" )
}
2016-05-29 03:54:26 +00:00
}
2017-06-06 16:50:28 +00:00
func getCloudFromConfig ( t * testing . T , config string ) * Cloud {
configReader := strings . NewReader ( config )
cloud , err := NewCloud ( configReader )
if err != nil {
t . Error ( err )
}
azureCloud , ok := cloud . ( * Cloud )
if ! ok {
t . Error ( "NewCloud returned incorrect type" )
}
return azureCloud
}
// TODO include checks for other appropriate default config parameters
func validateEmptyConfig ( t * testing . T , config string ) {
azureCloud := getCloudFromConfig ( t , config )
// backoff should be disabled by default if not explicitly enabled in config
if azureCloud . CloudProviderBackoff != false {
t . Errorf ( "got incorrect value for CloudProviderBackoff" )
}
// rate limits should be disabled by default if not explicitly enabled in config
if azureCloud . CloudProviderRateLimit != false {
t . Errorf ( "got incorrect value for CloudProviderRateLimit" )
}
}
2018-01-24 22:20:45 +00:00
func TestGetZone ( t * testing . T ) {
data := ` { "ID":"_azdev","UD":"0","FD":"99"} `
ts := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , data )
} ) )
defer ts . Close ( )
cloud := & Cloud { }
cloud . Location = "eastus"
zone , err := cloud . getZoneFromURL ( ts . URL )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if zone . FailureDomain != "99" {
t . Errorf ( "Unexpected value: %s, expected '99'" , zone . FailureDomain )
}
if zone . Region != cloud . Location {
t . Errorf ( "Expected: %s, saw: %s" , cloud . Location , zone . Region )
}
}
func TestFetchFaultDomain ( t * testing . T ) {
ts := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , ` { "ID":"_azdev","UD":"0","FD":"99"} ` )
} ) )
defer ts . Close ( )
faultDomain , err := fetchFaultDomain ( ts . URL )
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if faultDomain == nil {
t . Errorf ( "Unexpected nil fault domain" )
}
if * faultDomain != "99" {
t . Errorf ( "Expected '99', saw '%s'" , * faultDomain )
}
}
2017-06-06 16:50:28 +00:00
2016-05-29 03:54:26 +00:00
func TestDecodeInstanceInfo ( t * testing . T ) {
response := ` { "ID":"_azdev","UD":"0","FD":"99"} `
faultDomain , err := readFaultDomain ( strings . NewReader ( response ) )
if err != nil {
2018-01-24 22:20:45 +00:00
t . Errorf ( "Unexpected error in ReadFaultDomain: %v" , err )
2016-05-29 03:54:26 +00:00
}
if faultDomain == nil {
t . Error ( "Fault domain was unexpectedly nil" )
}
if * faultDomain != "99" {
t . Error ( "got incorrect fault domain" )
}
}
2017-05-31 21:19:38 +00:00
2017-12-13 06:21:57 +00:00
func TestGetNodeNameByProviderID ( t * testing . T ) {
az := getTestCloud ( )
2017-05-31 21:19:38 +00:00
providers := [ ] struct {
providerID string
name types . NodeName
fail bool
} {
{
providerID : CloudProviderName + ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0" ,
2017-08-30 04:20:58 +00:00
name : "k8s-agent-AAAAAAAA-0" ,
2017-05-31 21:19:38 +00:00
fail : false ,
} ,
{
providerID : CloudProviderName + ":/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0" ,
name : "" ,
fail : true ,
} ,
{
providerID : CloudProviderName + "://" ,
name : "" ,
fail : true ,
} ,
{
providerID : ":///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0" ,
name : "" ,
fail : true ,
} ,
{
providerID : "aws:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroupName/providers/Microsoft.Compute/virtualMachines/k8s-agent-AAAAAAAA-0" ,
name : "" ,
fail : true ,
} ,
}
for _ , test := range providers {
2017-12-13 06:21:57 +00:00
name , err := az . vmSet . GetNodeNameByProviderID ( test . providerID )
2017-05-31 21:19:38 +00:00
if ( err != nil ) != test . fail {
t . Errorf ( "Expected to failt=%t, with pattern %v" , test . fail , test )
}
if test . fail {
continue
}
if name != test . name {
t . Errorf ( "Expected %v, but got %v" , test . name , name )
}
}
}
2017-06-29 05:52:10 +00:00
2018-02-08 04:40:35 +00:00
func TestMetadataURLGeneration ( t * testing . T ) {
metadata := NewInstanceMetadata ( )
fullPath := metadata . makeMetadataURL ( "some/path" )
if fullPath != "http://169.254.169.254/metadata/some/path" {
t . Errorf ( "Expected http://169.254.169.254/metadata/some/path saw %s" , fullPath )
}
}
func TestMetadataParsing ( t * testing . T ) {
data := `
{
"interface" : [
{
"ipv4" : {
"ipAddress" : [
{
"privateIpAddress" : "10.0.1.4" ,
"publicIpAddress" : "X.X.X.X"
}
] ,
"subnet" : [
{
"address" : "10.0.1.0" ,
"prefix" : "24"
}
]
} ,
"ipv6" : {
"ipAddress" : [
]
} ,
"macAddress" : "002248020E1E"
}
]
}
`
network := NetworkMetadata { }
if err := json . Unmarshal ( [ ] byte ( data ) , & network ) ; err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
ip := network . Interface [ 0 ] . IPV4 . IPAddress [ 0 ] . PrivateIP
if ip != "10.0.1.4" {
t . Errorf ( "Unexpected value: %s, expected 10.0.1.4" , ip )
}
server := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , data )
} ) )
defer server . Close ( )
metadata := & InstanceMetadata {
baseURL : server . URL ,
}
networkJSON := NetworkMetadata { }
if err := metadata . Object ( "/some/path" , & networkJSON ) ; err != nil {
t . Errorf ( "Unexpected error: %v" , err )
}
if ! reflect . DeepEqual ( network , networkJSON ) {
t . Errorf ( "Unexpected inequality:\n%#v\nvs\n%#v" , network , networkJSON )
}
}
2017-11-15 01:39:55 +00:00
func addTestSubnet ( t * testing . T , az * Cloud , svc * v1 . Service ) {
2017-09-06 04:51:58 +00:00
if svc . Annotations [ ServiceAnnotationLoadBalancerInternal ] != "true" {
t . Error ( "Subnet added to non-internal service" )
}
2017-11-15 01:39:55 +00:00
subName := svc . Annotations [ ServiceAnnotationLoadBalancerInternalSubnet ]
if subName == "" {
subName = az . SubnetName
}
subnetID := fmt . Sprintf ( "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s" ,
az . SubscriptionID ,
az . VnetResourceGroup ,
az . VnetName ,
subName )
_ , errChan := az . SubnetsClient . CreateOrUpdate ( az . VnetResourceGroup , az . VnetName , subName ,
network . Subnet {
ID : & subnetID ,
Name : & subName ,
} , nil )
if err := <- errChan ; err != nil {
t . Errorf ( "Subnet cannot be created or update, %v" , err )
}
svc . Annotations [ ServiceAnnotationLoadBalancerInternalSubnet ] = subName
2017-08-30 04:00:21 +00:00
}
2017-11-17 01:05:51 +00:00
func TestIfServiceSpecifiesSharedRuleAndRuleDoesNotExistItIsCreated ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "servicesr" , v1 . ProtocolTCP , 80 )
svc . Spec . LoadBalancerIP = "192.168.77.88"
svc . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc , to . StringPtr ( svc . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc )
expectedRuleName := "shared-TCP-80-Internet"
_ , securityRule , ruleFound := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName )
if ! ruleFound {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 80 } , "192.168.77.88" , securityRule )
if err != nil {
t . Errorf ( "Shared rule was not updated with new service IP: %v" , err )
}
if securityRule . Priority == nil {
t . Errorf ( "Shared rule %s had no priority" , expectedRuleName )
}
if securityRule . Access != network . SecurityRuleAccessAllow {
t . Errorf ( "Shared rule %s did not have Allow access" , expectedRuleName )
}
if securityRule . Direction != network . SecurityRuleDirectionInbound {
t . Errorf ( "Shared rule %s did not have Inbound direction" , expectedRuleName )
}
}
func TestIfServiceSpecifiesSharedRuleAndRuleExistsThenTheServicesPortAndAddressAreAdded ( t * testing . T ) {
az := getTestCloud ( )
svc := getTestService ( "servicesr" , v1 . ProtocolTCP , 80 )
svc . Spec . LoadBalancerIP = "192.168.77.88"
svc . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName := "shared-TCP-80-Internet"
sg := getTestSecurityGroup ( az )
sg . SecurityRules = & [ ] network . SecurityRule {
{
Name : & expectedRuleName ,
SecurityRulePropertiesFormat : & network . SecurityRulePropertiesFormat {
Protocol : network . SecurityRuleProtocolTCP ,
SourcePortRange : to . StringPtr ( "*" ) ,
SourceAddressPrefix : to . StringPtr ( "Internet" ) ,
DestinationPortRange : to . StringPtr ( "80" ) ,
DestinationAddressPrefix : to . StringPtr ( "192.168.33.44" ) ,
Access : network . SecurityRuleAccessAllow ,
Direction : network . SecurityRuleDirectionInbound ,
} ,
} ,
}
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc , to . StringPtr ( svc . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error: %q" , err )
}
validateSecurityGroup ( t , sg , svc )
_ , securityRule , ruleFound := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName )
if ! ruleFound {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName )
}
expectedDestinationIPCount := 2
if len ( * securityRule . DestinationAddressPrefixes ) != expectedDestinationIPCount {
t . Errorf ( "Shared rule should have had %d destination IP addresses but had %d" , expectedDestinationIPCount , len ( * securityRule . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 80 } , "192.168.33.44" , securityRule )
if err != nil {
t . Errorf ( "Shared rule no longer matched other service IP: %v" , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 80 } , "192.168.77.88" , securityRule )
if err != nil {
t . Errorf ( "Shared rule was not updated with new service IP: %v" , err )
}
}
func TestIfServicesSpecifySharedRuleButDifferentPortsThenSeparateRulesAreCreated ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 8888 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName1 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-TCP-8888-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 )
_ , securityRule1 , rule1Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName1 )
if ! rule1Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName1 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount1 := 1
if len ( * securityRule1 . DestinationAddressPrefixes ) != expectedDestinationIPCount1 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName1 , expectedDestinationIPCount1 , len ( * securityRule1 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule1 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName1 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule1 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName1 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
}
func TestIfServicesSpecifySharedRuleButDifferentProtocolsThenSeparateRulesAreCreated ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolUDP , 4444 )
svc2 . Spec . LoadBalancerIP = "192.168.77.88"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName1 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-UDP-4444-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 )
_ , securityRule1 , rule1Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName1 )
if ! rule1Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName1 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount1 := 1
if len ( * securityRule1 . DestinationAddressPrefixes ) != expectedDestinationIPCount1 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName1 , expectedDestinationIPCount1 , len ( * securityRule1 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule1 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName1 , err )
}
if securityRule1 . Protocol != network . SecurityRuleProtocolTCP {
t . Errorf ( "Shared rule %s should have been %s but was %s" , expectedRuleName1 , network . SecurityRuleProtocolTCP , securityRule1 . Protocol )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
if securityRule2 . Protocol != network . SecurityRuleProtocolUDP {
t . Errorf ( "Shared rule %s should have been %s but was %s" , expectedRuleName2 , network . SecurityRuleProtocolUDP , securityRule2 . Protocol )
}
}
func TestIfServicesSpecifySharedRuleButDifferentSourceAddressesThenSeparateRulesAreCreated ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 80 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Spec . LoadBalancerSourceRanges = [ ] string { "192.168.12.0/24" }
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 80 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Spec . LoadBalancerSourceRanges = [ ] string { "192.168.34.0/24" }
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName1 := "shared-TCP-80-192.168.12.0_24"
expectedRuleName2 := "shared-TCP-80-192.168.34.0_24"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 )
_ , securityRule1 , rule1Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName1 )
if ! rule1Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName1 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount1 := 1
if len ( * securityRule1 . DestinationAddressPrefixes ) != expectedDestinationIPCount1 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName1 , expectedDestinationIPCount1 , len ( * securityRule1 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( svc1 . Spec . LoadBalancerSourceRanges [ 0 ] , v1 . ServicePort { Port : 80 } , "192.168.77.88" , securityRule1 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName1 , err )
}
err = securityRuleMatches ( svc2 . Spec . LoadBalancerSourceRanges [ 0 ] , v1 . ServicePort { Port : 80 } , "192.168.33.44" , securityRule1 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName1 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( svc2 . Spec . LoadBalancerSourceRanges [ 0 ] , v1 . ServicePort { Port : 80 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( svc1 . Spec . LoadBalancerSourceRanges [ 0 ] , v1 . ServicePort { Port : 80 } , "192.168.77.88" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
}
func TestIfServicesSpecifySharedRuleButSomeAreOnDifferentPortsThenRulesAreSeparatedOrConsoliatedByPort ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 8888 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc3 := getTestService ( "servicesr3" , v1 . ProtocolTCP , 4444 )
svc3 . Spec . LoadBalancerIP = "192.168.99.11"
svc3 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName13 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-TCP-8888-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc3 , to . StringPtr ( svc3 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc3: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 , svc3 )
_ , securityRule13 , rule13Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName13 )
if ! rule13Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName13 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount13 := 2
if len ( * securityRule13 . DestinationAddressPrefixes ) != expectedDestinationIPCount13 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName13 , expectedDestinationIPCount13 , len ( * securityRule13 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule13 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName13 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule13 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName13 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule13 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName13 )
}
if securityRule13 . Priority == nil {
t . Errorf ( "Shared rule %s had no priority" , expectedRuleName13 )
}
if securityRule13 . Access != network . SecurityRuleAccessAllow {
t . Errorf ( "Shared rule %s did not have Allow access" , expectedRuleName13 )
}
if securityRule13 . Direction != network . SecurityRuleDirectionInbound {
t . Errorf ( "Shared rule %s did not have Inbound direction" , expectedRuleName13 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
}
func TestIfServiceSpecifiesSharedRuleAndServiceIsDeletedThenTheServicesPortAndAddressAreRemoved ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 80 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 80 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName := "shared-TCP-80-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 )
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc1: %q" , err )
}
validateSecurityGroup ( t , sg , svc2 )
_ , securityRule , ruleFound := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName )
if ! ruleFound {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName )
}
expectedDestinationIPCount := 1
if len ( * securityRule . DestinationAddressPrefixes ) != expectedDestinationIPCount {
t . Errorf ( "Shared rule should have had %d destination IP addresses but had %d" , expectedDestinationIPCount , len ( * securityRule . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 80 } , "192.168.33.44" , securityRule )
if err != nil {
t . Errorf ( "Shared rule no longer matched other service IP: %v" , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 80 } , "192.168.77.88" , securityRule )
if err == nil {
t . Error ( "Shared rule was not updated to remove deleted service IP" )
}
}
func TestIfSomeServicesShareARuleAndOneIsDeletedItIsRemovedFromTheRightRule ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 8888 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc3 := getTestService ( "servicesr3" , v1 . ProtocolTCP , 4444 )
svc3 . Spec . LoadBalancerIP = "192.168.99.11"
svc3 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName13 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-TCP-8888-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc3 , to . StringPtr ( svc3 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc3: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 , svc3 )
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc1: %q" , err )
}
validateSecurityGroup ( t , sg , svc2 , svc3 )
_ , securityRule13 , rule13Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName13 )
if ! rule13Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName13 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount13 := 1
if len ( * securityRule13 . DestinationAddressPrefixes ) != expectedDestinationIPCount13 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName13 , expectedDestinationIPCount13 , len ( * securityRule13 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule13 )
if err == nil {
t . Errorf ( "Shared rule %s should have had svc1 removed but did not" , expectedRuleName13 )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule13 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName13 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule13 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName13 )
}
if securityRule13 . Priority == nil {
t . Errorf ( "Shared rule %s had no priority" , expectedRuleName13 )
}
if securityRule13 . Access != network . SecurityRuleAccessAllow {
t . Errorf ( "Shared rule %s did not have Allow access" , expectedRuleName13 )
}
if securityRule13 . Direction != network . SecurityRuleDirectionInbound {
t . Errorf ( "Shared rule %s did not have Inbound direction" , expectedRuleName13 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
}
func TestIfServiceSpecifiesSharedRuleAndLastServiceIsDeletedThenRuleIsDeleted ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 8888 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc3 := getTestService ( "servicesr3" , v1 . ProtocolTCP , 4444 )
svc3 . Spec . LoadBalancerIP = "192.168.99.11"
svc3 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
expectedRuleName13 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-TCP-8888-Internet"
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc3 , to . StringPtr ( svc3 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc3: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 , svc3 )
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc3 , to . StringPtr ( svc3 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc3: %q" , err )
}
validateSecurityGroup ( t , sg , svc2 )
_ , _ , rule13Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName13 )
if rule13Found {
t . Fatalf ( "Expected security rule %q to have been deleted but it was still present" , expectedRuleName13 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong service's port and IP" , expectedRuleName2 )
}
}
func TestCanCombineSharedAndPrivateRulesInSameGroup ( t * testing . T ) {
az := getTestCloud ( )
svc1 := getTestService ( "servicesr1" , v1 . ProtocolTCP , 4444 )
svc1 . Spec . LoadBalancerIP = "192.168.77.88"
svc1 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc2 := getTestService ( "servicesr2" , v1 . ProtocolTCP , 8888 )
svc2 . Spec . LoadBalancerIP = "192.168.33.44"
svc2 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc3 := getTestService ( "servicesr3" , v1 . ProtocolTCP , 4444 )
svc3 . Spec . LoadBalancerIP = "192.168.99.11"
svc3 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "true"
svc4 := getTestService ( "servicesr4" , v1 . ProtocolTCP , 4444 )
svc4 . Spec . LoadBalancerIP = "192.168.22.33"
svc4 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "false"
svc5 := getTestService ( "servicesr5" , v1 . ProtocolTCP , 8888 )
svc5 . Spec . LoadBalancerIP = "192.168.22.33"
svc5 . Annotations [ ServiceAnnotationSharedSecurityRule ] = "false"
expectedRuleName13 := "shared-TCP-4444-Internet"
expectedRuleName2 := "shared-TCP-8888-Internet"
expectedRuleName4 := getSecurityRuleName ( & svc4 , v1 . ServicePort { Port : 4444 , Protocol : v1 . ProtocolTCP } , "Internet" )
expectedRuleName5 := getSecurityRuleName ( & svc5 , v1 . ServicePort { Port : 8888 , Protocol : v1 . ProtocolTCP } , "Internet" )
sg := getTestSecurityGroup ( az )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc2 , to . StringPtr ( svc2 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc2: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc3 , to . StringPtr ( svc3 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc3: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc4 , to . StringPtr ( svc4 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc4: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc5 , to . StringPtr ( svc5 . Spec . LoadBalancerIP ) , true )
if err != nil {
t . Errorf ( "Unexpected error adding svc4: %q" , err )
}
validateSecurityGroup ( t , sg , svc1 , svc2 , svc3 , svc4 , svc5 )
expectedRuleCount := 4
if len ( * sg . SecurityRules ) != expectedRuleCount {
t . Errorf ( "Expected security group to have %d rules but it had %d" , expectedRuleCount , len ( * sg . SecurityRules ) )
}
_ , securityRule13 , rule13Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName13 )
if ! rule13Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName13 )
}
_ , securityRule2 , rule2Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
_ , securityRule4 , rule4Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName4 )
if ! rule4Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName4 )
}
_ , securityRule5 , rule5Found := findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName5 )
if ! rule5Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName5 )
}
expectedDestinationIPCount13 := 2
if len ( * securityRule13 . DestinationAddressPrefixes ) != expectedDestinationIPCount13 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName13 , expectedDestinationIPCount13 , len ( * securityRule13 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.77.88" , securityRule13 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName13 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.99.11" , securityRule13 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName13 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 4444 } , "192.168.22.33" , securityRule13 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong (unshared) service's port and IP" , expectedRuleName13 )
}
expectedDestinationIPCount2 := 1
if len ( * securityRule2 . DestinationAddressPrefixes ) != expectedDestinationIPCount2 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName2 , expectedDestinationIPCount2 , len ( * securityRule2 . DestinationAddressPrefixes ) )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.33.44" , securityRule2 )
if err != nil {
t . Errorf ( "Shared rule %s did not match service IP: %v" , expectedRuleName2 , err )
}
err = securityRuleMatches ( "Internet" , v1 . ServicePort { Port : 8888 } , "192.168.22.33" , securityRule2 )
if err == nil {
t . Errorf ( "Shared rule %s matched wrong (unshared) service's port and IP" , expectedRuleName2 )
}
if securityRule4 . DestinationAddressPrefixes != nil {
t . Errorf ( "Expected unshared rule %s to use single destination IP address but used collection" , expectedRuleName4 )
}
if securityRule4 . DestinationAddressPrefix == nil {
t . Errorf ( "Expected unshared rule %s to have a destination IP address" , expectedRuleName4 )
} else {
if ! strings . EqualFold ( * securityRule4 . DestinationAddressPrefix , svc4 . Spec . LoadBalancerIP ) {
t . Errorf ( "Expected unshared rule %s to have a destination %s but had %s" , expectedRuleName4 , svc4 . Spec . LoadBalancerIP , * securityRule4 . DestinationAddressPrefix )
}
}
if securityRule5 . DestinationAddressPrefixes != nil {
t . Errorf ( "Expected unshared rule %s to use single destination IP address but used collection" , expectedRuleName5 )
}
if securityRule5 . DestinationAddressPrefix == nil {
t . Errorf ( "Expected unshared rule %s to have a destination IP address" , expectedRuleName5 )
} else {
if ! strings . EqualFold ( * securityRule5 . DestinationAddressPrefix , svc5 . Spec . LoadBalancerIP ) {
t . Errorf ( "Expected unshared rule %s to have a destination %s but had %s" , expectedRuleName5 , svc5 . Spec . LoadBalancerIP , * securityRule5 . DestinationAddressPrefix )
}
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc1 , to . StringPtr ( svc1 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc1: %q" , err )
}
sg , err = az . reconcileSecurityGroup ( testClusterName , & svc5 , to . StringPtr ( svc5 . Spec . LoadBalancerIP ) , false )
if err != nil {
t . Errorf ( "Unexpected error removing svc5: %q" , err )
}
_ , securityRule13 , rule13Found = findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName13 )
if ! rule13Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName13 )
}
_ , securityRule2 , rule2Found = findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName2 )
if ! rule2Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName2 )
}
_ , securityRule4 , rule4Found = findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName4 )
if ! rule4Found {
t . Fatalf ( "Expected security rule %q but it was not present" , expectedRuleName4 )
}
_ , _ , rule5Found = findSecurityRuleByName ( * sg . SecurityRules , expectedRuleName5 )
if rule5Found {
t . Fatalf ( "Expected security rule %q to have been removed but it was not present" , expectedRuleName5 )
}
expectedDestinationIPCount13 = 1
if len ( * securityRule13 . DestinationAddressPrefixes ) != expectedDestinationIPCount13 {
t . Errorf ( "Shared rule %s should have had %d destination IP addresses but had %d" , expectedRuleName13 , expectedDestinationIPCount13 , len ( * securityRule13 . DestinationAddressPrefixes ) )
}
}
// TODO: sanity check if the same IP address incorrectly gets put in twice?
// (shouldn't happen but...)
// func TestIfServiceIsEditedFromOwnRuleToSharedRuleThenOwnRuleIsDeletedAndSharedRuleIsCreated(t *testing.T) {
// t.Error()
// }
// func TestIfServiceIsEditedFromSharedRuleToOwnRuleThenItIsRemovedFromSharedRuleAndOwnRuleIsCreated(t *testing.T) {
// t.Error()
// }