Move service enviroment vars code.

GetServiceEnvironmentVariables (originally in  pkg/registry/service/rest.go)
is split into two parts: one that lists services, and one that turns
a ServiceList into environment vars.  This will allow a subsequent PR
to add a call to the latter function with an existing ServiceList.
The former part is moved into pkg/registry/pod/bound_pod_factory.go.
The latter part is put in a new package, pkg/kubelet/envvars/envvars.go.
The new package is under kubelet because the container enviroment is more
associated with kubelet than with registry.
Test code moved too.
pull/6/head
Eric Tune 2014-11-21 16:51:29 -08:00
parent 162e4983b9
commit f122fc94bf
6 changed files with 202 additions and 135 deletions

View File

@ -0,0 +1,19 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package envvars is the package that build the environment variables that kubernetes provides
// to the containers run by it.
package envvars

View File

@ -0,0 +1,78 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package envvars
import (
"fmt"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)
// FromServices builds environment variables that a container is started with,
// which tell the container where to find the services it may need, which are
// provided as an argument.
func FromServices(services *api.ServiceList) []api.EnvVar {
var result []api.EnvVar
for _, service := range services.Items {
// Host
name := makeEnvVariableName(service.Name) + "_SERVICE_HOST"
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.Spec.Port)})
// Docker-compatible vars.
result = append(result, makeLinkVariables(service)...)
}
return result
}
func makeEnvVariableName(str string) string {
return strings.ToUpper(strings.Replace(str, "-", "_", -1))
}
func makeLinkVariables(service api.Service) []api.EnvVar {
prefix := makeEnvVariableName(service.Name)
protocol := string(api.ProtocolTCP)
if service.Spec.Protocol != "" {
protocol = string(service.Spec.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.Spec.PortalIP, service.Spec.Port),
},
{
Name: portPrefix,
Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.Spec.PortalIP, service.Spec.Port),
},
{
Name: portPrefix + "_PROTO",
Value: strings.ToLower(protocol),
},
{
Name: portPrefix + "_PORT",
Value: strconv.Itoa(service.Spec.Port),
},
{
Name: portPrefix + "_ADDR",
Value: service.Spec.PortalIP,
},
}
}

View File

@ -0,0 +1,92 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package envvars_test
import (
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
)
func TestFromServices(t *testing.T) {
sl := api.ServiceList{
Items: []api.Service{
{
ObjectMeta: api.ObjectMeta{Name: "foo-bar"},
Spec: api.ServiceSpec{
Port: 8080,
Selector: map[string]string{"bar": "baz"},
Protocol: "TCP",
PortalIP: "1.2.3.4",
},
},
{
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
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"},
Spec: api.ServiceSpec{
Port: 8082,
Selector: map[string]string{"bar": "baz"},
Protocol: "TCP",
PortalIP: "9.8.7.6",
},
},
},
}
vars := envvars.FromServices(&sl)
expected := []api.EnvVar{
{Name: "FOO_BAR_SERVICE_HOST", Value: "1.2.3.4"},
{Name: "FOO_BAR_SERVICE_PORT", Value: "8080"},
{Name: "FOO_BAR_PORT", Value: "tcp://1.2.3.4:8080"},
{Name: "FOO_BAR_PORT_8080_TCP", Value: "tcp://1.2.3.4:8080"},
{Name: "FOO_BAR_PORT_8080_TCP_PROTO", Value: "tcp"},
{Name: "FOO_BAR_PORT_8080_TCP_PORT", Value: "8080"},
{Name: "FOO_BAR_PORT_8080_TCP_ADDR", Value: "1.2.3.4"},
{Name: "ABC_123_SERVICE_HOST", Value: "5.6.7.8"},
{Name: "ABC_123_SERVICE_PORT", Value: "8081"},
{Name: "ABC_123_PORT", Value: "udp://5.6.7.8:8081"},
{Name: "ABC_123_PORT_8081_UDP", Value: "udp://5.6.7.8:8081"},
{Name: "ABC_123_PORT_8081_UDP_PROTO", Value: "udp"},
{Name: "ABC_123_PORT_8081_UDP_PORT", Value: "8081"},
{Name: "ABC_123_PORT_8081_UDP_ADDR", Value: "5.6.7.8"},
{Name: "Q_U_U_X_SERVICE_HOST", Value: "9.8.7.6"},
{Name: "Q_U_U_X_SERVICE_PORT", Value: "8082"},
{Name: "Q_U_U_X_PORT", Value: "tcp://9.8.7.6:8082"},
{Name: "Q_U_U_X_PORT_8082_TCP", Value: "tcp://9.8.7.6:8082"},
{Name: "Q_U_U_X_PORT_8082_TCP_PROTO", Value: "tcp"},
{Name: "Q_U_U_X_PORT_8082_TCP_PORT", Value: "8082"},
{Name: "Q_U_U_X_PORT_8082_TCP_ADDR", Value: "9.8.7.6"},
}
if len(vars) != len(expected) {
t.Errorf("Expected %d env vars, got: %+v", len(expected), vars)
return
}
for i := range expected {
if !reflect.DeepEqual(vars[i], expected[i]) {
t.Errorf("expected %#v, got %#v", vars[i], expected[i])
}
}
}

