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 (
2017-06-29 05:52:10 +00:00
"encoding/json"
2016-05-29 03:54:26 +00:00
"fmt"
2017-11-16 18:23:21 +00:00
"math"
2017-06-29 05:52:10 +00:00
"net/http"
"net/http/httptest"
"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"
2017-11-15 01:39:55 +00:00
"k8s.io/client-go/util/flowcontrol"
2016-11-18 20:58:42 +00:00
serviceapi "k8s.io/kubernetes/pkg/api/v1/service"
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 )
}
lbStatus , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
lbStatus , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
lbStatus , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
}
lbStatus , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
}
_ , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
lbStatus , err := az . EnsureLoadBalancer ( testClusterName , & svc , clusterResources . nodes )
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 )
}
err := az . EnsureLoadBalancerDeleted ( testClusterName , & svc )
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 )
}
// 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 )
configProperties := getTestPublicFipConfigurationProperties ( )
lb := getTestLoadBalancer ( )
nodes := [ ] * v1 . Node { }
lb , _ , err := az . reconcileLoadBalancer ( lb , & configProperties , testClusterName , & svc , nodes )
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
configProperties := getTestPublicFipConfigurationProperties ( )
lb := getTestLoadBalancer ( )
nodes := [ ] * v1 . Node { }
lb , _ , err := az . reconcileLoadBalancer ( lb , & configProperties , testClusterName , & svc , nodes )
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
configProperties := getTestPublicFipConfigurationProperties ( )
lb := getTestLoadBalancer ( )
nodes := [ ] * v1 . Node { }
lb , _ , err := az . reconcileLoadBalancer ( lb , & configProperties , testClusterName , & svc , nodes )
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-15 01:39:55 +00:00
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , lbStatus , 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 )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc1 , lbStatus , 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
sg , err := az . reconcileSecurityGroup ( testClusterName , & service1 , lbStatus , 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 )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svcUpdated , lbStatus , 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 )
sg , err := az . reconcileSecurityGroup ( testClusterName , & svc , lbStatus , 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-11-15 01:39:55 +00:00
TenantID : "tenant" ,
SubscriptionID : "subscription" ,
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 ,
2016-05-29 03:54:26 +00:00
} ,
}
2017-11-15 01:39:55 +00:00
az . operationPollRateLimiter = flowcontrol . NewTokenBucketRateLimiter ( 100 , 100 )
2017-11-16 21:23:45 +00:00
az . LoadBalancerClient = newFakeAzureLBClient ( )
az . PublicIPAddressesClient = newFakeAzurePIPClient ( az . Config . SubscriptionID )
az . SubnetsClient = newFakeAzureSubnetsClient ( )
az . SecurityGroupsClient = newFakeAzureNSGClient ( )
az . VirtualMachinesClient = newFakeAzureVirtualMachinesClient ( )
az . InterfacesClient = newFakeAzureInterfacesClient ( )
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-03-16 08:30:40 +00:00
func getTestPublicFipConfigurationProperties ( ) network . FrontendIPConfigurationPropertiesFormat {
return network . FrontendIPConfigurationPropertiesFormat {
PublicIPAddress : & network . PublicIPAddress { ID : to . StringPtr ( "/this/is/a/public/ip/address/id" ) } ,
}
2016-05-29 03:54:26 +00:00
}
2017-09-06 04:51:58 +00:00
func getTestInternalFipConfigurationProperties ( expectedSubnetName * string ) network . FrontendIPConfigurationPropertiesFormat {
var expectedSubnet * network . Subnet
if expectedSubnetName != nil {
expectedSubnet = & network . Subnet { Name : expectedSubnetName }
}
return network . FrontendIPConfigurationPropertiesFormat {
PublicIPAddress : & network . PublicIPAddress { ID : to . StringPtr ( "/this/is/a/public/ip/address/id" ) } ,
Subnet : expectedSubnet ,
}
}
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 getTestLoadBalancer ( services ... v1 . Service ) network . LoadBalancer {
2016-05-29 03:54:26 +00:00
rules := [ ] network . LoadBalancingRule { }
probes := [ ] network . Probe { }
for _ , service := range services {
for _ , port := range service . Spec . Ports {
2017-08-30 04:00:21 +00:00
ruleName := getLoadBalancerRuleName ( & service , port , nil )
2016-05-29 03:54:26 +00:00
rules = append ( rules , network . LoadBalancingRule {
Name : to . StringPtr ( ruleName ) ,
2016-12-07 07:16:53 +00:00
LoadBalancingRulePropertiesFormat : & network . LoadBalancingRulePropertiesFormat {
2016-05-29 03:54:26 +00:00
FrontendPort : to . Int32Ptr ( port . Port ) ,
2016-08-25 08:43:43 +00:00
BackendPort : to . Int32Ptr ( port . Port ) ,
2016-05-29 03:54:26 +00:00
} ,
} )
probes = append ( probes , network . Probe {
Name : to . StringPtr ( ruleName ) ,
2016-12-07 07:16:53 +00:00
ProbePropertiesFormat : & network . ProbePropertiesFormat {
2016-05-29 03:54:26 +00:00
Port : to . Int32Ptr ( port . NodePort ) ,
} ,
} )
}
}
lb := network . LoadBalancer {
2016-12-07 07:16:53 +00:00
LoadBalancerPropertiesFormat : & network . LoadBalancerPropertiesFormat {
2016-05-29 03:54:26 +00:00
LoadBalancingRules : & rules ,
Probes : & probes ,
} ,
}
return lb
}
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
// Becuase service properties are updated outside of cloudprovider code
}
func validateSecurityGroup ( t * testing . T , securityGroup * network . SecurityGroup , services ... v1 . Service ) {
2016-05-29 03:54:26 +00:00
expectedRuleCount := 0
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 )
2016-11-12 06:55:06 +00:00
expectedRuleCount ++
foundRule := false
2016-12-07 07:16:53 +00:00
for _ , actualRule := range * securityGroup . SecurityRules {
2016-11-12 06:55:06 +00:00
if strings . EqualFold ( * actualRule . Name , wantedRuleName ) &&
2016-12-07 07:16:53 +00:00
* actualRule . SourceAddressPrefix == source &&
* actualRule . DestinationPortRange == fmt . Sprintf ( "%d" , wantedRule . Port ) {
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 )
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" )
}
}
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 {
t . Error ( "Unexpected error in ReadFaultDomain" )
}
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
func TestSplitProviderID ( t * testing . T ) {
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 {
name , err := splitProviderID ( test . providerID )
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
2017-07-19 17:44:41 +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 )
}
}
2017-06-29 05:52:10 +00:00
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 ( )
2017-07-19 17:44:41 +00:00
metadata := & InstanceMetadata {
baseURL : server . URL ,
}
2017-06-29 05:52:10 +00:00
networkJSON := NetworkMetadata { }
2017-07-19 13:57:45 +00:00
if err := metadata . Object ( "/some/path" , & networkJSON ) ; err != nil {
2017-06-29 05:52:10 +00:00
t . Errorf ( "Unexpected error: %v" , err )
}
if ! reflect . DeepEqual ( network , networkJSON ) {
t . Errorf ( "Unexpected inequality:\n%#v\nvs\n%#v" , network , networkJSON )
}
}
2017-08-30 04:00:21 +00:00
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
}