refactor services to v1beta3

This commit is contained in:
markturansky 2014-10-30 09:29:11 -04:00
parent 5a649f2b93
commit bd7643c033
26 changed files with 466 additions and 340 deletions

View File

@ -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 {

View File

@ -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:

View File

@ -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
},

View File

@ -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
},

View File

@ -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"`

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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",
},
},
},
},

View File

@ -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,

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
})
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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.

View File

@ -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

View File

@ -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)
}

View File

@ -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)

View File

@ -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())

View File

@ -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)
}

View File

@ -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",
},
},
},

View File

@ -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,
},
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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",
},
},
},
},