Merge pull request #440 from brendandburns/link

Add Docker link style env vars to link containers to services.
This commit is contained in:
Daniel Smith 2014-07-14 16:47:49 -07:00
commit dcbb309e4f
3 changed files with 131 additions and 14 deletions

View File

@ -18,6 +18,8 @@ package api
import ( import (
"github.com/fsouza/go-dockerclient" "github.com/fsouza/go-dockerclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
// Common string formats // Common string formats
@ -267,6 +269,9 @@ type Service struct {
// This service will route traffic to pods having labels matching this selector. // This service will route traffic to pods having labels matching this selector.
Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"` Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"` CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
// Container port to connect to, either a name or a port number
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"`
} }
// Endpoints is a collection of endpoints that implement the actual service, for example: // Endpoints is a collection of endpoints that implement the actual service, for example:

View File

@ -17,9 +17,11 @@ limitations under the License.
package registry package registry
import ( import (
"reflect"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
func TestMakeManifestNoServices(t *testing.T) { func TestMakeManifestNoServices(t *testing.T) {
@ -59,6 +61,10 @@ func TestMakeManifestServices(t *testing.T) {
{ {
JSONBase: api.JSONBase{ID: "test"}, JSONBase: api.JSONBase{ID: "test"},
Port: 8080, Port: 8080,
ContainerPort: util.IntOrString{
Kind: util.IntstrInt,
IntVal: 900,
},
}, },
}, },
}, },
@ -80,12 +86,44 @@ func TestMakeManifestServices(t *testing.T) {
}) })
expectNoError(t, err) expectNoError(t, err)
container := manifest.Containers[0] container := manifest.Containers[0]
if len(container.Env) != 2 || envs := []api.EnvVar{
container.Env[0].Name != "TEST_SERVICE_PORT" || {
container.Env[0].Value != "8080" || Name: "TEST_SERVICE_PORT",
container.Env[1].Name != "SERVICE_HOST" || Value: "8080",
container.Env[1].Value != "machine" { },
t.Errorf("Expected 2 env vars, got: %#v", manifest) {
Name: "TEST_PORT",
Value: "tcp://machine:8080",
},
{
Name: "TEST_PORT_900_TCP",
Value: "tcp://machine:8080",
},
{
Name: "TEST_PORT_900_TCP_PROTO",
Value: "tcp",
},
{
Name: "TEST_PORT_900_TCP_PORT",
Value: "8080",
},
{
Name: "TEST_PORT_900_TCP_ADDR",
Value: "machine",
},
{
Name: "SERVICE_HOST",
Value: "machine",
},
}
if len(container.Env) != 7 {
t.Errorf("Expected 7 env vars, got %d: %#v", len(container.Env), manifest)
return
}
for ix := range container.Env {
if !reflect.DeepEqual(envs[ix], container.Env[ix]) {
t.Errorf("expected %#v, got %#v", envs[ix], container.Env[ix])
}
} }
} }
@ -96,6 +134,10 @@ func TestMakeManifestServicesExistingEnvVar(t *testing.T) {
{ {
JSONBase: api.JSONBase{ID: "test"}, JSONBase: api.JSONBase{ID: "test"},
Port: 8080, Port: 8080,
ContainerPort: util.IntOrString{
Kind: util.IntstrInt,
IntVal: 900,
},
}, },
}, },
}, },
@ -122,13 +164,48 @@ func TestMakeManifestServicesExistingEnvVar(t *testing.T) {
}) })
expectNoError(t, err) expectNoError(t, err)
container := manifest.Containers[0] container := manifest.Containers[0]
if len(container.Env) != 3 ||
container.Env[0].Name != "foo" || envs := []api.EnvVar{
container.Env[0].Value != "bar" || {
container.Env[1].Name != "TEST_SERVICE_PORT" || Name: "foo",
container.Env[1].Value != "8080" || Value: "bar",
container.Env[2].Name != "SERVICE_HOST" || },
container.Env[2].Value != "machine" { {
t.Errorf("Expected no env vars, got: %#v", manifest) Name: "TEST_SERVICE_PORT",
Value: "8080",
},
{
Name: "TEST_PORT",
Value: "tcp://machine:8080",
},
{
Name: "TEST_PORT_900_TCP",
Value: "tcp://machine:8080",
},
{
Name: "TEST_PORT_900_TCP_PROTO",
Value: "tcp",
},
{
Name: "TEST_PORT_900_TCP_PORT",
Value: "8080",
},
{
Name: "TEST_PORT_900_TCP_ADDR",
Value: "machine",
},
{
Name: "SERVICE_HOST",
Value: "machine",
},
}
if len(container.Env) != 8 {
t.Errorf("Expected 8 env vars, got: %#v", manifest)
return
}
for ix := range container.Env {
if !reflect.DeepEqual(envs[ix], container.Env[ix]) {
t.Errorf("expected %#v, got %#v", envs[ix], container.Env[ix])
}
} }
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
type ServiceRegistryStorage struct { type ServiceRegistryStorage struct {
@ -41,6 +42,39 @@ func MakeServiceRegistryStorage(registry ServiceRegistry, cloud cloudprovider.In
} }
} }
func makeLinkVariables(service api.Service, machine string) []api.EnvVar {
prefix := strings.ToUpper(service.ID)
var port string
if service.ContainerPort.Kind == util.IntstrString {
port = service.ContainerPort.StrVal
} else {
port = strconv.Itoa(service.ContainerPort.IntVal)
}
portPrefix := prefix + "_PORT_" + port + "_TCP"
return []api.EnvVar{
{
Name: prefix + "_PORT",
Value: fmt.Sprintf("tcp://%s:%d", machine, service.Port),
},
{
Name: portPrefix,
Value: fmt.Sprintf("tcp://%s:%d", machine, service.Port),
},
{
Name: portPrefix + "_PROTO",
Value: "tcp",
},
{
Name: portPrefix + "_PORT",
Value: strconv.Itoa(service.Port),
},
{
Name: portPrefix + "_ADDR",
Value: machine,
},
}
}
// GetServiceEnvironmentVariables populates a list of environment variables that are use // GetServiceEnvironmentVariables populates a list of environment variables that are use
// in the container environment to get access to services. // in the container environment to get access to services.
func GetServiceEnvironmentVariables(registry ServiceRegistry, machine string) ([]api.EnvVar, error) { func GetServiceEnvironmentVariables(registry ServiceRegistry, machine string) ([]api.EnvVar, error) {
@ -53,6 +87,7 @@ func GetServiceEnvironmentVariables(registry ServiceRegistry, machine string) ([
name := strings.ToUpper(service.ID) + "_SERVICE_PORT" name := strings.ToUpper(service.ID) + "_SERVICE_PORT"
value := strconv.Itoa(service.Port) value := strconv.Itoa(service.Port)
result = append(result, api.EnvVar{Name: name, Value: value}) result = append(result, api.EnvVar{Name: name, Value: value})
result = append(result, makeLinkVariables(service, machine)...)
} }
result = append(result, api.EnvVar{Name: "SERVICE_HOST", Value: machine}) result = append(result, api.EnvVar{Name: "SERVICE_HOST", Value: machine})
return result, nil return result, nil