Update master service ports and type via controller.

This commit is contained in:
Andrew Butcher
2015-10-16 14:54:07 -04:00
parent ff7ce44e74
commit 0c4aafaf1e
3 changed files with 577 additions and 61 deletions

View File

@@ -17,20 +17,22 @@ limitations under the License.
package master
import (
"errors"
"net"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/util"
)
func TestSetEndpoints(t *testing.T) {
func TestReconcileEndpoints(t *testing.T) {
ns := api.NamespaceDefault
om := func(name string) api.ObjectMeta {
return api.ObjectMeta{Namespace: ns, Name: name}
}
tests := []struct {
reconcile_tests := []struct {
testName string
serviceName string
ip string
@@ -291,29 +293,6 @@ func TestSetEndpoints(t *testing.T) {
}},
},
},
{
testName: "existing endpoints extra un-ordered service ports satisfy",
serviceName: "foo",
ip: "1.2.3.4",
endpointPorts: []api.EndpointPort{
{Name: "baz", Port: 1010, Protocol: "TCP"},
{Name: "foo", Port: 8080, Protocol: "TCP"},
{Name: "bar", Port: 1000, Protocol: "TCP"},
},
endpoints: &api.EndpointsList{
Items: []api.Endpoints{{
ObjectMeta: om("foo"),
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{
{Name: "bar", Port: 1000, Protocol: "TCP"},
{Name: "foo", Port: 8080, Protocol: "TCP"},
{Name: "baz", Port: 1010, Protocol: "TCP"},
},
}},
}},
},
},
{
testName: "existing endpoints extra service ports missing port",
serviceName: "foo",
@@ -343,13 +322,488 @@ func TestSetEndpoints(t *testing.T) {
},
},
}
for _, test := range tests {
for _, test := range reconcile_tests {
master := Controller{MasterCount: test.additionalMasters + 1}
registry := &registrytest.EndpointRegistry{
Endpoints: test.endpoints,
}
master.EndpointRegistry = registry
err := master.SetEndpoints(test.serviceName, net.ParseIP(test.ip), test.endpointPorts)
err := master.ReconcileEndpoints(test.serviceName, net.ParseIP(test.ip), test.endpointPorts, true)
if err != nil {
t.Errorf("case %q: unexpected error: %v", test.testName, err)
}
if test.expectUpdate != nil {
if len(registry.Updates) != 1 {
t.Errorf("case %q: unexpected updates: %v", test.testName, registry.Updates)
} else if e, a := test.expectUpdate, &registry.Updates[0]; !reflect.DeepEqual(e, a) {
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
}
}
if test.expectUpdate == nil && len(registry.Updates) > 0 {
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, registry.Updates)
}
}
non_reconcile_tests := []struct {
testName string
serviceName string
ip string
endpointPorts []api.EndpointPort
additionalMasters int
endpoints *api.EndpointsList
expectUpdate *api.Endpoints // nil means none expected
}{
{
testName: "existing endpoints extra service ports missing port no update",
serviceName: "foo",
ip: "1.2.3.4",
endpointPorts: []api.EndpointPort{
{Name: "foo", Port: 8080, Protocol: "TCP"},
{Name: "bar", Port: 1000, Protocol: "TCP"},
},
endpoints: &api.EndpointsList{
Items: []api.Endpoints{{
ObjectMeta: om("foo"),
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
}},
}},
},
expectUpdate: nil,
},
{
testName: "existing endpoints extra service ports, wrong ports, wrong IP",
serviceName: "foo",
ip: "1.2.3.4",
endpointPorts: []api.EndpointPort{
{Name: "foo", Port: 8080, Protocol: "TCP"},
{Name: "bar", Port: 1000, Protocol: "TCP"},
},
endpoints: &api.EndpointsList{
Items: []api.Endpoints{{
ObjectMeta: om("foo"),
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "4.3.2.1"}},
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
}},
}},
},
expectUpdate: &api.Endpoints{
ObjectMeta: om("foo"),
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
}},
},
},
{
testName: "no existing endpoints",
serviceName: "foo",
ip: "1.2.3.4",
endpointPorts: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
endpoints: nil,
expectUpdate: &api.Endpoints{
ObjectMeta: om("foo"),
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
}},
},
},
}
for _, test := range non_reconcile_tests {
master := Controller{MasterCount: test.additionalMasters + 1}
registry := &registrytest.EndpointRegistry{
Endpoints: test.endpoints,
}
master.EndpointRegistry = registry
err := master.ReconcileEndpoints(test.serviceName, net.ParseIP(test.ip), test.endpointPorts, false)
if err != nil {
t.Errorf("case %q: unexpected error: %v", test.testName, err)
}
if test.expectUpdate != nil {
if len(registry.Updates) != 1 {
t.Errorf("case %q: unexpected updates: %v", test.testName, registry.Updates)
} else if e, a := test.expectUpdate, &registry.Updates[0]; !reflect.DeepEqual(e, a) {
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
}
}
if test.expectUpdate == nil && len(registry.Updates) > 0 {
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, registry.Updates)
}
}
}
func TestCreateOrUpdateMasterService(t *testing.T) {
ns := api.NamespaceDefault
om := func(name string) api.ObjectMeta {
return api.ObjectMeta{Namespace: ns, Name: name}
}
create_tests := []struct {
testName string
serviceName string
servicePorts []api.ServicePort
serviceType api.ServiceType
expectCreate *api.Service // nil means none expected
}{
{
testName: "service does not exist",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
expectCreate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
}
for _, test := range create_tests {
master := Controller{MasterCount: 1}
registry := &registrytest.ServiceRegistry{
Err: errors.New("unable to get svc"),
}
master.ServiceRegistry = registry
master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, false)
if test.expectCreate != nil {
if len(registry.List.Items) != 1 {
t.Errorf("case %q: unexpected creations: %v", test.testName, registry.List.Items)
} else if e, a := test.expectCreate.Spec, registry.List.Items[0].Spec; !reflect.DeepEqual(e, a) {
t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a)
}
}
if test.expectCreate == nil && len(registry.List.Items) > 1 {
t.Errorf("case %q: no create expected, yet saw: %v", test.testName, registry.List.Items)
}
}
reconcile_tests := []struct {
testName string
serviceName string
servicePorts []api.ServicePort
serviceType api.ServiceType
service *api.Service
expectUpdate *api.Service // nil means none expected
}{
{
testName: "service definition wrong port",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8000, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition missing port",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
{Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition incorrect port",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "bar", Port: 1000, Protocol: "UDP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition incorrect port name",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 1000, Protocol: "UDP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition incorrect target port",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition incorrect protocol",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "UDP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition has incorrect type",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeNodePort,
},
},
expectUpdate: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
},
{
testName: "service definition satisfies",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: nil,
},
}
for _, test := range reconcile_tests {
master := Controller{MasterCount: 1}
registry := &registrytest.ServiceRegistry{
Service: test.service,
}
master.ServiceRegistry = registry
err := master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, true)
if err != nil {
t.Errorf("case %q: unexpected error: %v", test.testName, err)
}
if test.expectUpdate != nil {
if len(registry.Updates) != 1 {
t.Errorf("case %q: unexpected updates: %v", test.testName, registry.Updates)
} else if e, a := test.expectUpdate, &registry.Updates[0]; !reflect.DeepEqual(e, a) {
t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a)
}
}
if test.expectUpdate == nil && len(registry.Updates) > 0 {
t.Errorf("case %q: no update expected, yet saw: %v", test.testName, registry.Updates)
}
}
non_reconcile_tests := []struct {
testName string
serviceName string
servicePorts []api.ServicePort
serviceType api.ServiceType
service *api.Service
expectUpdate *api.Service // nil means none expected
}{
{
testName: "service definition wrong port, no expected update",
serviceName: "foo",
servicePorts: []api.ServicePort{
{Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)},
},
serviceType: api.ServiceTypeClusterIP,
service: &api.Service{
ObjectMeta: om("foo"),
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "foo", Port: 1000, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1000)},
},
Selector: nil,
ClusterIP: "1.2.3.4",
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
},
},
expectUpdate: nil,
},
}
for _, test := range non_reconcile_tests {
master := Controller{MasterCount: 1}
registry := &registrytest.ServiceRegistry{
Service: test.service,
}
master.ServiceRegistry = registry
err := master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, net.ParseIP("1.2.3.4"), test.servicePorts, test.serviceType, false)
if err != nil {
t.Errorf("case %q: unexpected error: %v", test.testName, err)
}