2016-05-29 23:05:38 +00:00
|
|
|
/*
|
2016-09-08 11:02:39 +00:00
|
|
|
Copyright 2016 The Kubernetes Authors.
|
2016-05-29 23:05:38 +00:00
|
|
|
|
|
|
|
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 controller
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
2016-09-22 21:56:50 +00:00
|
|
|
"time"
|
2016-05-29 23:05:38 +00:00
|
|
|
|
2017-07-16 19:30:20 +00:00
|
|
|
api_v1 "k8s.io/api/core/v1"
|
2017-04-01 14:38:58 +00:00
|
|
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2017-04-18 19:44:17 +00:00
|
|
|
"k8s.io/ingress/controllers/gce/backends"
|
|
|
|
"k8s.io/ingress/controllers/gce/utils"
|
2016-05-29 23:05:38 +00:00
|
|
|
)
|
|
|
|
|
2016-09-22 21:56:50 +00:00
|
|
|
// Pods created in loops start from this time, for routines that
|
|
|
|
// sort on timestamp.
|
|
|
|
var firstPodCreationTime = time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)
|
|
|
|
|
2016-05-29 23:05:38 +00:00
|
|
|
func TestZoneListing(t *testing.T) {
|
2017-02-15 00:48:07 +00:00
|
|
|
cm := NewFakeClusterManager(DefaultClusterUID, DefaultFirewallName)
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc := newLoadBalancerController(t, cm)
|
2016-05-29 23:05:38 +00:00
|
|
|
zoneToNode := map[string][]string{
|
|
|
|
"zone-1": {"n1"},
|
|
|
|
"zone-2": {"n2"},
|
|
|
|
}
|
|
|
|
addNodes(lbc, zoneToNode)
|
|
|
|
zones, err := lbc.tr.ListZones()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Failed to list zones: %v", err)
|
|
|
|
}
|
|
|
|
for expectedZone := range zoneToNode {
|
|
|
|
found := false
|
|
|
|
for _, gotZone := range zones {
|
|
|
|
if gotZone == expectedZone {
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
t.Fatalf("Expected zones %v; Got zones %v", zoneToNode, zones)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInstancesAddedToZones(t *testing.T) {
|
2017-02-15 00:48:07 +00:00
|
|
|
cm := NewFakeClusterManager(DefaultClusterUID, DefaultFirewallName)
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc := newLoadBalancerController(t, cm)
|
2016-05-29 23:05:38 +00:00
|
|
|
zoneToNode := map[string][]string{
|
|
|
|
"zone-1": {"n1", "n2"},
|
|
|
|
"zone-2": {"n3"},
|
|
|
|
}
|
|
|
|
addNodes(lbc, zoneToNode)
|
|
|
|
|
|
|
|
// Create 2 igs, one per zone.
|
|
|
|
testIG := "test-ig"
|
|
|
|
testPort := int64(3001)
|
|
|
|
lbc.CloudClusterManager.instancePool.AddInstanceGroup(testIG, testPort)
|
|
|
|
|
|
|
|
// node pool syncs kube-nodes, this will add them to both igs.
|
|
|
|
lbc.CloudClusterManager.instancePool.Sync([]string{"n1", "n2", "n3"})
|
|
|
|
gotZonesToNode := cm.fakeIGs.GetInstancesByZone()
|
|
|
|
|
|
|
|
i := 0
|
|
|
|
for z, nodeNames := range zoneToNode {
|
|
|
|
if ig, err := cm.fakeIGs.GetInstanceGroup(testIG, z); err != nil {
|
|
|
|
t.Errorf("Failed to find ig %v in zone %v, found %+v: %v", testIG, z, ig, err)
|
|
|
|
}
|
|
|
|
if cm.fakeIGs.Ports[i] != testPort {
|
|
|
|
t.Errorf("Expected the same node port on all igs, got ports %+v", cm.fakeIGs.Ports)
|
|
|
|
}
|
|
|
|
expNodes := sets.NewString(nodeNames...)
|
|
|
|
gotNodes := sets.NewString(gotZonesToNode[z]...)
|
|
|
|
if !gotNodes.Equal(expNodes) {
|
|
|
|
t.Errorf("Nodes not added to zones, expected %+v got %+v", expNodes, gotNodes)
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProbeGetter(t *testing.T) {
|
2017-02-15 00:48:07 +00:00
|
|
|
cm := NewFakeClusterManager(DefaultClusterUID, DefaultFirewallName)
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc := newLoadBalancerController(t, cm)
|
2017-04-18 19:44:17 +00:00
|
|
|
|
|
|
|
nodePortToHealthCheck := map[backends.ServicePort]string{
|
|
|
|
{Port: 3001, Protocol: utils.ProtocolHTTP}: "/healthz",
|
|
|
|
{Port: 3002, Protocol: utils.ProtocolHTTPS}: "/foo",
|
2016-05-29 23:05:38 +00:00
|
|
|
}
|
2017-04-01 14:38:58 +00:00
|
|
|
addPods(lbc, nodePortToHealthCheck, api_v1.NamespaceDefault)
|
2016-09-22 21:56:50 +00:00
|
|
|
for p, exp := range nodePortToHealthCheck {
|
2017-04-18 19:44:17 +00:00
|
|
|
got, err := lbc.tr.GetProbe(p)
|
|
|
|
if err != nil || got == nil {
|
|
|
|
t.Errorf("Failed to get probe for node port %v: %v", p, err)
|
|
|
|
} else if getProbePath(got) != exp {
|
|
|
|
t.Errorf("Wrong path for node port %v, got %v expected %v", p, getProbePath(got), exp)
|
2016-09-22 21:56:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-27 22:22:44 +00:00
|
|
|
func TestProbeGetterNamedPort(t *testing.T) {
|
2017-02-15 00:48:07 +00:00
|
|
|
cm := NewFakeClusterManager(DefaultClusterUID, DefaultFirewallName)
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc := newLoadBalancerController(t, cm)
|
2017-04-18 19:44:17 +00:00
|
|
|
nodePortToHealthCheck := map[backends.ServicePort]string{
|
|
|
|
{Port: 3001, Protocol: utils.ProtocolHTTP}: "/healthz",
|
2017-01-27 22:22:44 +00:00
|
|
|
}
|
2017-04-01 14:38:58 +00:00
|
|
|
addPods(lbc, nodePortToHealthCheck, api_v1.NamespaceDefault)
|
2017-01-27 22:22:44 +00:00
|
|
|
for _, p := range lbc.podLister.Indexer.List() {
|
2017-04-01 14:38:58 +00:00
|
|
|
pod := p.(*api_v1.Pod)
|
2017-01-27 22:22:44 +00:00
|
|
|
pod.Spec.Containers[0].Ports[0].Name = "test"
|
|
|
|
pod.Spec.Containers[0].ReadinessProbe.Handler.HTTPGet.Port = intstr.IntOrString{Type: intstr.String, StrVal: "test"}
|
|
|
|
}
|
|
|
|
for p, exp := range nodePortToHealthCheck {
|
2017-04-18 19:44:17 +00:00
|
|
|
got, err := lbc.tr.GetProbe(p)
|
|
|
|
if err != nil || got == nil {
|
|
|
|
t.Errorf("Failed to get probe for node port %v: %v", p, err)
|
|
|
|
} else if getProbePath(got) != exp {
|
|
|
|
t.Errorf("Wrong path for node port %v, got %v expected %v", p, getProbePath(got), exp)
|
2017-01-27 22:22:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-09-22 21:56:50 +00:00
|
|
|
func TestProbeGetterCrossNamespace(t *testing.T) {
|
2017-02-15 00:48:07 +00:00
|
|
|
cm := NewFakeClusterManager(DefaultClusterUID, DefaultFirewallName)
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc := newLoadBalancerController(t, cm)
|
2016-09-22 21:56:50 +00:00
|
|
|
|
2017-04-01 14:38:58 +00:00
|
|
|
firstPod := &api_v1.Pod{
|
|
|
|
ObjectMeta: meta_v1.ObjectMeta{
|
2016-09-22 21:56:50 +00:00
|
|
|
// labels match those added by "addPods", but ns and health check
|
|
|
|
// path is different. If this pod was created in the same ns, it
|
|
|
|
// would become the health check.
|
|
|
|
Labels: map[string]string{"app-3001": "test"},
|
|
|
|
Name: fmt.Sprintf("test-pod-new-ns"),
|
|
|
|
Namespace: "new-ns",
|
2017-04-01 14:38:58 +00:00
|
|
|
CreationTimestamp: meta_v1.NewTime(firstPodCreationTime.Add(-time.Duration(time.Hour))),
|
2016-09-22 21:56:50 +00:00
|
|
|
},
|
2017-04-01 14:38:58 +00:00
|
|
|
Spec: api_v1.PodSpec{
|
|
|
|
Containers: []api_v1.Container{
|
2016-09-22 21:56:50 +00:00
|
|
|
{
|
2017-04-01 14:38:58 +00:00
|
|
|
Ports: []api_v1.ContainerPort{{ContainerPort: 80}},
|
|
|
|
ReadinessProbe: &api_v1.Probe{
|
|
|
|
Handler: api_v1.Handler{
|
|
|
|
HTTPGet: &api_v1.HTTPGetAction{
|
|
|
|
Scheme: api_v1.URISchemeHTTP,
|
2016-09-22 21:56:50 +00:00
|
|
|
Path: "/badpath",
|
|
|
|
Port: intstr.IntOrString{
|
|
|
|
Type: intstr.Int,
|
|
|
|
IntVal: 80,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
lbc.podLister.Indexer.Add(firstPod)
|
2017-04-18 19:44:17 +00:00
|
|
|
nodePortToHealthCheck := map[backends.ServicePort]string{
|
|
|
|
{Port: 3001, Protocol: utils.ProtocolHTTP}: "/healthz",
|
2016-09-22 21:56:50 +00:00
|
|
|
}
|
2017-04-01 14:38:58 +00:00
|
|
|
addPods(lbc, nodePortToHealthCheck, api_v1.NamespaceDefault)
|
2016-09-22 21:56:50 +00:00
|
|
|
|
2016-05-29 23:05:38 +00:00
|
|
|
for p, exp := range nodePortToHealthCheck {
|
2017-04-18 19:44:17 +00:00
|
|
|
got, err := lbc.tr.GetProbe(p)
|
|
|
|
if err != nil || got == nil {
|
|
|
|
t.Errorf("Failed to get probe for node port %v: %v", p, err)
|
|
|
|
} else if getProbePath(got) != exp {
|
|
|
|
t.Errorf("Wrong path for node port %v, got %v expected %v", p, getProbePath(got), exp)
|
2016-05-29 23:05:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-18 19:44:17 +00:00
|
|
|
func addPods(lbc *LoadBalancerController, nodePortToHealthCheck map[backends.ServicePort]string, ns string) {
|
2016-09-22 21:56:50 +00:00
|
|
|
delay := time.Minute
|
2016-05-29 23:05:38 +00:00
|
|
|
for np, u := range nodePortToHealthCheck {
|
2017-04-18 19:44:17 +00:00
|
|
|
l := map[string]string{fmt.Sprintf("app-%d", np.Port): "test"}
|
2017-04-01 14:38:58 +00:00
|
|
|
svc := &api_v1.Service{
|
|
|
|
Spec: api_v1.ServiceSpec{
|
2016-05-29 23:05:38 +00:00
|
|
|
Selector: l,
|
2017-04-01 14:38:58 +00:00
|
|
|
Ports: []api_v1.ServicePort{
|
2016-05-29 23:05:38 +00:00
|
|
|
{
|
2017-04-18 19:44:17 +00:00
|
|
|
NodePort: int32(np.Port),
|
2016-05-29 23:05:38 +00:00
|
|
|
TargetPort: intstr.IntOrString{
|
|
|
|
Type: intstr.Int,
|
|
|
|
IntVal: 80,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2017-04-18 19:44:17 +00:00
|
|
|
svc.Name = fmt.Sprintf("%d", np.Port)
|
2016-09-22 21:56:50 +00:00
|
|
|
svc.Namespace = ns
|
2016-11-10 23:31:49 +00:00
|
|
|
lbc.svcLister.Indexer.Add(svc)
|
2016-05-29 23:05:38 +00:00
|
|
|
|
2017-04-01 14:38:58 +00:00
|
|
|
pod := &api_v1.Pod{
|
|
|
|
ObjectMeta: meta_v1.ObjectMeta{
|
2016-09-22 21:56:50 +00:00
|
|
|
Labels: l,
|
2017-04-18 19:44:17 +00:00
|
|
|
Name: fmt.Sprintf("%d", np.Port),
|
2016-09-22 21:56:50 +00:00
|
|
|
Namespace: ns,
|
2017-04-01 14:38:58 +00:00
|
|
|
CreationTimestamp: meta_v1.NewTime(firstPodCreationTime.Add(delay)),
|
2016-05-29 23:05:38 +00:00
|
|
|
},
|
2017-04-01 14:38:58 +00:00
|
|
|
Spec: api_v1.PodSpec{
|
|
|
|
Containers: []api_v1.Container{
|
2016-05-29 23:05:38 +00:00
|
|
|
{
|
2017-04-01 14:38:58 +00:00
|
|
|
Ports: []api_v1.ContainerPort{{Name: "test", ContainerPort: 80}},
|
|
|
|
ReadinessProbe: &api_v1.Probe{
|
|
|
|
Handler: api_v1.Handler{
|
|
|
|
HTTPGet: &api_v1.HTTPGetAction{
|
2017-04-18 19:44:17 +00:00
|
|
|
Scheme: api_v1.URIScheme(string(np.Protocol)),
|
2016-06-29 01:03:12 +00:00
|
|
|
Path: u,
|
2016-05-29 23:05:38 +00:00
|
|
|
Port: intstr.IntOrString{
|
|
|
|
Type: intstr.Int,
|
|
|
|
IntVal: 80,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
lbc.podLister.Indexer.Add(pod)
|
2016-09-22 21:56:50 +00:00
|
|
|
delay = 2 * delay
|
2016-05-29 23:05:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func addNodes(lbc *LoadBalancerController, zoneToNode map[string][]string) {
|
|
|
|
for zone, nodes := range zoneToNode {
|
|
|
|
for _, node := range nodes {
|
2017-04-01 14:38:58 +00:00
|
|
|
n := &api_v1.Node{
|
|
|
|
ObjectMeta: meta_v1.ObjectMeta{
|
2016-05-29 23:05:38 +00:00
|
|
|
Name: node,
|
|
|
|
Labels: map[string]string{
|
|
|
|
zoneKey: zone,
|
|
|
|
},
|
|
|
|
},
|
2017-04-01 14:38:58 +00:00
|
|
|
Status: api_v1.NodeStatus{
|
|
|
|
Conditions: []api_v1.NodeCondition{
|
|
|
|
{Type: api_v1.NodeReady, Status: api_v1.ConditionTrue},
|
2016-05-29 23:05:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2017-04-01 14:38:58 +00:00
|
|
|
lbc.nodeLister.Indexer.Add(n)
|
2016-05-29 23:05:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lbc.CloudClusterManager.instancePool.Init(lbc.tr)
|
|
|
|
}
|
2017-04-18 19:44:17 +00:00
|
|
|
|
|
|
|
func getProbePath(p *api_v1.Probe) string {
|
|
|
|
return p.Handler.HTTPGet.Path
|
|
|
|
}
|