diff --git a/pkg/api/types.go b/pkg/api/types.go index e6400b27733..2a5c550f937 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -17,9 +17,8 @@ limitations under the License. package api import ( - "github.com/fsouza/go-dockerclient" - "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/fsouza/go-dockerclient" ) // Common string formats @@ -270,7 +269,8 @@ type Service struct { Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` - // Container port to connect to, either a name or a port number + // 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"` } diff --git a/pkg/registry/endpoints.go b/pkg/registry/endpoints.go index ab00a911c58..10a1db2be7b 100644 --- a/pkg/registry/endpoints.go +++ b/pkg/registry/endpoints.go @@ -17,11 +17,13 @@ limitations under the License. package registry import ( + "fmt" "net" "strconv" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/golang/glog" ) @@ -37,6 +39,26 @@ type EndpointController struct { podRegistry PodRegistry } +func findPort(manifest *api.ContainerManifest, portName util.IntOrString) (int, error) { + if ((portName.Kind == util.IntstrString && len(portName.StrVal) == 0) || + (portName.Kind == util.IntstrInt && portName.IntVal == 0)) && + len(manifest.Containers[0].Ports) > 0 { + return manifest.Containers[0].Ports[0].ContainerPort, nil + } + if portName.Kind == util.IntstrInt { + return portName.IntVal, nil + } + name := portName.StrVal + for _, container := range manifest.Containers { + for _, port := range container.Ports { + if port.Name == name { + return port.ContainerPort, nil + } + } + } + return -1, fmt.Errorf("no suitable port for manifest: %s", manifest.ID) +} + func (e *EndpointController) SyncServiceEndpoints() error { services, err := e.serviceRegistry.ListServices() if err != nil { @@ -52,11 +74,12 @@ func (e *EndpointController) SyncServiceEndpoints() error { } endpoints := make([]string, len(pods)) for ix, pod := range pods { - // TODO: Use port names in the service object, don't just use port #0 - endpoints[ix] = net.JoinHostPort( - pod.CurrentState.Host, - strconv.Itoa(pod.DesiredState.Manifest.Containers[0].Ports[0].HostPort), - ) + port, err := findPort(&pod.DesiredState.Manifest, service.ContainerPort) + if err != nil { + glog.Errorf("Failed to find port for service: %v, %v", service, err) + continue + } + endpoints[ix] = net.JoinHostPort(pod.CurrentState.PodIP, strconv.Itoa(port)) } err = e.serviceRegistry.UpdateEndpoints(api.Endpoints{ Name: service.ID, diff --git a/pkg/registry/endpoints_test.go b/pkg/registry/endpoints_test.go index 71250d04c69..8581bbae701 100644 --- a/pkg/registry/endpoints_test.go +++ b/pkg/registry/endpoints_test.go @@ -21,8 +21,62 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) +func TestFindPort(t *testing.T) { + manifest := api.ContainerManifest{ + Containers: []api.Container{ + { + Ports: []api.Port{ + { + Name: "foo", + ContainerPort: 8080, + HostPort: 9090, + }, + { + Name: "bar", + ContainerPort: 8000, + HostPort: 9000, + }, + }, + }, + }, + } + port, err := findPort(&manifest, util.IntOrString{Kind: util.IntstrString, StrVal: "foo"}) + expectNoError(t, err) + if port != 8080 { + t.Errorf("Expected 8080, Got %d", port) + } + port, err = findPort(&manifest, util.IntOrString{Kind: util.IntstrString, StrVal: "bar"}) + expectNoError(t, err) + if port != 8000 { + t.Errorf("Expected 8000, Got %d", port) + } + port, err = findPort(&manifest, util.IntOrString{Kind: util.IntstrInt, IntVal: 8000}) + if port != 8000 { + t.Errorf("Expected 8000, Got %d", port) + } + port, err = findPort(&manifest, util.IntOrString{Kind: util.IntstrInt, IntVal: 7000}) + if port != 7000 { + t.Errorf("Expected 7000, Got %d", port) + } + port, err = findPort(&manifest, util.IntOrString{Kind: util.IntstrString, StrVal: "baz"}) + if err == nil { + t.Error("unexpected non-error") + } + port, err = findPort(&manifest, util.IntOrString{Kind: util.IntstrString, StrVal: ""}) + expectNoError(t, err) + if port != 8080 { + t.Errorf("Expected 8080, Got %d", port) + } + port, err = findPort(&manifest, util.IntOrString{}) + expectNoError(t, err) + if port != 8080 { + t.Errorf("Expected 8080, Got %d", port) + } +} + func TestSyncEndpointsEmpty(t *testing.T) { serviceRegistry := MockServiceRegistry{} podRegistry := MockPodRegistry{}