Pass dynamic ports to the exec driver via environment variables
This commit is contained in:
parent
09249d877c
commit
3e90379f05
|
@ -3,6 +3,7 @@ package driver
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/nomad/client/config"
|
||||
|
@ -101,3 +102,31 @@ func NewExecContext() *ExecContext {
|
|||
ctx := &ExecContext{}
|
||||
return ctx
|
||||
}
|
||||
|
||||
// PopulateEnvironment converts exec context and task configuration into
|
||||
// environment variables so they can be passed along to a driver.
|
||||
//
|
||||
// The output is a list of strings with NAME=value pairs.
|
||||
func PopulateEnvironment(ctx *ExecContext, task *structs.Task) []string {
|
||||
env := []string{}
|
||||
|
||||
env = append(env, fmt.Sprintf("NOMAD_ALLOC_DIR=%s", ctx.AllocDir))
|
||||
env = append(env, fmt.Sprintf("NOMAD_MEMORY_LIMIT=%d", task.Resources.MemoryMB))
|
||||
env = append(env, fmt.Sprintf("NOMAD_CPU_LIMIT=%d", task.Resources.CPU))
|
||||
|
||||
// Meta values
|
||||
for key, value := range task.Meta {
|
||||
env = append(env, fmt.Sprintf("NOMAD_META_%s=%s", strings.ToUpper(key), value))
|
||||
}
|
||||
|
||||
// Named Ports
|
||||
// TODO make this work with multiple network interfaces.
|
||||
network := task.Resources.Networks[0]
|
||||
|
||||
env = append(env, fmt.Sprintf("NOMAD_HOST_IP=%d", network.IP))
|
||||
for idx, port := range network.ListDynamicPorts() {
|
||||
env = append(env, fmt.Sprintf("NOMAD_PORT_%s=%d", strings.ToUpper(network.DynamicPorts[idx]), port))
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
|
|
@ -55,6 +55,9 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
|
|||
return nil, fmt.Errorf("failed to constrain resources: %s", err)
|
||||
}
|
||||
|
||||
// Add the environment
|
||||
cmd.Command().Env = PopulateEnvironment(ctx, task)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("failed to start command: %v", err)
|
||||
}
|
||||
|
|
|
@ -645,6 +645,49 @@ func (n *NetworkResource) GoString() string {
|
|||
return fmt.Sprintf("*%#v", *n)
|
||||
}
|
||||
|
||||
// ListDynamicPorts returns a list of integers that correspond to the labels in
|
||||
// .DynamicPorts. This is a little bit strange and bears some explanation:
|
||||
//
|
||||
// When we request dynamic ports nomad checks to see which ports are available.
|
||||
// Once it finds enough to satisfy our requirements, it sends us an offer and
|
||||
// marks those ports as reserved (or if it can't find enough we get an error).
|
||||
// The complete reserved list includes reserved ports we requested, along with
|
||||
// dynamic ports that nomad found for us. This list is merged together and
|
||||
// becomes the list of ALL reserved ports. (Reserved has a double-meaning.)
|
||||
//
|
||||
// Later when we want to use our dynamic port range, we can call ListDynamicPorts
|
||||
// to get a list of ints that correspond to the list of DyanmicPorts requested
|
||||
// in the jobspec. The indexes in both DynamicPorts and ListDynamicPorts() will
|
||||
// match. DynamicPorts actually holds the Labels while ListDynamicPorts tells us
|
||||
// the port numbers (sorry, a bit confusing).
|
||||
//
|
||||
// Also, be aware that this is intended to be called in the context of
|
||||
// task.Resources after an offer has been made. If you call it in some other
|
||||
// context the behavior is unspecified, including maybe crashing. So don't do that.
|
||||
func (n *NetworkResource) ListDynamicPorts() []int {
|
||||
var ports []int
|
||||
for i := len(n.ReservedPorts) - len(n.DynamicPorts); i < len(n.ReservedPorts); i++ {
|
||||
ports = append(ports, n.ReservedPorts[i])
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
// MapDynamicPorts returns a mapping of Label:PortNumber for dynamic ports
|
||||
// allocated on this NetworkResource. If you need the port order you should use
|
||||
// ListDynamicPorts instead.
|
||||
//
|
||||
// See caveats in ListDynamicPorts
|
||||
func (n *NetworkResource) MapDynamicPorts() map[string]int {
|
||||
ports := n.ListDynamicPorts()
|
||||
mapping := map[string]int{}
|
||||
|
||||
for idx, label := range n.DynamicPorts {
|
||||
mapping[label] = ports[idx]
|
||||
}
|
||||
|
||||
return mapping
|
||||
}
|
||||
|
||||
const (
|
||||
// JobTypeNomad is reserved for internal system tasks and is
|
||||
// always handled by the CoreScheduler.
|
||||
|
|
|
@ -266,6 +266,37 @@ func TestResource_Add_Network(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListDynamicPorts(t *testing.T) {
|
||||
resources := &NetworkResource{
|
||||
ReservedPorts: []int{80, 443, 3306, 8080},
|
||||
DynamicPorts: []string{"mysql", "admin"},
|
||||
}
|
||||
|
||||
expected := []int{3306, 8080}
|
||||
actual := resources.ListDynamicPorts()
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Fatalf("Expected %#v; found %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapDynamicPorts(t *testing.T) {
|
||||
resources := &NetworkResource{
|
||||
ReservedPorts: []int{80, 443, 3306, 8080},
|
||||
DynamicPorts: []string{"mysql", "admin"},
|
||||
}
|
||||
|
||||
expected := map[string]int{
|
||||
"mysql": 3306,
|
||||
"admin": 8080,
|
||||
}
|
||||
actual := resources.MapDynamicPorts()
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Fatalf("Expected %#v; found %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
type FooRequest struct {
|
||||
Foo string
|
||||
|
|
Loading…
Reference in New Issue