2015-03-24 17:32:43 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
2015-03-24 17:32:43 +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 servicecontroller
|
|
|
|
|
|
|
|
import (
|
2015-04-22 20:54:44 +00:00
|
|
|
"reflect"
|
2015-03-24 17:32:43 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
|
|
|
|
fake_cloud "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake"
|
2015-04-09 20:48:27 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
2015-03-24 17:32:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const region = "us-central"
|
|
|
|
|
2015-05-22 21:49:26 +00:00
|
|
|
func newService(name string, uid types.UID, serviceType api.ServiceType) *api.Service {
|
|
|
|
return &api.Service{ObjectMeta: api.ObjectMeta{Name: name, Namespace: "namespace", UID: uid}, Spec: api.ServiceSpec{Type: serviceType}}
|
2015-04-22 20:54:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 17:32:43 +00:00
|
|
|
func TestCreateExternalLoadBalancer(t *testing.T) {
|
|
|
|
table := []struct {
|
|
|
|
service *api.Service
|
|
|
|
expectErr bool
|
|
|
|
expectCreateAttempt bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
service: &api.Service{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "no-external-balancer",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-05-22 21:49:26 +00:00
|
|
|
Type: api.ServiceTypeClusterIP,
|
2015-03-24 17:32:43 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
expectErr: false,
|
|
|
|
expectCreateAttempt: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
service: &api.Service{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "udp-service",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: api.ServiceSpec{
|
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Port: 80,
|
|
|
|
Protocol: api.ProtocolUDP,
|
|
|
|
}},
|
2015-05-22 21:49:26 +00:00
|
|
|
Type: api.ServiceTypeLoadBalancer,
|
2015-03-24 17:32:43 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
expectErr: true,
|
|
|
|
expectCreateAttempt: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
service: &api.Service{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "basic-service1",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: api.ServiceSpec{
|
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Port: 80,
|
|
|
|
Protocol: api.ProtocolTCP,
|
|
|
|
}},
|
2015-05-22 21:49:26 +00:00
|
|
|
Type: api.ServiceTypeLoadBalancer,
|
2015-03-24 17:32:43 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
expectErr: false,
|
|
|
|
expectCreateAttempt: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range table {
|
|
|
|
cloud := &fake_cloud.FakeCloud{}
|
|
|
|
cloud.Region = region
|
|
|
|
client := &testclient.Fake{}
|
2015-05-03 06:32:21 +00:00
|
|
|
controller := New(cloud, client, "test-cluster")
|
2015-03-24 17:32:43 +00:00
|
|
|
controller.init()
|
2015-07-06 21:37:46 +00:00
|
|
|
cloud.Calls = nil // ignore any cloud calls made in init()
|
|
|
|
client.ClearActions() // ignore any client calls made in init()
|
2015-04-09 20:48:27 +00:00
|
|
|
err, _ := controller.createLoadBalancerIfNeeded(types.NamespacedName{"foo", "bar"}, item.service, nil)
|
2015-03-24 17:32:43 +00:00
|
|
|
if !item.expectErr && err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
} else if item.expectErr && err == nil {
|
|
|
|
t.Errorf("expected error creating %v, got nil", item.service)
|
|
|
|
}
|
2015-07-06 21:37:46 +00:00
|
|
|
actions := client.Actions()
|
2015-03-24 17:32:43 +00:00
|
|
|
if !item.expectCreateAttempt {
|
|
|
|
if len(cloud.Calls) > 0 {
|
|
|
|
t.Errorf("unexpected cloud provider calls: %v", cloud.Calls)
|
|
|
|
}
|
2015-07-06 21:37:46 +00:00
|
|
|
if len(actions) > 0 {
|
|
|
|
t.Errorf("unexpected client actions: %v", actions)
|
2015-03-24 17:32:43 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if len(cloud.Balancers) != 1 {
|
|
|
|
t.Errorf("expected one load balancer to be created, got %v", cloud.Balancers)
|
|
|
|
} else if cloud.Balancers[0].Name != controller.loadBalancerName(item.service) ||
|
|
|
|
cloud.Balancers[0].Region != region ||
|
2015-05-22 23:42:04 +00:00
|
|
|
cloud.Balancers[0].Ports[0].Port != item.service.Spec.Ports[0].Port {
|
2015-03-24 17:32:43 +00:00
|
|
|
t.Errorf("created load balancer has incorrect parameters: %v", cloud.Balancers[0])
|
|
|
|
}
|
|
|
|
actionFound := false
|
2015-07-06 21:37:46 +00:00
|
|
|
for _, action := range actions {
|
2015-08-03 13:21:11 +00:00
|
|
|
if action.GetVerb() == "update" && action.GetResource() == "services" {
|
2015-03-24 17:32:43 +00:00
|
|
|
actionFound = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !actionFound {
|
2015-07-06 21:37:46 +00:00
|
|
|
t.Errorf("expected updated service to be sent to client, got these actions instead: %v", actions)
|
2015-03-24 17:32:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-22 20:54:44 +00:00
|
|
|
// TODO: Finish converting and update comments
|
|
|
|
func TestUpdateNodesInExternalLoadBalancer(t *testing.T) {
|
|
|
|
hosts := []string{"node0", "node1", "node73"}
|
|
|
|
table := []struct {
|
|
|
|
services []*api.Service
|
|
|
|
expectedUpdateCalls []fake_cloud.FakeUpdateBalancerCall
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
// No services present: no calls should be made.
|
|
|
|
services: []*api.Service{},
|
|
|
|
expectedUpdateCalls: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Services do not have external load balancers: no calls should be made.
|
|
|
|
services: []*api.Service{
|
2015-05-22 21:49:26 +00:00
|
|
|
newService("s0", "111", api.ServiceTypeClusterIP),
|
2015-05-20 15:59:34 +00:00
|
|
|
newService("s1", "222", api.ServiceTypeNodePort),
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
expectedUpdateCalls: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Services does have an external load balancer: one call should be made.
|
|
|
|
services: []*api.Service{
|
2015-05-22 21:49:26 +00:00
|
|
|
newService("s0", "333", api.ServiceTypeLoadBalancer),
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
expectedUpdateCalls: []fake_cloud.FakeUpdateBalancerCall{
|
2015-05-03 06:32:21 +00:00
|
|
|
{Name: "a333", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Three services have an external load balancer: three calls.
|
|
|
|
services: []*api.Service{
|
2015-05-22 21:49:26 +00:00
|
|
|
newService("s0", "444", api.ServiceTypeLoadBalancer),
|
|
|
|
newService("s1", "555", api.ServiceTypeLoadBalancer),
|
|
|
|
newService("s2", "666", api.ServiceTypeLoadBalancer),
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
expectedUpdateCalls: []fake_cloud.FakeUpdateBalancerCall{
|
2015-05-03 06:32:21 +00:00
|
|
|
{Name: "a444", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
|
|
|
{Name: "a555", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
|
|
|
{Name: "a666", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Two services have an external load balancer and two don't: two calls.
|
|
|
|
services: []*api.Service{
|
2015-05-20 15:59:34 +00:00
|
|
|
newService("s0", "777", api.ServiceTypeNodePort),
|
2015-05-22 21:49:26 +00:00
|
|
|
newService("s1", "888", api.ServiceTypeLoadBalancer),
|
|
|
|
newService("s3", "999", api.ServiceTypeLoadBalancer),
|
|
|
|
newService("s4", "123", api.ServiceTypeClusterIP),
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
expectedUpdateCalls: []fake_cloud.FakeUpdateBalancerCall{
|
2015-05-03 06:32:21 +00:00
|
|
|
{Name: "a888", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
|
|
|
{Name: "a999", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
2015-04-22 20:54:44 +00:00
|
|
|
},
|
|
|
|
},
|
2015-05-18 05:36:48 +00:00
|
|
|
{
|
|
|
|
// One service has an external load balancer and one is nil: one call.
|
|
|
|
services: []*api.Service{
|
2015-05-22 21:49:26 +00:00
|
|
|
newService("s0", "234", api.ServiceTypeLoadBalancer),
|
2015-05-18 05:36:48 +00:00
|
|
|
nil,
|
|
|
|
},
|
|
|
|
expectedUpdateCalls: []fake_cloud.FakeUpdateBalancerCall{
|
|
|
|
{Name: "a234", Region: region, Hosts: []string{"node0", "node1", "node73"}},
|
|
|
|
},
|
|
|
|
},
|
2015-04-22 20:54:44 +00:00
|
|
|
}
|
|
|
|
for _, item := range table {
|
|
|
|
cloud := &fake_cloud.FakeCloud{}
|
|
|
|
|
|
|
|
cloud.Region = region
|
|
|
|
client := &testclient.Fake{}
|
2015-05-03 06:32:21 +00:00
|
|
|
controller := New(cloud, client, "test-cluster2")
|
2015-04-22 20:54:44 +00:00
|
|
|
controller.init()
|
|
|
|
cloud.Calls = nil // ignore any cloud calls made in init()
|
|
|
|
|
|
|
|
var services []*cachedService
|
|
|
|
for _, service := range item.services {
|
2015-06-16 22:59:03 +00:00
|
|
|
services = append(services, &cachedService{lastState: service, appliedState: service})
|
2015-04-22 20:54:44 +00:00
|
|
|
}
|
|
|
|
if err := controller.updateLoadBalancerHosts(services, hosts); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(item.expectedUpdateCalls, cloud.UpdateCalls) {
|
|
|
|
t.Errorf("expected update calls mismatch, expected %+v, got %+v", item.expectedUpdateCalls, cloud.UpdateCalls)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 17:32:43 +00:00
|
|
|
// TODO(a-robinson): Add tests for update/sync/delete.
|