diff --git a/pkg/api/types.go b/pkg/api/types.go index 2d446df5c51..50b3b1b85ce 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -111,7 +111,7 @@ type Port struct { HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"` // Required: This must be a valid port number, 0 < x < 65536. ContainerPort int `yaml:"containerPort" json:"containerPort"` - // Optional: Defaults to "TCP". + // Optional: Supports "TCP" and "UDP". Defaults to "TCP". Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"` // Optional: What host IP to bind the external port to. HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"` @@ -389,7 +389,11 @@ func (*ServiceList) IsAnAPIObject() {} // will answer requests sent through the proxy. type Service struct { JSONBase `json:",inline" yaml:",inline"` - Port int `json:"port,omitempty" yaml:"port,omitempty"` + + // Required. + Port int `json:"port" yaml:"port"` + // Optional: Supports "TCP" and "UDP". Defaults to "TCP". + Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"` // This service's labels. Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 552f61f2c28..1dba02b5f47 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -111,7 +111,7 @@ type Port struct { HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"` // Required: This must be a valid port number, 0 < x < 65536. ContainerPort int `yaml:"containerPort" json:"containerPort"` - // Optional: Defaults to "TCP". + // Optional: Supports "TCP" and "UDP". Defaults to "TCP". Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"` // Optional: What host IP to bind the external port to. HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"` @@ -401,7 +401,11 @@ func (*ServiceList) IsAnAPIObject() {} // will answer requests sent through the proxy. type Service struct { JSONBase `json:",inline" yaml:",inline"` - Port int `json:"port,omitempty" yaml:"port,omitempty"` + + // Required. + Port int `json:"port" yaml:"port"` + // Optional: Supports "TCP" and "UDP". Defaults to "TCP". + Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"` // This service's labels. Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 48f183b4162..7743cdd4b78 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -282,6 +282,11 @@ func ValidateService(service *api.Service) errs.ErrorList { if !util.IsValidPortNum(service.Port) { allErrs = append(allErrs, errs.NewFieldInvalid("Service.Port", service.Port)) } + if len(service.Protocol) == 0 { + service.Protocol = "TCP" + } else if !supportedPortProtocols.Has(strings.ToUpper(service.Protocol)) { + allErrs = append(allErrs, errs.NewFieldNotSupported("protocol", service.Protocol)) + } if labels.Set(service.Selector).AsSelector().Empty() { allErrs = append(allErrs, errs.NewFieldRequired("selector", service.Selector)) } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 1f1cc8b72c2..e977fc1a6f1 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -408,6 +408,17 @@ func TestValidateService(t *testing.T) { // Should fail because the port number is invalid. numErrs: 1, }, + { + name: "invalid protocol", + svc: api.Service{ + JSONBase: api.JSONBase{ID: "abc123"}, + Port: 8675, + Protocol: "INVALID", + Selector: map[string]string{"foo": "bar"}, + }, + // Should fail because the protocol is invalid. + numErrs: 1, + }, { name: "missing selector", svc: api.Service{ @@ -422,6 +433,7 @@ func TestValidateService(t *testing.T) { svc: api.Service{ JSONBase: api.JSONBase{ID: "abc123"}, Port: 1, + Protocol: "TCP", Selector: map[string]string{"foo": "bar"}, }, numErrs: 0, @@ -431,6 +443,7 @@ func TestValidateService(t *testing.T) { svc: api.Service{ JSONBase: api.JSONBase{ID: "abc123"}, Port: 65535, + Protocol: "UDP", Selector: map[string]string{"foo": "bar"}, }, numErrs: 0, @@ -452,6 +465,19 @@ func TestValidateService(t *testing.T) { t.Errorf("Unexpected error list for case %q: %+v", tc.name, errs) } } + + svc := api.Service{ + Port: 6502, + JSONBase: api.JSONBase{ID: "foo"}, + Selector: map[string]string{"foo": "bar"}, + } + errs := ValidateService(&svc) + if len(errs) != 0 { + t.Errorf("Unexpected non-zero error list: %#v", errs) + } + if svc.Protocol != "TCP" { + t.Errorf("Expected default protocol of 'TCP': %#v", errs) + } } func TestValidateReplicationController(t *testing.T) {