Skip to content

Commit

Permalink
Implement multi-port Endpoints
Browse files Browse the repository at this point in the history
This is a part of multi-port services.
  • Loading branch information
thockin committed Feb 22, 2015
1 parent e0fd830 commit 160f288
Show file tree
Hide file tree
Showing 33 changed files with 742 additions and 374 deletions.
10 changes: 9 additions & 1 deletion pkg/api/testing/fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
Expand Down Expand Up @@ -237,7 +239,13 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
func(ep *api.Endpoint, c fuzz.Continue) {
// TODO: If our API used a particular type for IP fields we could just catch that here.
ep.IP = fmt.Sprintf("%d.%d.%d.%d", c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256))
ep.Port = c.Rand.Intn(65536)
// TODO: Once we drop single-port APIs, make this fuzz
// multiple ports and fuzz port.name. This will force
// a compile error when those APIs are deleted.
_ = v1beta1.Dependency
_ = v1beta2.Dependency
ep.Ports = []api.EndpointPort{{Name: "", Port: c.Rand.Intn(65536)}}
c.Fuzz(&ep.Ports[0].Protocol)
},
)
return f
Expand Down
20 changes: 15 additions & 5 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,9 +750,6 @@ type Endpoints struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`

// Optional: The IP protocol for these endpoints. Supports "TCP" and
// "UDP". Defaults to "TCP".
Protocol Protocol `json:"protocol,omitempty"`
Endpoints []Endpoint `json:"endpoints,omitempty"`
}

Expand All @@ -762,8 +759,21 @@ type Endpoint struct {
// TODO: This should allow hostname or IP, see #4447.
IP string `json:"ip"`

// Required: The destination port to access.
Port int `json:"port"`
// The ports exposed on this IP.
Ports []EndpointPort
}

type EndpointPort struct {
// Optional if only one port is defined in this Endpoint.
// The name of this port within the larger service/endpoint structure.
// This must be a DNS_LABEL.
Name string

// The IP protocol for this port. Supports "TCP" and "UDP".
Protocol Protocol

// The destination port to access.
Port int
}

// EndpointsList is a list of endpoints.
Expand Down
24 changes: 13 additions & 11 deletions pkg/api/v1beta1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1121,12 +1121,16 @@ func init() {
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil {
return err
}
for i := range in.Endpoints {
ep := &in.Endpoints[i]
out.Endpoints = append(out.Endpoints, net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port)))
// newer.Endpoints.Endpoints[i].Ports is an array - take the first one.
if len(ep.Ports) > 0 {
port := &ep.Ports[0]
if err := s.Convert(&port.Protocol, &out.Protocol, 0); err != nil {
return err
}
out.Endpoints = append(out.Endpoints, net.JoinHostPort(ep.IP, strconv.Itoa(port.Port)))
}
}
return nil
},
Expand All @@ -1137,22 +1141,20 @@ func init() {
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil {
return err
}
for i := range in.Endpoints {
out.Endpoints = append(out.Endpoints, newer.Endpoint{})
ep := &out.Endpoints[i]
host, port, err := net.SplitHostPort(in.Endpoints[i])
if err != nil {
return err
}
ep.IP = host
pn, err := strconv.Atoi(port)
if err != nil {
return err
}
ep.Port = pn
epp := newer.EndpointPort{Port: pn}
if err := s.Convert(&in.Protocol, &epp.Protocol, 0); err != nil {
return err
}
out.Endpoints = append(out.Endpoints, newer.Endpoint{IP: host, Ports: []newer.EndpointPort{epp}})
}
return nil
},
Expand Down
26 changes: 10 additions & 16 deletions pkg/api/v1beta1/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,41 +390,35 @@ func TestEndpointsConversion(t *testing.T) {
}{
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "empty",
},
Protocol: current.ProtocolTCP,
Protocol: "",
Endpoints: []string{},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolTCP,
Endpoints: []newer.Endpoint{},
},
},
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "one",
},
Protocol: current.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolTCP,
Endpoints: []newer.Endpoint{{IP: "1.2.3.4", Port: 88}},
Endpoints: []newer.Endpoint{
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolTCP, Port: 88}}},
},
},
},
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "several",
},
Protocol: current.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolUDP,
Endpoints: []newer.Endpoint{{IP: "1.2.3.4", Port: 88}, {IP: "1.2.3.4", Port: 89}, {IP: "1.2.3.4", Port: 90}},
Endpoints: []newer.Endpoint{
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 88}}},
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 89}}},
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 90}}},
},
},
},
}
Expand All @@ -436,7 +430,7 @@ func TestEndpointsConversion(t *testing.T) {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if got.Protocol != tc.expected.Protocol || !newer.Semantic.DeepEqual(got.Endpoints, tc.expected.Endpoints) {
if !newer.Semantic.DeepEqual(got.Endpoints, tc.expected.Endpoints) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected, got)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1beta1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func init() {
}
},
func(obj *Endpoints) {
if obj.Protocol == "" {
if obj.Protocol == "" && len(obj.Endpoints) > 0 {
obj.Protocol = "TCP"
}
},
Expand Down
12 changes: 11 additions & 1 deletion pkg/api/v1beta1/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,21 @@ func TestSetDefaultSecret(t *testing.T) {
}
}

func TestSetDefaulEndpointsProtocol(t *testing.T) {
func TestSetDefaulEndpointsProtocolEmpty(t *testing.T) {
in := &current.Endpoints{}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*current.Endpoints)

if out.Protocol != "" {
t.Errorf("Expected protocol \"\", got %s", out.Protocol)
}
}

func TestSetDefaulEndpointsProtocol(t *testing.T) {
in := &current.Endpoints{Endpoints: []string{"1.2.3.4:5678"}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*current.Endpoints)

if out.Protocol != current.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", current.ProtocolTCP, out.Protocol)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/v1beta1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import (
// Codec encodes internal objects to the v1beta1 scheme
var Codec = runtime.CodecFor(api.Scheme, "v1beta1")

// Dependency does nothing but give a hook for other packages to force a
// compile-time error when this API version is eventually removed. This is
// useful, for example, to clean up things that are implicitly tied to
// semantics of older APIs.
const Dependency = true

func init() {
api.Scheme.AddKnownTypes("v1beta1",
&Pod{},
Expand Down
24 changes: 13 additions & 11 deletions pkg/api/v1beta2/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1036,12 +1036,16 @@ func init() {
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil {
return err
}
for i := range in.Endpoints {
ep := &in.Endpoints[i]
out.Endpoints = append(out.Endpoints, net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port)))
// newer.Endpoints.Endpoints[i].Ports is an array - take the first one.
if len(ep.Ports) > 0 {
port := &ep.Ports[0]
if err := s.Convert(&port.Protocol, &out.Protocol, 0); err != nil {
return err
}
out.Endpoints = append(out.Endpoints, net.JoinHostPort(ep.IP, strconv.Itoa(port.Port)))
}
}
return nil
},
Expand All @@ -1052,22 +1056,20 @@ func init() {
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil {
return err
}
for i := range in.Endpoints {
out.Endpoints = append(out.Endpoints, newer.Endpoint{})
ep := &out.Endpoints[i]
host, port, err := net.SplitHostPort(in.Endpoints[i])
if err != nil {
return err
}
ep.IP = host
pn, err := strconv.Atoi(port)
if err != nil {
return err
}
ep.Port = pn
epp := newer.EndpointPort{Port: pn}
if err := s.Convert(&in.Protocol, &epp.Protocol, 0); err != nil {
return err
}
out.Endpoints = append(out.Endpoints, newer.Endpoint{IP: host, Ports: []newer.EndpointPort{epp}})
}
return nil
},
Expand Down
26 changes: 10 additions & 16 deletions pkg/api/v1beta2/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,41 +220,35 @@ func TestEndpointsConversion(t *testing.T) {
}{
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "empty",
},
Protocol: current.ProtocolTCP,
Protocol: "",
Endpoints: []string{},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolTCP,
Endpoints: []newer.Endpoint{},
},
},
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "one",
},
Protocol: current.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolTCP,
Endpoints: []newer.Endpoint{{IP: "1.2.3.4", Port: 88}},
Endpoints: []newer.Endpoint{
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolTCP, Port: 88}}},
},
},
},
{
given: current.Endpoints{
TypeMeta: current.TypeMeta{
ID: "several",
},
Protocol: current.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
},
expected: newer.Endpoints{
Protocol: newer.ProtocolUDP,
Endpoints: []newer.Endpoint{{IP: "1.2.3.4", Port: 88}, {IP: "1.2.3.4", Port: 89}, {IP: "1.2.3.4", Port: 90}},
Endpoints: []newer.Endpoint{
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 88}}},
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 89}}},
{IP: "1.2.3.4", Ports: []newer.EndpointPort{{Protocol: newer.ProtocolUDP, Port: 90}}},
},
},
},
}
Expand All @@ -266,7 +260,7 @@ func TestEndpointsConversion(t *testing.T) {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if got.Protocol != tc.expected.Protocol || !newer.Semantic.DeepEqual(got.Endpoints, tc.expected.Endpoints) {
if !newer.Semantic.DeepEqual(got.Endpoints, tc.expected.Endpoints) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected, got)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1beta2/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func init() {
}
},
func(obj *Endpoints) {
if obj.Protocol == "" {
if obj.Protocol == "" && len(obj.Endpoints) > 0 {
obj.Protocol = "TCP"
}
},
Expand Down
12 changes: 11 additions & 1 deletion pkg/api/v1beta2/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,21 @@ func TestSetDefaultSecret(t *testing.T) {
}
}

func TestSetDefaulEndpointsProtocol(t *testing.T) {
func TestSetDefaulEndpointsProtocolEmpty(t *testing.T) {
in := &current.Endpoints{}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*current.Endpoints)

if out.Protocol != "" {
t.Errorf("Expected protocol \"\", got %s", out.Protocol)
}
}

func TestSetDefaulEndpointsProtocol(t *testing.T) {
in := &current.Endpoints{Endpoints: []string{"1.2.3.4:5678"}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*current.Endpoints)

if out.Protocol != current.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", current.ProtocolTCP, out.Protocol)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/v1beta2/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import (
// Codec encodes internal objects to the v1beta2 scheme
var Codec = runtime.CodecFor(api.Scheme, "v1beta2")

// Dependency does nothing but give a hook for other packages to force a
// compile-time error when this API version is eventually removed. This is
// useful, for example, to clean up things that are implicitly tied to
// semantics of older APIs.
const Dependency = true

func init() {
api.Scheme.AddKnownTypes("v1beta2",
&Pod{},
Expand Down
10 changes: 8 additions & 2 deletions pkg/api/v1beta3/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,14 @@ func init() {
}
},
func(obj *Endpoints) {
if obj.Protocol == "" {
obj.Protocol = "TCP"
for i := range obj.Endpoints {
ep := &obj.Endpoints[i]
for j := range ep.Ports {
port := &ep.Ports[j]
if port.Protocol == "" {
port.Protocol = ProtocolTCP
}
}
}
},
)
Expand Down
Loading

0 comments on commit 160f288

Please sign in to comment.