diff --git a/cmd/integration/integration.go b/cmd/integration/integration.go index 3a12bd45483..1c47715fc44 100644 --- a/cmd/integration/integration.go +++ b/cmd/integration/integration.go @@ -285,10 +285,12 @@ func runSelfLinkTest(c *client.Client) { "name": "selflinktest", }, }, - Port: 12345, - // This is here because validation requires it. - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Port: 12345, + // This is here because validation requires it. + Selector: map[string]string{ + "foo": "bar", + }, }, }, ).Do().Into(&svc) @@ -345,10 +347,12 @@ func runAtomicPutTest(c *client.Client) { "name": "atomicService", }, }, - Port: 12345, - // This is here because validation requires it. - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Port: 12345, + // This is here because validation requires it. + Selector: map[string]string{ + "foo": "bar", + }, }, }, ).Do().Into(&svc) @@ -379,10 +383,10 @@ func runAtomicPutTest(c *client.Client) { glog.Errorf("Error getting atomicService: %v", err) continue } - if tmpSvc.Selector == nil { - tmpSvc.Selector = map[string]string{l: v} + if tmpSvc.Spec.Selector == nil { + tmpSvc.Spec.Selector = map[string]string{l: v} } else { - tmpSvc.Selector[l] = v + tmpSvc.Spec.Selector[l] = v } glog.Infof("Posting update (%s, %s)", l, v) err = c.Put().Path("services").Path(svc.Name).Body(&tmpSvc).Do().Error() @@ -405,8 +409,8 @@ func runAtomicPutTest(c *client.Client) { if err := c.Get().Path("services").Path(svc.Name).Do().Into(&svc); err != nil { glog.Fatalf("Failed getting atomicService after writers are complete: %v", err) } - if !reflect.DeepEqual(testLabels, labels.Set(svc.Selector)) { - glog.Fatalf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, svc.Selector) + if !reflect.DeepEqual(testLabels, labels.Set(svc.Spec.Selector)) { + glog.Fatalf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, svc.Spec.Selector) } glog.Info("Atomic PUTs work.") } @@ -508,10 +512,12 @@ func runServiceTest(client *client.Client) { } svc1 := api.Service{ ObjectMeta: api.ObjectMeta{Name: "service1"}, - Selector: map[string]string{ - "name": "thisisalonglabel", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "name": "thisisalonglabel", + }, + Port: 8080, }, - Port: 8080, } _, err = client.Services(api.NamespaceDefault).Create(&svc1) if err != nil { @@ -523,10 +529,12 @@ func runServiceTest(client *client.Client) { // A second service with the same port. svc2 := api.Service{ ObjectMeta: api.ObjectMeta{Name: "service2"}, - Selector: map[string]string{ - "name": "thisisalonglabel", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "name": "thisisalonglabel", + }, + Port: 8080, }, - Port: 8080, } _, err = client.Services(api.NamespaceDefault).Create(&svc2) if err != nil { diff --git a/pkg/api/types.go b/pkg/api/types.go index 811c98eb271..0058cfde21f 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -479,6 +479,38 @@ type ServiceList struct { Items []Service `json:"items" yaml:"items"` } +// ServiceStatus represents the current status of a service +type ServiceStatus struct{} + +// ServiceSpec describes the attributes that a user creates on a service +type ServiceSpec struct { + // Port is the TCP or UDP port that will be made available to each pod for connecting to the pods + // proxied by this service. + Port int `json:"port" yaml:"port"` + + // Optional: Supports "TCP" and "UDP". Defaults to "TCP". + Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"` + + // This service will route traffic to pods having labels matching this selector. + Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` + + // PortalIP is usually assigned by the master. If specified by the user + // we will try to respect it or else fail the request. This field can + // not be changed by updates. + PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"` + + // ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port. + // TODO: This is awkward - if we had a BoundService, it would be better factored. + ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` + + // CreateExternalLoadBalancer indicates whether a load balancer should be created for this service. + CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` + + // ContainerPort is the name of the port on the container to direct traffic to. + // Optional, if unspecified use the first port on the container. + ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` +} + // Service is a named abstraction of software service (for example, mysql) consisting of local port // (for example 3306) that the proxy listens on, and the selector that determines which pods // will answer requests sent through the proxy. @@ -486,27 +518,11 @@ type Service struct { TypeMeta `json:",inline" yaml:",inline"` ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` - // Required. - Port int `json:"port" yaml:"port"` - // Optional: Defaults to "TCP". - Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty"` + // Spec defines the behavior of a service. + Spec ServiceSpec `json:"spec,omitempty" yaml:"spec,omitempty"` - // This service will route traffic to pods having labels matching this selector. - Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` - CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` - - // ContainerPort is the name of the port on the container to direct traffic to. - // Optional, if unspecified use the first port on the container. - ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` - - // PortalIP is usually assigned by the master. If specified by the user - // we will try to respect it or else fail the request. This field can - // not be changed by updates. - PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"` - - // ProxyPort is assigned by the master. If specified by the user it will be ignored. - // TODO: This is awkward - if we had a BoundService, it would be better factored. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` + // Status represents the current status of a service. + Status ServiceStatus `json:"status,omitempty" yaml:"status,omitempty"` } // Endpoints is a collection of endpoints that implement the actual service, for example: diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index d36f51c2b78..0b238cc68fb 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -247,6 +247,7 @@ func init() { }, func(in *newer.Service, out *Service, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } @@ -257,16 +258,15 @@ func init() { return err } - out.Port = in.Port - out.Protocol = Protocol(in.Protocol) - if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil { + out.Port = in.Spec.Port + out.Protocol = Protocol(in.Spec.Protocol) + if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil { return err } - out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer - out.ContainerPort = in.ContainerPort - out.PortalIP = in.PortalIP - out.ProxyPort = in.ProxyPort - + out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer + out.ContainerPort = in.Spec.ContainerPort + out.PortalIP = in.Spec.PortalIP + out.ProxyPort = in.Spec.ProxyPort return nil }, func(in *Service, out *newer.Service, s conversion.Scope) error { @@ -280,16 +280,15 @@ func init() { return err } - out.Port = in.Port - out.Protocol = newer.Protocol(in.Protocol) - if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil { + out.Spec.Port = in.Port + out.Spec.Protocol = newer.Protocol(in.Protocol) + if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil { return err } - out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer - out.ContainerPort = in.ContainerPort - out.PortalIP = in.PortalIP - out.ProxyPort = in.ProxyPort - + out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer + out.Spec.ContainerPort = in.ContainerPort + out.Spec.PortalIP = in.PortalIP + out.Spec.ProxyPort = in.ProxyPort return nil }, diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index 4dc6f29291c..3051c968c62 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -188,15 +188,15 @@ func init() { return err } - out.Port = in.Port - out.Protocol = Protocol(in.Protocol) - if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil { + out.Port = in.Spec.Port + out.Protocol = Protocol(in.Spec.Protocol) + if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil { return err } - out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer - out.ContainerPort = in.ContainerPort - out.PortalIP = in.PortalIP - out.ProxyPort = in.ProxyPort + out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer + out.ContainerPort = in.Spec.ContainerPort + out.PortalIP = in.Spec.PortalIP + out.ProxyPort = in.Spec.ProxyPort return nil }, @@ -211,15 +211,15 @@ func init() { return err } - out.Port = in.Port - out.Protocol = newer.Protocol(in.Protocol) - if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil { + out.Spec.Port = in.Port + out.Spec.Protocol = newer.Protocol(in.Protocol) + if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil { return err } - out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer - out.ContainerPort = in.ContainerPort - out.PortalIP = in.PortalIP - out.ProxyPort = in.ProxyPort + out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer + out.Spec.ContainerPort = in.ContainerPort + out.Spec.PortalIP = in.PortalIP + out.Spec.ProxyPort = in.ProxyPort return nil }, diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 396bef0d6c8..cb5b4ace730 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -123,36 +123,37 @@ const ( NamespaceAll string = "" ) -// ContainerManifest corresponds to the Container Manifest format, documented at: -// https://developers.google.com/compute/docs/containers/container_vms#container_manifest -// This is used as the representation of Kubernetes workloads. -// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd -// directly. -type ContainerManifest struct { - // Required: This must be a supported version string, such as "v1beta1". - Version string `json:"version" yaml:"version"` - // Required: This must be a DNS_SUBDOMAIN. - // TODO: ID on Manifest is deprecated and will be removed in the future. - ID string `json:"id" yaml:"id"` - // TODO: UUID on Manifest is deprecated in the future once we are done - // with the API refactoring. It is required for now to determine the instance - // of a Pod. - UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` - Volumes []Volume `json:"volumes" yaml:"volumes"` - Containers []Container `json:"containers" yaml:"containers"` - RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` -} - -// ContainerManifestList is used to communicate container manifests to kubelet. -// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd -// directly. -type ContainerManifestList struct { - TypeMeta `json:",inline" yaml:",inline"` - // ID is the legacy field representing Name - ID string `json:"id,omitempty" yaml:"id,omitempty"` - - Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"` -} +// +//// ContainerManifest corresponds to the Container Manifest format, documented at: +//// https://developers.google.com/compute/docs/containers/container_vms#container_manifest +//// This is used as the representation of Kubernetes workloads. +//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd +//// directly. +//type ContainerManifest struct { +// // Required: This must be a supported version string, such as "v1beta1". +// Version string `json:"version" yaml:"version"` +// // Required: This must be a DNS_SUBDOMAIN. +// // TODO: ID on Manifest is deprecated and will be removed in the future. +// ID string `json:"id" yaml:"id"` +// // TODO: UUID on Manifest is deprecated in the future once we are done +// // with the API refactoring. It is required for now to determine the instance +// // of a Pod. +// UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` +// Volumes []Volume `json:"volumes" yaml:"volumes"` +// Containers []Container `json:"containers" yaml:"containers"` +// RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"` +//} +// +//// ContainerManifestList is used to communicate container manifests to kubelet. +//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd +//// directly. +//type ContainerManifestList struct { +// TypeMeta `json:",inline" yaml:",inline"` +// // ID is the legacy field representing Name +// ID string `json:"id,omitempty" yaml:"id,omitempty"` +// +// Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"` +//} // Volume represents a named volume in a pod that may be accessed by any containers in the pod. type Volume struct { @@ -583,10 +584,7 @@ type ReplicationControllerList struct { } // ServiceStatus represents the current status of a service -type ServiceStatus struct { - // ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port. - ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` -} +type ServiceStatus struct{} // ServiceSpec describes the attributes that a user creates on a service type ServiceSpec struct { @@ -605,6 +603,9 @@ type ServiceSpec struct { // not be changed by updates. PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"` + // ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port. + ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"` + // CreateExternalLoadBalancer indicates whether a load balancer should be created for this service. CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 3b6742c7591..b906e76d433 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -392,19 +392,19 @@ func ValidateService(service *api.Service) errs.ValidationErrorList { if !util.IsDNSSubdomain(service.Namespace) { allErrs = append(allErrs, errs.NewFieldInvalid("namespace", service.Namespace)) } - if !util.IsValidPortNum(service.Port) { - allErrs = append(allErrs, errs.NewFieldInvalid("port", service.Port)) + if !util.IsValidPortNum(service.Spec.Port) { + allErrs = append(allErrs, errs.NewFieldInvalid("spec.port", service.Spec.Port)) } - if len(service.Protocol) == 0 { - service.Protocol = "TCP" - } else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Protocol))) { - allErrs = append(allErrs, errs.NewFieldNotSupported("protocol", service.Protocol)) + if len(service.Spec.Protocol) == 0 { + service.Spec.Protocol = "TCP" + } else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Spec.Protocol))) { + allErrs = append(allErrs, errs.NewFieldNotSupported("spec.protocol", service.Spec.Protocol)) } - if labels.Set(service.Selector).AsSelector().Empty() { - allErrs = append(allErrs, errs.NewFieldRequired("selector", service.Selector)) + if labels.Set(service.Spec.Selector).AsSelector().Empty() { + allErrs = append(allErrs, errs.NewFieldRequired("spec.selector", service.Spec.Selector)) } allErrs = append(allErrs, validateLabels(service.Labels)...) - allErrs = append(allErrs, validateLabels(service.Selector)...) + allErrs = append(allErrs, validateLabels(service.Spec.Selector)...) return allErrs } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index e67bf79455b..422cdebee02 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -633,8 +633,10 @@ func TestValidateService(t *testing.T) { name: "missing id", svc: api.Service{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault}, - Port: 8675, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + }, }, // Should fail because the ID is missing. numErrs: 1, @@ -643,8 +645,10 @@ func TestValidateService(t *testing.T) { name: "missing namespace", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, - Port: 8675, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + }, }, // Should fail because the Namespace is missing. numErrs: 1, @@ -653,8 +657,10 @@ func TestValidateService(t *testing.T) { name: "invalid id", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "123abc", Namespace: api.NamespaceDefault}, - Port: 8675, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + }, }, // Should fail because the ID is invalid. numErrs: 1, @@ -663,7 +669,9 @@ func TestValidateService(t *testing.T) { name: "missing port", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"foo": "bar"}, + }, }, // Should fail because the port number is missing/invalid. numErrs: 1, @@ -672,8 +680,10 @@ func TestValidateService(t *testing.T) { name: "invalid port", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Port: 65536, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 66536, + Selector: map[string]string{"foo": "bar"}, + }, }, // Should fail because the port number is invalid. numErrs: 1, @@ -682,9 +692,11 @@ func TestValidateService(t *testing.T) { name: "invalid protocol", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Port: 8675, - Protocol: "INVALID", - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + Protocol: "INVALID", + }, }, // Should fail because the protocol is invalid. numErrs: 1, @@ -693,7 +705,9 @@ func TestValidateService(t *testing.T) { name: "missing selector", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, - Port: 8675, + Spec: api.ServiceSpec{ + Port: 8675, + }, }, // Should fail because the selector is missing. numErrs: 1, @@ -702,9 +716,11 @@ func TestValidateService(t *testing.T) { name: "valid 1", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Port: 1, - Protocol: "TCP", - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + Protocol: "TCP", + }, }, numErrs: 0, }, @@ -712,9 +728,11 @@ func TestValidateService(t *testing.T) { name: "valid 2", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Port: 65535, - Protocol: "UDP", - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + Protocol: "UDP", + }, }, numErrs: 0, }, @@ -722,8 +740,10 @@ func TestValidateService(t *testing.T) { name: "valid 3", svc: api.Service{ ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault}, - Port: 80, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar"}, + }, }, numErrs: 0, }, @@ -737,8 +757,10 @@ func TestValidateService(t *testing.T) { "NoUppercaseOrSpecialCharsLike=Equals": "bar", }, }, - Port: 80, - Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"}, + }, }, numErrs: 2, }, @@ -752,15 +774,17 @@ func TestValidateService(t *testing.T) { } svc := api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, - Selector: map[string]string{"foo": "bar"}, + Spec: api.ServiceSpec{ + Port: 8675, + 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" { + if svc.Spec.Protocol != "TCP" { t.Errorf("Expected default protocol of 'TCP': %#v", errs) } } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index b1630334e84..fc06570ed48 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -429,8 +429,10 @@ func TestListServices(t *testing.T) { "name": "baz", }, }, - Selector: map[string]string{ - "one": "two", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "one": "two", + }, }, }, }, @@ -456,8 +458,10 @@ func TestListServicesLabels(t *testing.T) { "name": "baz", }, }, - Selector: map[string]string{ - "one": "two", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "one": "two", + }, }, }, }, diff --git a/pkg/client/request_test.go b/pkg/client/request_test.go index 7381051db1c..7c4623b5fee 100644 --- a/pkg/client/request_test.go +++ b/pkg/client/request_test.go @@ -276,7 +276,7 @@ func TestRequestDo(t *testing.T) { func TestDoRequestNewWay(t *testing.T) { reqBody := "request body" - expectedObj := &api.Service{Port: 12345} + expectedObj := &api.Service{Spec: api.ServiceSpec{Port: 12345}} expectedBody, _ := v1beta2.Codec.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, @@ -311,7 +311,7 @@ func TestDoRequestNewWay(t *testing.T) { func TestDoRequestNewWayReader(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} reqBodyExpected, _ := v1beta1.Codec.Encode(reqObj) - expectedObj := &api.Service{Port: 12345} + expectedObj := &api.Service{Spec: api.ServiceSpec{Port: 12345}} expectedBody, _ := v1beta1.Codec.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, @@ -347,7 +347,7 @@ func TestDoRequestNewWayReader(t *testing.T) { func TestDoRequestNewWayObj(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} reqBodyExpected, _ := v1beta2.Codec.Encode(reqObj) - expectedObj := &api.Service{Port: 12345} + expectedObj := &api.Service{Spec: api.ServiceSpec{Port: 12345}} expectedBody, _ := v1beta2.Codec.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, @@ -396,7 +396,7 @@ func TestDoRequestNewWayFile(t *testing.T) { t.Errorf("unexpected error: %v", err) } - expectedObj := &api.Service{Port: 12345} + expectedObj := &api.Service{Spec: api.ServiceSpec{Port: 12345}} expectedBody, _ := v1beta1.Codec.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, @@ -439,7 +439,7 @@ func TestWasCreated(t *testing.T) { t.Errorf("unexpected error: %v", err) } - expectedObj := &api.Service{Port: 12345} + expectedObj := &api.Service{Spec: api.ServiceSpec{Port: 12345}} expectedBody, _ := v1beta1.Codec.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 201, diff --git a/pkg/kubecfg/kubecfg.go b/pkg/kubecfg/kubecfg.go index f215c43f14c..d303f2e1fbf 100644 --- a/pkg/kubecfg/kubecfg.go +++ b/pkg/kubecfg/kubecfg.go @@ -309,9 +309,11 @@ func createService(ctx api.Context, name string, port int, client client.Interfa "name": name, }, }, - Port: port, - Selector: map[string]string{ - "name": name, + Spec: api.ServiceSpec{ + Port: port, + Selector: map[string]string{ + "name": name, + }, }, } svc, err := client.Services(api.Namespace(ctx)).Create(svc) diff --git a/pkg/kubecfg/parse_test.go b/pkg/kubecfg/parse_test.go index f630d2a3a35..0f36dd8f6c4 100644 --- a/pkg/kubecfg/parse_test.go +++ b/pkg/kubecfg/parse_test.go @@ -94,9 +94,11 @@ func TestParseService(t *testing.T) { "area": "staging", }, }, - Port: 8080, - Selector: map[string]string{ - "area": "staging", + Spec: api.ServiceSpec{ + Port: 8080, + Selector: map[string]string{ + "area": "staging", + }, }, }, v1beta1.Codec, testParser) } diff --git a/pkg/kubecfg/resource_printer.go b/pkg/kubecfg/resource_printer.go index 1d90e3ee5f9..048e0327a9d 100644 --- a/pkg/kubecfg/resource_printer.go +++ b/pkg/kubecfg/resource_printer.go @@ -227,7 +227,7 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr func printService(svc *api.Service, w io.Writer) error { _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\n", svc.Name, labels.Set(svc.Labels), - labels.Set(svc.Selector), svc.PortalIP, svc.Port) + labels.Set(svc.Spec.Selector), svc.Spec.PortalIP, svc.Spec.Port) return err } diff --git a/pkg/kubectl/describe.go b/pkg/kubectl/describe.go index 4724534c0e8..9960a1f4749 100644 --- a/pkg/kubectl/describe.go +++ b/pkg/kubectl/describe.go @@ -155,8 +155,8 @@ func (d *ServiceDescriber) Describe(namespace, name string) (string, error) { return tabbedString(func(out *tabwriter.Writer) error { fmt.Fprintf(out, "Name:\t%s\n", service.Name) fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(service.Labels)) - fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(service.Selector)) - fmt.Fprintf(out, "Port:\t%d\n", service.Port) + fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(service.Spec.Selector)) + fmt.Fprintf(out, "Port:\t%d\n", service.Spec.Port) return nil }) } diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 1248977924d..8309ef37479 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -245,7 +245,7 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr func printService(svc *api.Service, w io.Writer) error { _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\n", svc.Name, labels.Set(svc.Labels), - labels.Set(svc.Selector), svc.PortalIP, svc.Port) + labels.Set(svc.Spec.Selector), svc.Spec.PortalIP, svc.Spec.Port) return err } diff --git a/pkg/kubelet/config/config_test.go b/pkg/kubelet/config/config_test.go index e1f2ab94092..5c291aa31ff 100644 --- a/pkg/kubelet/config/config_test.go +++ b/pkg/kubelet/config/config_test.go @@ -42,10 +42,7 @@ func (s sortedPods) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s sortedPods) Less(i, j int) bool { - if s[i].Namespace < s[j].Namespace { - return true - } - return s[i].Name < s[j].Name + return s[i].Namespace < s[j].Namespace } func CreateValidPod(name, namespace, source string) api.BoundPod { diff --git a/pkg/master/publish.go b/pkg/master/publish.go index 83d3447ca06..a7f7154cebb 100644 --- a/pkg/master/publish.go +++ b/pkg/master/publish.go @@ -83,11 +83,13 @@ func (m *Master) createMasterServiceIfNeeded(serviceName string, port int) error Name: serviceName, Namespace: "default", }, - Port: port, - // We're going to add the endpoints by hand, so this selector is mainly to - // prevent identification of other pods. This selector will be useful when - // we start hosting apiserver in a pod. - Selector: map[string]string{"provider": "kubernetes", "component": "apiserver"}, + Spec: api.ServiceSpec{ + Port: port, + // We're going to add the endpoints by hand, so this selector is mainly to + // prevent identification of other pods. This selector will be useful when + // we start hosting apiserver in a pod. + Selector: map[string]string{"provider": "kubernetes", "component": "apiserver"}, + }, } // Kids, don't do this at home: this is a hack. There's no good way to call the business // logic which lives in the REST object from here. diff --git a/pkg/proxy/config/config_test.go b/pkg/proxy/config/config_test.go index 67222f2b9cc..5321a9cd106 100644 --- a/pkg/proxy/config/config_test.go +++ b/pkg/proxy/config/config_test.go @@ -136,7 +136,7 @@ func TestNewServiceAddedAndNotified(t *testing.T) { handler := NewServiceHandlerMock() handler.Wait(1) config.RegisterHandler(handler) - serviceUpdate := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Port: 10}) + serviceUpdate := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{Port: 10}}) channel <- serviceUpdate handler.ValidateServices(t, serviceUpdate.Services) @@ -147,12 +147,12 @@ func TestServiceAddedRemovedSetAndNotified(t *testing.T) { channel := config.Channel("one") handler := NewServiceHandlerMock() config.RegisterHandler(handler) - serviceUpdate := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Port: 10}) + serviceUpdate := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{Port: 10}}) handler.Wait(1) channel <- serviceUpdate handler.ValidateServices(t, serviceUpdate.Services) - serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Port: 20}) + serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Spec: api.ServiceSpec{Port: 20}}) handler.Wait(1) channel <- serviceUpdate2 services := []api.Service{serviceUpdate2.Services[0], serviceUpdate.Services[0]} @@ -164,7 +164,7 @@ func TestServiceAddedRemovedSetAndNotified(t *testing.T) { services = []api.Service{serviceUpdate2.Services[0]} handler.ValidateServices(t, services) - serviceUpdate4 := CreateServiceUpdate(SET, api.Service{ObjectMeta: api.ObjectMeta{Name: "foobar"}, Port: 99}) + serviceUpdate4 := CreateServiceUpdate(SET, api.Service{ObjectMeta: api.ObjectMeta{Name: "foobar"}, Spec: api.ServiceSpec{Port: 99}}) handler.Wait(1) channel <- serviceUpdate4 services = []api.Service{serviceUpdate4.Services[0]} @@ -180,8 +180,8 @@ func TestNewMultipleSourcesServicesAddedAndNotified(t *testing.T) { } handler := NewServiceHandlerMock() config.RegisterHandler(handler) - serviceUpdate1 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Port: 10}) - serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Port: 20}) + serviceUpdate1 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{Port: 10}}) + serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Spec: api.ServiceSpec{Port: 20}}) handler.Wait(2) channelOne <- serviceUpdate1 channelTwo <- serviceUpdate2 @@ -197,8 +197,8 @@ func TestNewMultipleSourcesServicesMultipleHandlersAddedAndNotified(t *testing.T handler2 := NewServiceHandlerMock() config.RegisterHandler(handler) config.RegisterHandler(handler2) - serviceUpdate1 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Port: 10}) - serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Port: 20}) + serviceUpdate1 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{Port: 10}}) + serviceUpdate2 := CreateServiceUpdate(ADD, api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}, Spec: api.ServiceSpec{Port: 20}}) handler.Wait(2) handler2.Wait(2) channelOne <- serviceUpdate1 diff --git a/pkg/proxy/config/etcd.go b/pkg/proxy/config/etcd.go index 1d536ed5a46..640c2845cfa 100644 --- a/pkg/proxy/config/etcd.go +++ b/pkg/proxy/config/etcd.go @@ -148,7 +148,7 @@ func (s ConfigSourceEtcd) decodeServices(node *etcd.Node, retServices []api.Serv glog.Errorf("Couldn't get endpoints for %s %s : %v skipping", svc.Namespace, svc.Name, err) endpoints = api.Endpoints{} } else { - glog.V(3).Infof("Got service: %s %s on localport %d mapping to: %s", svc.Namespace, svc.Name, svc.Port, endpoints) + glog.V(3).Infof("Got service: %s %s on localport %d mapping to: %s", svc.Namespace, svc.Name, svc.Spec.Port, endpoints) } retEndpoints = append(retEndpoints, endpoints) } diff --git a/pkg/proxy/proxier.go b/pkg/proxy/proxier.go index 3e6479085f7..9fcafefafd7 100644 --- a/pkg/proxy/proxier.go +++ b/pkg/proxy/proxier.go @@ -435,12 +435,12 @@ func (proxier *Proxier) OnUpdate(services []api.Service) { for _, service := range services { activeServices.Insert(service.Name) info, exists := proxier.getServiceInfo(service.Name) - serviceIP := net.ParseIP(service.PortalIP) + serviceIP := net.ParseIP(service.Spec.PortalIP) // TODO: check health of the socket? What if ProxyLoop exited? - if exists && info.isActive() && info.portalPort == service.Port && info.portalIP.Equal(serviceIP) { + if exists && info.isActive() && info.portalPort == service.Spec.Port && info.portalIP.Equal(serviceIP) { continue } - if exists && (info.portalPort != service.Port || !info.portalIP.Equal(serviceIP)) { + if exists && (info.portalPort != service.Spec.Port || !info.portalIP.Equal(serviceIP)) { glog.V(4).Infof("Something changed for service %q: stopping it", service.Name) err := proxier.closePortal(service.Name, info) if err != nil { @@ -451,14 +451,14 @@ func (proxier *Proxier) OnUpdate(services []api.Service) { glog.Errorf("Failed to stop service %q: %s", service.Name, err) } } - glog.V(1).Infof("Adding new service %q at %s:%d/%s (local :%d)", service.Name, serviceIP, service.Port, service.Protocol, service.ProxyPort) - info, err := proxier.addServiceOnPort(service.Name, service.Protocol, service.ProxyPort, udpIdleTimeout) + glog.V(1).Infof("Adding new service %q at %s:%d/%s (local :%d)", service.Name, serviceIP, service.Spec.Port, service.Spec.Protocol, service.Spec.ProxyPort) + info, err := proxier.addServiceOnPort(service.Name, service.Spec.Protocol, service.Spec.ProxyPort, udpIdleTimeout) if err != nil { glog.Errorf("Failed to start proxy for %q: %+v", service.Name, err) continue } info.portalIP = serviceIP - info.portalPort = service.Port + info.portalPort = service.Spec.Port err = proxier.openPortal(service.Name, info) if err != nil { glog.Errorf("Failed to open portal for %q: %s", service.Name, err) diff --git a/pkg/proxy/proxier_test.go b/pkg/proxy/proxier_test.go index 196a4d5e71e..44d8982f045 100644 --- a/pkg/proxy/proxier_test.go +++ b/pkg/proxy/proxier_test.go @@ -340,7 +340,7 @@ func TestTCPProxyUpdateDeleteUpdate(t *testing.T) { t.Fatalf(err.Error()) } p.OnUpdate([]api.Service{ - {ObjectMeta: api.ObjectMeta{Name: "echo"}, Port: svcInfo.proxyPort, ProxyPort: svcInfo.proxyPort, Protocol: "TCP"}, + {ObjectMeta: api.ObjectMeta{Name: "echo"}, Spec: api.ServiceSpec{Port: svcInfo.proxyPort, Protocol: "TCP", ProxyPort: svcInfo.proxyPort}, Status: api.ServiceStatus{}}, }) testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) } @@ -371,7 +371,7 @@ func TestUDPProxyUpdateDeleteUpdate(t *testing.T) { t.Fatalf(err.Error()) } p.OnUpdate([]api.Service{ - {ObjectMeta: api.ObjectMeta{Name: "echo"}, Port: svcInfo.proxyPort, ProxyPort: svcInfo.proxyPort, Protocol: "UDP"}, + {ObjectMeta: api.ObjectMeta{Name: "echo"}, Spec: api.ServiceSpec{Port: svcInfo.proxyPort, Protocol: "UDP", ProxyPort: svcInfo.proxyPort}, Status: api.ServiceStatus{}}, }) testEchoUDP(t, "127.0.0.1", svcInfo.proxyPort) } @@ -406,7 +406,7 @@ func TestTCPProxyUpdatePort(t *testing.T) { t.Errorf("expected difference, got %d %d", newPort, svcInfo.proxyPort) } p.OnUpdate([]api.Service{ - {ObjectMeta: api.ObjectMeta{Name: "echo"}, Port: newPort, ProxyPort: newPort, Protocol: "TCP"}, + {ObjectMeta: api.ObjectMeta{Name: "echo"}, Spec: api.ServiceSpec{Port: newPort, Protocol: "TCP", ProxyPort: newPort}, Status: api.ServiceStatus{}}, }) if err := waitForClosedPortTCP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) @@ -451,7 +451,7 @@ func TestUDPProxyUpdatePort(t *testing.T) { t.Errorf("expected difference, got %d %d", newPort, svcInfo.proxyPort) } p.OnUpdate([]api.Service{ - {ObjectMeta: api.ObjectMeta{Name: "echo"}, Port: newPort, ProxyPort: newPort, Protocol: "UDP"}, + {ObjectMeta: api.ObjectMeta{Name: "echo"}, Spec: api.ServiceSpec{Port: newPort, Protocol: "UDP", ProxyPort: newPort}, Status: api.ServiceStatus{}}, }) if err := waitForClosedPortUDP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) diff --git a/pkg/registry/etcd/etcd_test.go b/pkg/registry/etcd/etcd_test.go index 60dd13bd4ad..f1367003a18 100644 --- a/pkg/registry/etcd/etcd_test.go +++ b/pkg/registry/etcd/etcd_test.go @@ -1144,27 +1144,28 @@ func TestEtcdUpdateService(t *testing.T) { ctx := api.NewDefaultContext() fakeClient := tools.NewFakeEtcdClient(t) fakeClient.TestIndex = true - key, _ := makeServiceKey(ctx, "foo") - resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Service{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0) + key, _ := makeServiceKey(ctx, "uniquefoo") + resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Service{ObjectMeta: api.ObjectMeta{Name: "uniquefoo"}}), 0) registry := NewTestEtcdRegistry(fakeClient) testService := api.Service{ ObjectMeta: api.ObjectMeta{ - Name: "foo", + Name: "uniquefoo", ResourceVersion: strconv.FormatUint(resp.Node.ModifiedIndex, 10), Labels: map[string]string{ "baz": "bar", }, }, - Selector: map[string]string{ - "baz": "bar", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "baz": "bar", + }, }, } err := registry.UpdateService(ctx, &testService) if err != nil { t.Errorf("unexpected error: %v", err) } - - svc, err := registry.GetService(ctx, "foo") + svc, err := registry.GetService(ctx, "uniquefoo") if err != nil { t.Errorf("unexpected error: %v", err) } diff --git a/pkg/registry/pod/bound_pod_factory_test.go b/pkg/registry/pod/bound_pod_factory_test.go index 7cc94c4e21e..ce0eb21f87c 100644 --- a/pkg/registry/pod/bound_pod_factory_test.go +++ b/pkg/registry/pod/bound_pod_factory_test.go @@ -62,12 +62,14 @@ func TestMakeBoundPodServices(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "test"}, - Port: 8080, - ContainerPort: util.IntOrString{ - Kind: util.IntstrInt, - IntVal: 900, + Spec: api.ServiceSpec{ + Port: 8080, + ContainerPort: util.IntOrString{ + Kind: util.IntstrInt, + IntVal: 900, + }, + PortalIP: "1.2.3.4", }, - PortalIP: "1.2.3.4", }, }, }, @@ -138,12 +140,14 @@ func TestMakeBoundPodServicesExistingEnvVar(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "test"}, - Port: 8080, - ContainerPort: util.IntOrString{ - Kind: util.IntstrInt, - IntVal: 900, + Spec: api.ServiceSpec{ + Port: 8080, + ContainerPort: util.IntOrString{ + Kind: util.IntstrInt, + IntVal: 900, + }, + PortalIP: "1.2.3.4", }, - PortalIP: "1.2.3.4", }, }, }, diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index 8bd1652caf6..cfd7fe5c47d 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -71,18 +71,19 @@ func reloadIPsFromStorage(ipa *ipAllocator, registry Registry) { } for i := range services.Items { service := &services.Items[i] - if service.PortalIP == "" { + if service.Spec.PortalIP == "" { glog.Warningf("service %q has no PortalIP", service.Name) continue } - if err := ipa.Allocate(net.ParseIP(service.PortalIP)); err != nil { + if err := ipa.Allocate(net.ParseIP(service.Spec.PortalIP)); err != nil { // This is really bad. - glog.Errorf("service %q PortalIP %s could not be allocated: %s", service.Name, service.PortalIP, err) + glog.Errorf("service %q PortalIP %s could not be allocated: %s", service.Name, service.Spec.PortalIP, err) } } } func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) { + service := obj.(*api.Service) if !api.ValidNamespace(ctx, &service.ObjectMeta) { return nil, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context")) @@ -93,18 +94,18 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE service.CreationTimestamp = util.Now() - if service.PortalIP == "" { + if service.Spec.PortalIP == "" { // Allocate next available. if ip, err := rs.portalMgr.AllocateNext(); err != nil { return nil, err } else { - service.PortalIP = ip.String() + service.Spec.PortalIP = ip.String() } } else { // Try to respect the requested IP. - if err := rs.portalMgr.Allocate(net.ParseIP(service.PortalIP)); err != nil { + if err := rs.portalMgr.Allocate(net.ParseIP(service.Spec.PortalIP)); err != nil { // TODO: Differentiate "IP already allocated" from real errors. - el := errors.ValidationErrorList{errors.NewFieldInvalid("portalIP", service.PortalIP)} + el := errors.ValidationErrorList{errors.NewFieldInvalid("spec.portalIP", service.Spec.PortalIP)} return nil, errors.NewInvalid("service", service.Name, el) } } @@ -112,8 +113,8 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE return apiserver.MakeAsync(func() (runtime.Object, error) { // TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers // correctly no matter what http operations happen. - service.ProxyPort = 0 - if service.CreateExternalLoadBalancer { + service.Spec.ProxyPort = 0 + if service.Spec.CreateExternalLoadBalancer { if rs.cloud == nil { return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.") } @@ -133,13 +134,13 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE if err != nil { return nil, err } - err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, service.Port, hostsFromMinionList(hosts)) + err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, service.Spec.Port, hostsFromMinionList(hosts)) if err != nil { return nil, err } // External load-balancers require a known port for the service proxy. // TODO: If we end up brokering HostPorts between Pods and Services, this can be any port. - service.ProxyPort = service.Port + service.Spec.ProxyPort = service.Spec.Port } err := rs.registry.CreateService(ctx, service) if err != nil { @@ -162,7 +163,7 @@ func (rs *REST) Delete(ctx api.Context, id string) (<-chan apiserver.RESTResult, if err != nil { return nil, err } - rs.portalMgr.Release(net.ParseIP(service.PortalIP)) + rs.portalMgr.Release(net.ParseIP(service.Spec.PortalIP)) return apiserver.MakeAsync(func() (runtime.Object, error) { rs.deleteExternalLoadBalancer(service) return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(ctx, id) @@ -214,10 +215,10 @@ func GetServiceEnvironmentVariables(ctx api.Context, registry Registry, machine for _, service := range services.Items { // Host name := makeEnvVariableName(service.Name) + "_SERVICE_HOST" - result = append(result, api.EnvVar{Name: name, Value: service.PortalIP}) + result = append(result, api.EnvVar{Name: name, Value: service.Spec.PortalIP}) // Port name = makeEnvVariableName(service.Name) + "_SERVICE_PORT" - result = append(result, api.EnvVar{Name: name, Value: strconv.Itoa(service.Port)}) + result = append(result, api.EnvVar{Name: name, Value: strconv.Itoa(service.Spec.Port)}) // Docker-compatible vars. result = append(result, makeLinkVariables(service)...) } @@ -237,13 +238,13 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RE if err != nil { return nil, err } - if service.PortalIP != cur.PortalIP { + if service.Spec.PortalIP != cur.Spec.PortalIP { // TODO: Would be nice to pass "field is immutable" to users. - el := errors.ValidationErrorList{errors.NewFieldInvalid("portalIP", service.PortalIP)} + el := errors.ValidationErrorList{errors.NewFieldInvalid("spec.portalIP", service.Spec.PortalIP)} return nil, errors.NewInvalid("service", service.Name, el) } // Copy over non-user fields. - service.ProxyPort = cur.ProxyPort + service.Spec.ProxyPort = cur.Spec.ProxyPort // TODO: check to see if external load balancer status changed err = rs.registry.UpdateService(ctx, service) if err != nil { @@ -268,7 +269,7 @@ func (rs *REST) ResourceLocation(ctx api.Context, id string) (string, error) { } func (rs *REST) deleteExternalLoadBalancer(service *api.Service) error { - if !service.CreateExternalLoadBalancer || rs.cloud == nil { + if !service.Spec.CreateExternalLoadBalancer || rs.cloud == nil { return nil } zones, ok := rs.cloud.Zones() @@ -300,18 +301,18 @@ func makeEnvVariableName(str string) string { func makeLinkVariables(service api.Service) []api.EnvVar { prefix := makeEnvVariableName(service.Name) protocol := string(api.ProtocolTCP) - if service.Protocol != "" { - protocol = string(service.Protocol) + if service.Spec.Protocol != "" { + protocol = string(service.Spec.Protocol) } - portPrefix := fmt.Sprintf("%s_PORT_%d_%s", prefix, service.Port, strings.ToUpper(protocol)) + portPrefix := fmt.Sprintf("%s_PORT_%d_%s", prefix, service.Spec.Port, strings.ToUpper(protocol)) return []api.EnvVar{ { Name: prefix + "_PORT", - Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.PortalIP, service.Port), + Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.Spec.PortalIP, service.Spec.Port), }, { Name: portPrefix, - Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.PortalIP, service.Port), + Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.Spec.PortalIP, service.Spec.Port), }, { Name: portPrefix + "_PROTO", @@ -319,11 +320,11 @@ func makeLinkVariables(service api.Service) []api.EnvVar { }, { Name: portPrefix + "_PORT", - Value: strconv.Itoa(service.Port), + Value: strconv.Itoa(service.Spec.Port), }, { Name: portPrefix + "_ADDR", - Value: service.PortalIP, + Value: service.Spec.PortalIP, }, } } diff --git a/pkg/registry/service/rest_test.go b/pkg/registry/service/rest_test.go index 0ddf6435fcc..172ebb6b518 100644 --- a/pkg/registry/service/rest_test.go +++ b/pkg/registry/service/rest_test.go @@ -45,9 +45,11 @@ func TestServiceRegistryCreate(t *testing.T) { machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + }, } ctx := api.NewDefaultContext() c, _ := storage.Create(ctx, svc) @@ -59,11 +61,11 @@ func TestServiceRegistryCreate(t *testing.T) { if created_service.CreationTimestamp.IsZero() { t.Errorf("Expected timestamp to be set, got: %v", created_service.CreationTimestamp) } - if created_service.PortalIP != "1.2.3.1" { - t.Errorf("Unexpected PortalIP: %s", created_service.PortalIP) + if created_service.Spec.PortalIP != "1.2.3.1" { + t.Errorf("Unexpected PortalIP: %s", created_service.Spec.PortalIP) } - if created_service.ProxyPort != 0 { - t.Errorf("Unexpected ProxyPort: %d", created_service.ProxyPort) + if created_service.Spec.ProxyPort != 0 { + t.Errorf("Unexpected ProxyPort: %d", created_service.Spec.ProxyPort) } if len(fakeCloud.Calls) != 0 { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) @@ -82,13 +84,17 @@ func TestServiceStorageValidatesCreate(t *testing.T) { storage := NewREST(registry, nil, nil, makeIPNet(t)) failureCases := map[string]api.Service{ "empty ID": { - Port: 6502, ObjectMeta: api.ObjectMeta{Name: ""}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + }, }, "empty selector": { ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + }, }, } ctx := api.NewDefaultContext() @@ -108,15 +114,19 @@ func TestServiceRegistryUpdate(t *testing.T) { ctx := api.NewDefaultContext() registry := registrytest.NewServiceRegistry() registry.CreateService(ctx, &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz1"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz1"}, + }, }) storage := NewREST(registry, nil, nil, makeIPNet(t)) c, err := storage.Update(ctx, &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz2"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz2"}, + }, }) if c == nil { t.Errorf("Expected non-nil channel") @@ -138,21 +148,27 @@ func TestServiceStorageValidatesUpdate(t *testing.T) { ctx := api.NewDefaultContext() registry := registrytest.NewServiceRegistry() registry.CreateService(ctx, &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + }, }) storage := NewREST(registry, nil, nil, makeIPNet(t)) failureCases := map[string]api.Service{ "empty ID": { - Port: 6502, ObjectMeta: api.ObjectMeta{Name: ""}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + }, }, "empty selector": { - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{}, + }, }, } for _, failureCase := range failureCases { @@ -173,10 +189,12 @@ func TestServiceRegistryExternalService(t *testing.T) { machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, - CreateExternalLoadBalancer: true, + ObjectMeta: api.ObjectMeta{Name: "foo"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + CreateExternalLoadBalancer: true, + }, } c, _ := storage.Create(ctx, svc) <-c @@ -200,10 +218,12 @@ func TestServiceRegistryExternalServiceError(t *testing.T) { machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, - CreateExternalLoadBalancer: true, + ObjectMeta: api.ObjectMeta{Name: "foo"}, + Spec: api.ServiceSpec{ + Port: 6502, + Selector: map[string]string{"bar": "baz"}, + CreateExternalLoadBalancer: true, + }, } ctx := api.NewDefaultContext() c, _ := storage.Create(ctx, svc) @@ -224,7 +244,9 @@ func TestServiceRegistryDelete(t *testing.T) { storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + }, } registry.CreateService(ctx, svc) c, _ := storage.Delete(ctx, svc.Name) @@ -244,9 +266,11 @@ func TestServiceRegistryDeleteExternal(t *testing.T) { machines := []string{"foo", "bar", "baz"} storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, - CreateExternalLoadBalancer: true, + ObjectMeta: api.ObjectMeta{Name: "foo"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + CreateExternalLoadBalancer: true, + }, } registry.CreateService(ctx, svc) c, _ := storage.Delete(ctx, svc.Name) @@ -266,24 +290,30 @@ func TestServiceRegistryMakeLinkVariables(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "foo-bar"}, - Selector: map[string]string{"bar": "baz"}, - Port: 8080, - Protocol: "TCP", - PortalIP: "1.2.3.4", + Spec: api.ServiceSpec{ + Port: 8080, + Selector: map[string]string{"bar": "baz"}, + Protocol: "TCP", + PortalIP: "1.2.3.4", + }, }, { ObjectMeta: api.ObjectMeta{Name: "abc-123"}, - Selector: map[string]string{"bar": "baz"}, - Port: 8081, - Protocol: "UDP", - PortalIP: "5.6.7.8", + Spec: api.ServiceSpec{ + Port: 8081, + Selector: map[string]string{"bar": "baz"}, + Protocol: "UDP", + PortalIP: "5.6.7.8", + }, }, { ObjectMeta: api.ObjectMeta{Name: "q-u-u-x"}, - Selector: map[string]string{"bar": "baz"}, - Port: 8082, - Protocol: "", - PortalIP: "9.8.7.6", + Spec: api.ServiceSpec{ + Port: 8082, + Selector: map[string]string{"bar": "baz"}, + Protocol: "TCP", + PortalIP: "9.8.7.6", + }, }, }, } @@ -334,7 +364,9 @@ func TestServiceRegistryGet(t *testing.T) { storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) registry.CreateService(ctx, &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + }, }) storage.Get(ctx, "foo") if len(fakeCloud.Calls) != 0 { @@ -354,7 +386,9 @@ func TestServiceRegistryResourceLocation(t *testing.T) { storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) registry.CreateService(ctx, &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + }, }) redirector := apiserver.Redirector(storage) location, err := redirector.ResourceLocation(ctx, "foo") @@ -383,11 +417,15 @@ func TestServiceRegistryList(t *testing.T) { storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) registry.CreateService(ctx, &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + }, }) registry.CreateService(ctx, &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo2"}, - Selector: map[string]string{"bar2": "baz2"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar2": "baz2"}, + }, }) registry.List.ResourceVersion = "1" s, _ := storage.List(ctx, labels.Everything(), labels.Everything()) @@ -416,9 +454,11 @@ func TestServiceRegistryIPAllocation(t *testing.T) { rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc1 := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } ctx := api.NewDefaultContext() c1, _ := rest.Create(ctx, svc1) @@ -427,15 +467,16 @@ func TestServiceRegistryIPAllocation(t *testing.T) { if created_service_1.Name != "foo" { t.Errorf("Expected foo, but got %v", created_service_1.Name) } - if created_service_1.PortalIP != "1.2.3.1" { - t.Errorf("Unexpected PortalIP: %s", created_service_1.PortalIP) + if created_service_1.Spec.PortalIP != "1.2.3.1" { + t.Errorf("Unexpected PortalIP: %s", created_service_1.Spec.PortalIP) } svc2 := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "bar"}, - Selector: map[string]string{"bar": "baz"}, - } + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }} ctx = api.NewDefaultContext() c2, _ := rest.Create(ctx, svc2) created_svc2 := <-c2 @@ -443,22 +484,24 @@ func TestServiceRegistryIPAllocation(t *testing.T) { if created_service_2.Name != "bar" { t.Errorf("Expected bar, but got %v", created_service_2.Name) } - if created_service_2.PortalIP != "1.2.3.2" { // new IP - t.Errorf("Unexpected PortalIP: %s", created_service_2.PortalIP) + if created_service_2.Spec.PortalIP != "1.2.3.2" { // new IP + t.Errorf("Unexpected PortalIP: %s", created_service_2.Spec.PortalIP) } svc3 := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "quux"}, - Selector: map[string]string{"bar": "baz"}, - PortalIP: "1.2.3.93", + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + PortalIP: "1.2.3.93", + Port: 6502, + }, } ctx = api.NewDefaultContext() c3, _ := rest.Create(ctx, svc3) created_svc3 := <-c3 created_service_3 := created_svc3.Object.(*api.Service) - if created_service_3.PortalIP != "1.2.3.93" { // specific IP - t.Errorf("Unexpected PortalIP: %s", created_service_3.PortalIP) + if created_service_3.Spec.PortalIP != "1.2.3.93" { // specific IP + t.Errorf("Unexpected PortalIP: %s", created_service_3.Spec.PortalIP) } } @@ -469,9 +512,11 @@ func TestServiceRegistryIPReallocation(t *testing.T) { rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc1 := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } ctx := api.NewDefaultContext() c1, _ := rest.Create(ctx, svc1) @@ -480,17 +525,19 @@ func TestServiceRegistryIPReallocation(t *testing.T) { if created_service_1.Name != "foo" { t.Errorf("Expected foo, but got %v", created_service_1.Name) } - if created_service_1.PortalIP != "1.2.3.1" { - t.Errorf("Unexpected PortalIP: %s", created_service_1.PortalIP) + if created_service_1.Spec.PortalIP != "1.2.3.1" { + t.Errorf("Unexpected PortalIP: %s", created_service_1.Spec.PortalIP) } c, _ := rest.Delete(ctx, created_service_1.Name) <-c svc2 := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "bar"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } ctx = api.NewDefaultContext() c2, _ := rest.Create(ctx, svc2) @@ -499,8 +546,8 @@ func TestServiceRegistryIPReallocation(t *testing.T) { if created_service_2.Name != "bar" { t.Errorf("Expected bar, but got %v", created_service_2.Name) } - if created_service_2.PortalIP != "1.2.3.1" { // same IP as before - t.Errorf("Unexpected PortalIP: %s", created_service_2.PortalIP) + if created_service_2.Spec.PortalIP != "1.2.3.1" { // same IP as before + t.Errorf("Unexpected PortalIP: %s", created_service_2.Spec.PortalIP) } } @@ -511,42 +558,44 @@ func TestServiceRegistryIPUpdate(t *testing.T) { rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } ctx := api.NewDefaultContext() c, _ := rest.Create(ctx, svc) created_svc := <-c created_service := created_svc.Object.(*api.Service) - if created_service.Port != 6502 { - t.Errorf("Expected port 6502, but got %v", created_service.Port) + if created_service.Spec.Port != 6502 { + t.Errorf("Expected port 6502, but got %v", created_service.Spec.Port) } - if created_service.PortalIP != "1.2.3.1" { - t.Errorf("Unexpected PortalIP: %s", created_service.PortalIP) + if created_service.Spec.PortalIP != "1.2.3.1" { + t.Errorf("Unexpected PortalIP: %s", created_service.Spec.PortalIP) } - if created_service.ProxyPort != 0 { - t.Errorf("Unexpected ProxyPort: %d", created_service.ProxyPort) + if created_service.Spec.ProxyPort != 0 { + t.Errorf("Unexpected ProxyPort: %d", created_service.Spec.ProxyPort) } update := new(api.Service) *update = *created_service - update.Port = 6503 - update.ProxyPort = 309 // should be ignored + update.Spec.Port = 6503 + update.Spec.ProxyPort = 309 // should be ignored c, _ = rest.Update(ctx, update) updated_svc := <-c updated_service := updated_svc.Object.(*api.Service) - if updated_service.Port != 6503 { - t.Errorf("Expected port 6503, but got %v", updated_service.Port) + if updated_service.Spec.Port != 6503 { + t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Port) } - if updated_service.ProxyPort != 0 { // unchanged, despite trying - t.Errorf("Unexpected ProxyPort: %d", updated_service.ProxyPort) + if updated_service.Spec.ProxyPort != 0 { // unchanged, despite trying + t.Errorf("Unexpected ProxyPort: %d", updated_service.Spec.ProxyPort) } *update = *created_service - update.Port = 6503 - update.PortalIP = "1.2.3.76" // error + update.Spec.Port = 6503 + update.Spec.PortalIP = "1.2.3.76" // error c, _ = rest.Update(ctx, update) result := <-c @@ -563,23 +612,25 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) { rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, - CreateExternalLoadBalancer: true, + ObjectMeta: api.ObjectMeta{Name: "foo"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + CreateExternalLoadBalancer: true, + }, } ctx := api.NewDefaultContext() c, _ := rest.Create(ctx, svc) created_svc := <-c created_service := created_svc.Object.(*api.Service) - if created_service.Port != 6502 { - t.Errorf("Expected port 6502, but got %v", created_service.Port) + if created_service.Spec.Port != 6502 { + t.Errorf("Expected port 6502, but got %v", created_service.Spec.Port) } - if created_service.PortalIP != "1.2.3.1" { - t.Errorf("Unexpected PortalIP: %s", created_service.PortalIP) + if created_service.Spec.PortalIP != "1.2.3.1" { + t.Errorf("Unexpected PortalIP: %s", created_service.Spec.PortalIP) } - if created_service.ProxyPort != 6502 { - t.Errorf("Unexpected ProxyPort: %d", created_service.ProxyPort) + if created_service.Spec.ProxyPort != 6502 { + t.Errorf("Unexpected ProxyPort: %d", created_service.Spec.ProxyPort) } } @@ -590,17 +641,21 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) { rest1 := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc := &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } ctx := api.NewDefaultContext() c, _ := rest1.Create(ctx, svc) <-c svc = &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } c, _ = rest1.Create(ctx, svc) <-c @@ -609,15 +664,17 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) { rest2 := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t)) svc = &api.Service{ - Port: 6502, ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{"bar": "baz"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"bar": "baz"}, + Port: 6502, + }, } c, _ = rest2.Create(ctx, svc) created_svc := <-c created_service := created_svc.Object.(*api.Service) - if created_service.PortalIP != "1.2.3.3" { - t.Errorf("Unexpected PortalIP: %s", created_service.PortalIP) + if created_service.Spec.PortalIP != "1.2.3.3" { + t.Errorf("Unexpected PortalIP: %s", created_service.Spec.PortalIP) } } diff --git a/pkg/service/endpoints_controller.go b/pkg/service/endpoints_controller.go index f76cec32aa3..93eddb6f893 100644 --- a/pkg/service/endpoints_controller.go +++ b/pkg/service/endpoints_controller.go @@ -57,7 +57,7 @@ func (e *EndpointController) SyncServiceEndpoints() error { continue } glog.Infof("About to update endpoints for service %v", service.Name) - pods, err := e.client.Pods(service.Namespace).List(labels.Set(service.Selector).AsSelector()) + pods, err := e.client.Pods(service.Namespace).List(labels.Set(service.Spec.Selector).AsSelector()) if err != nil { glog.Errorf("Error syncing service: %#v, skipping.", service) resultErr = err @@ -65,7 +65,7 @@ func (e *EndpointController) SyncServiceEndpoints() error { } endpoints := []string{} for _, pod := range pods.Items { - port, err := findPort(&pod.DesiredState.Manifest, service.ContainerPort) + port, err := findPort(&pod.DesiredState.Manifest, service.Spec.ContainerPort) if err != nil { glog.Errorf("Failed to find port for service: %v, %v", service, err) continue diff --git a/pkg/service/endpoints_controller_test.go b/pkg/service/endpoints_controller_test.go index daa3b68457f..4833721304c 100644 --- a/pkg/service/endpoints_controller_test.go +++ b/pkg/service/endpoints_controller_test.go @@ -182,8 +182,10 @@ func TestSyncEndpointsItemsPreexisting(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "foo": "bar", + }, }, }, }, @@ -219,8 +221,10 @@ func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "foo": "bar", + }, }, }, }, @@ -248,8 +252,10 @@ func TestSyncEndpointsItems(t *testing.T) { Items: []api.Service{ { ObjectMeta: api.ObjectMeta{Name: "foo"}, - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "foo": "bar", + }, }, }, }, @@ -277,8 +283,10 @@ func TestSyncEndpointsPodError(t *testing.T) { serviceList := api.ServiceList{ Items: []api.Service{ { - Selector: map[string]string{ - "foo": "bar", + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "foo": "bar", + }, }, }, },