View File

@ -18,6 +18,7 @@ package pod
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
)
@ -31,8 +32,19 @@ type BasicBoundPodFactory struct {
ServiceRegistry service.Registry
}
// getServiceEnvironmentVariables populates a list of environment variables that are use
// in the container environment to get access to services.
func getServiceEnvironmentVariables(ctx api.Context, registry service.Registry, machine string) ([]api.EnvVar, error) {
var result []api.EnvVar
services, err := registry.ListServices(ctx)
if err != nil {
return result, err
}
return envvars.FromServices(services), nil
}
func (b *BasicBoundPodFactory) MakeBoundPod(machine string, pod *api.Pod) (*api.BoundPod, error) {
envVars, err := service.GetServiceEnvironmentVariables(api.NewContext(), b.ServiceRegistry, machine)
envVars, err := getServiceEnvironmentVariables(api.NewContext(), b.ServiceRegistry, machine)
if err != nil {
return nil, err
}
@ -44,8 +56,6 @@ func (b *BasicBoundPodFactory) MakeBoundPod(machine string, pod *api.Pod) (*api.
boundPod.Spec.Containers[ix].Env = append(container.Env, envVars...)
}
// Make a dummy self link so that references to this bound pod will work.
// TODO: When kubelets get boundPods from apiserver instead of etcd, then
// the selflink should be generated there.
boundPod.SelfLink = "/api/v1beta1/boundPods/" + boundPod.Name
return boundPod, nil
}

View File

@ -20,8 +20,6 @@ import (
"fmt"
"math/rand"
"net"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
@ -211,27 +209,6 @@ func (*REST) New() runtime.Object {
return &api.Service{}
}
// GetServiceEnvironmentVariables populates a list of environment variables that are use
// in the container environment to get access to services.
func GetServiceEnvironmentVariables(ctx api.Context, registry Registry, machine string) ([]api.EnvVar, error) {
var result []api.EnvVar
services, err := registry.ListServices(ctx)
if err != nil {
return result, err
}
for _, service := range services.Items {
// Host
name := makeEnvVariableName(service.Name) + "_SERVICE_HOST"
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.Spec.Port)})
// Docker-compatible vars.
result = append(result, makeLinkVariables(service)...)
}
return result, nil
}
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) {
service := obj.(*api.Service)
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
@ -300,38 +277,3 @@ func (rs *REST) deleteExternalLoadBalancer(service *api.Service) error {
}
return nil
}
func makeEnvVariableName(str string) string {
return strings.ToUpper(strings.Replace(str, "-", "_", -1))
}
func makeLinkVariables(service api.Service) []api.EnvVar {
prefix := makeEnvVariableName(service.Name)
protocol := string(api.ProtocolTCP)
if service.Spec.Protocol != "" {
protocol = string(service.Spec.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.Spec.PortalIP, service.Spec.Port),
},
{
Name: portPrefix,
Value: fmt.Sprintf("%s://%s:%d", strings.ToLower(protocol), service.Spec.PortalIP, service.Spec.Port),
},
{
Name: portPrefix + "_PROTO",
Value: strings.ToLower(protocol),
},
{
Name: portPrefix + "_PORT",
Value: strconv.Itoa(service.Spec.Port),
},
{
Name: portPrefix + "_ADDR",
Value: service.Spec.PortalIP,
},
}
}

View File

@ -19,7 +19,6 @@ package service
import (
"fmt"
"net"
"reflect"
"strings"
"testing"
@ -288,79 +287,6 @@ func TestServiceRegistryDeleteExternal(t *testing.T) {
}
}
func TestServiceRegistryMakeLinkVariables(t *testing.T) {
ctx := api.NewDefaultContext()
registry := registrytest.NewServiceRegistry()
registry.List = api.ServiceList{
Items: []api.Service{
{
ObjectMeta: api.ObjectMeta{Name: "foo-bar"},
Spec: api.ServiceSpec{
Port: 8080,
Selector: map[string]string{"bar": "baz"},
Protocol: "TCP",
PortalIP: "1.2.3.4",
},
},
{
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
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"},
Spec: api.ServiceSpec{
Port: 8082,
Selector: map[string]string{"bar": "baz"},
Protocol: "TCP",
PortalIP: "9.8.7.6",
},
},
},
}
machine := "machine"
vars, err := GetServiceEnvironmentVariables(ctx, registry, machine)
if err != nil {
t.Errorf("Unexpected err: %v", err)
}
expected := []api.EnvVar{
{Name: "FOO_BAR_SERVICE_HOST", Value: "1.2.3.4"},
{Name: "FOO_BAR_SERVICE_PORT", Value: "8080"},
{Name: "FOO_BAR_PORT", Value: "tcp://1.2.3.4:8080"},
{Name: "FOO_BAR_PORT_8080_TCP", Value: "tcp://1.2.3.4:8080"},
{Name: "FOO_BAR_PORT_8080_TCP_PROTO", Value: "tcp"},
{Name: "FOO_BAR_PORT_8080_TCP_PORT", Value: "8080"},
{Name: "FOO_BAR_PORT_8080_TCP_ADDR", Value: "1.2.3.4"},
{Name: "ABC_123_SERVICE_HOST", Value: "5.6.7.8"},
{Name: "ABC_123_SERVICE_PORT", Value: "8081"},
{Name: "ABC_123_PORT", Value: "udp://5.6.7.8:8081"},
{Name: "ABC_123_PORT_8081_UDP", Value: "udp://5.6.7.8:8081"},
{Name: "ABC_123_PORT_8081_UDP_PROTO", Value: "udp"},
{Name: "ABC_123_PORT_8081_UDP_PORT", Value: "8081"},
{Name: "ABC_123_PORT_8081_UDP_ADDR", Value: "5.6.7.8"},
{Name: "Q_U_U_X_SERVICE_HOST", Value: "9.8.7.6"},
{Name: "Q_U_U_X_SERVICE_PORT", Value: "8082"},
{Name: "Q_U_U_X_PORT", Value: "tcp://9.8.7.6:8082"},
{Name: "Q_U_U_X_PORT_8082_TCP", Value: "tcp://9.8.7.6:8082"},
{Name: "Q_U_U_X_PORT_8082_TCP_PROTO", Value: "tcp"},
{Name: "Q_U_U_X_PORT_8082_TCP_PORT", Value: "8082"},
{Name: "Q_U_U_X_PORT_8082_TCP_ADDR", Value: "9.8.7.6"},
}
if len(vars) != len(expected) {
t.Errorf("Expected %d env vars, got: %+v", len(expected), vars)
return
}
for i := range expected {
if !reflect.DeepEqual(vars[i], expected[i]) {
t.Errorf("expected %#v, got %#v", vars[i], expected[i])
}
}
}
func TestServiceRegistryGet(t *testing.T) {
ctx := api.NewDefaultContext()
registry := registrytest.NewServiceRegistry()