Merge branch 'master' of github.com:hashicorp/nomad

This commit is contained in:
Alex Dadgar 2016-03-28 14:34:05 -07:00
commit 5512d69438
9 changed files with 145 additions and 14 deletions

View file

@ -20,6 +20,7 @@ IMPROVEMENTS:
* client: Allow task's to be run as particular user [GH-950, GH-978]
* client: `artifact` block now supports downloading paths relative to the
task's directory [GH-944]
* discovery: Support script based health checks [GH-986]
BUG FIXES:
* core: Fix issue where in-place updated allocation double counted resources

8
Godeps/Godeps.json generated
View file

@ -255,13 +255,13 @@
},
{
"ImportPath": "github.com/hashicorp/consul/api",
"Comment": "v0.6.3-290-ge3f6c6a",
"Rev": "e3f6c6a7987ff879a1c138abcc4d14d8b65fc13f"
"Comment": "v0.6.3-363-gae32a3c",
"Rev": "ae32a3ceae9fddb431b933ed7b2a82110e41e1bf"
},
{
"ImportPath": "github.com/hashicorp/consul/tlsutil",
"Comment": "v0.6.3-290-ge3f6c6a",
"Rev": "e3f6c6a7987ff879a1c138abcc4d14d8b65fc13f"
"Comment": "v0.6.3-363-gae32a3c",
"Rev": "ae32a3ceae9fddb431b933ed7b2a82110e41e1bf"
},
{
"ImportPath": "github.com/hashicorp/errwrap",

View file

@ -44,6 +44,9 @@ type ConsulConfig struct {
Auth string
EnableSSL bool
VerifySSL bool
CAFile string
CertFile string
KeyFile string
}
const (
@ -83,6 +86,20 @@ func NewConsulService(config *ConsulConfig, logger *log.Logger, allocID string)
}
if config.EnableSSL {
cfg.Scheme = "https"
tlsCfg := consul.TLSConfig{
Address: cfg.Address,
CAFile: config.CAFile,
CertFile: config.CertFile,
KeyFile: config.KeyFile,
InsecureSkipVerify: !config.VerifySSL,
}
tlsClientCfg, err := consul.SetupTLSConfig(&tlsCfg)
if err != nil {
return nil, fmt.Errorf("error creating tls client config for consul: %v", err)
}
cfg.HttpClient.Transport = &http.Transport{
TLSClientConfig: tlsClientCfg,
}
}
if config.EnableSSL && !config.VerifySSL {
cfg.HttpClient.Transport = &http.Transport{

View file

@ -523,7 +523,7 @@ func (e *UniversalExecutor) createCheck(check *structs.ServiceCheck, checkID str
interval: check.Interval,
containerID: e.consulCtx.ContainerID,
logger: e.logger,
cmd: check.Cmd,
cmd: check.Command,
args: check.Args,
}, nil
}
@ -532,7 +532,7 @@ func (e *UniversalExecutor) createCheck(check *structs.ServiceCheck, checkID str
return &ExecScriptCheck{
id: checkID,
interval: check.Interval,
cmd: check.Cmd,
cmd: check.Command,
args: check.Args,
taskDir: e.taskDir,
FSIsolation: e.command.FSIsolation,

View file

@ -79,6 +79,9 @@ func consulContext(clientConfig *config.Config, containerID string) *executor.Co
Auth: clientConfig.Read("consul.auth"),
EnableSSL: clientConfig.ReadBoolDefault("consul.ssl", false),
VerifySSL: clientConfig.ReadBoolDefault("consul.verifyssl", true),
CAFile: clientConfig.Read("consul.tls_ca_file"),
CertFile: clientConfig.Read("consul.tls_cert_file"),
KeyFile: clientConfig.Read("consul.tls_key_file"),
}
return &executor.ConsulContext{
ConsulConfig: &cfg,

View file

@ -750,7 +750,7 @@ func parseChecks(service *structs.Service, checkObjs *ast.ObjectList) error {
"timeout",
"path",
"protocol",
"cmd",
"command",
"args",
}
if err := checkHCLKeys(co.Val, valid); err != nil {

View file

@ -1411,7 +1411,7 @@ const (
type ServiceCheck struct {
Name string // Name of the check, defaults to id
Type string // Type of the check - tcp, http, docker and script
Cmd string // Cmd is the command to run for script checks
Command string // Command is the command to run for script checks
Args []string // Args is a list of argumes for script checks
Path string // path of the health check url for http type check
Protocol string // Protocol to use if check is http, defaults to http
@ -1437,7 +1437,7 @@ func (sc *ServiceCheck) Validate() error {
return fmt.Errorf("service checks of http type must have a valid http path")
}
if sc.Type == ServiceCheckScript && sc.Cmd == "" {
if sc.Type == ServiceCheckScript && sc.Command == "" {
return fmt.Errorf("service checks of script type must have a valid script path")
}
@ -1452,7 +1452,7 @@ func (sc *ServiceCheck) Hash(serviceID string) string {
io.WriteString(h, serviceID)
io.WriteString(h, sc.Name)
io.WriteString(h, sc.Type)
io.WriteString(h, sc.Cmd)
io.WriteString(h, sc.Command)
io.WriteString(h, strings.Join(sc.Args, ""))
io.WriteString(h, sc.Path)
io.WriteString(h, sc.Protocol)

View file

@ -3,9 +3,11 @@ package api
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@ -122,6 +124,30 @@ type Config struct {
Token string
}
// TLSConfig is used to generate a TLSClientConfig that's useful for talking to
// Consul using TLS.
type TLSConfig struct {
// Address is the optional address of the Consul server. The port, if any
// will be removed from here and this will be set to the ServerName of the
// resulting config.
Address string
// CAFile is the optional path to the CA certificate used for Consul
// communication, defaults to the system bundle if not specified.
CAFile string
// CertFile is the optional path to the certificate for Consul
// communication. If this is set then you need to also set KeyFile.
CertFile string
// KeyFile is the optional path to the private key for Consul communication.
// If this is set then you need to also set CertFile.
KeyFile string
// InsecureSkipVerify if set to true will disable TLS host verification.
InsecureSkipVerify bool
}
// DefaultConfig returns a default configuration for the client. By default this
// will pool and reuse idle connections to Consul. If you have a long-lived
// client object, this is the desired behavior and should make the most efficient
@ -194,10 +220,19 @@ func defaultConfig(transportFn func() *http.Transport) *Config {
}
if !doVerify {
transport := transportFn()
transport.TLSClientConfig = &tls.Config{
tlsClientConfig, err := SetupTLSConfig(&TLSConfig{
InsecureSkipVerify: true,
})
// We don't expect this to fail given that we aren't
// parsing any of the input, but we panic just in case
// since this doesn't have an error return.
if err != nil {
panic(err)
}
transport := transportFn()
transport.TLSClientConfig = tlsClientConfig
config.HttpClient.Transport = transport
}
}
@ -205,6 +240,50 @@ func defaultConfig(transportFn func() *http.Transport) *Config {
return config
}
// TLSConfig is used to generate a TLSClientConfig that's useful for talking to
// Consul using TLS.
func SetupTLSConfig(tlsConfig *TLSConfig) (*tls.Config, error) {
tlsClientConfig := &tls.Config{
InsecureSkipVerify: tlsConfig.InsecureSkipVerify,
}
if tlsConfig.Address != "" {
server := tlsConfig.Address
hasPort := strings.LastIndex(server, ":") > strings.LastIndex(server, "]")
if hasPort {
var err error
server, _, err = net.SplitHostPort(server)
if err != nil {
return nil, err
}
}
tlsClientConfig.ServerName = server
}
if tlsConfig.CertFile != "" && tlsConfig.KeyFile != "" {
tlsCert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
if err != nil {
return nil, err
}
tlsClientConfig.Certificates = []tls.Certificate{tlsCert}
}
if tlsConfig.CAFile != "" {
data, err := ioutil.ReadFile(tlsConfig.CAFile)
if err != nil {
return nil, fmt.Errorf("failed to read CA file: %v", err)
}
caPool := x509.NewCertPool()
if !caPool.AppendCertsFromPEM(data) {
return nil, fmt.Errorf("failed to parse CA certificate")
}
tlsClientConfig.RootCAs = caPool
}
return tlsClientConfig, nil
}
// Client provides a client to the Consul API
type Client struct {
config Config

View file

@ -37,6 +37,20 @@ Nomad does not currently run Consul for you.
* `consul.verifyssl`: This option enables SSL verification when the transport
scheme for the Consul API client is `https`. This is set to true by default.
* `consul.tls_ca_file`: The path to the CA certificate used for Consul communication.
Set accordingly to the
[ca_file](https://www.consul.io/docs/agent/options.html#ca_file) setting in
Consul.
* `consul.tls_cert_file`: The path to the certificate for Consul communication. Set
accordingly
[cert_file](https://www.consul.io/docs/agent/options.html#cert_file) in
Consul.
* `consul.tls_key_file`: The path to the private key for Consul communication.
Set accordingly to the
[key_file](https://www.consul.io/docs/agent/options.html#key_file) setting in
Consul.
## Service Definition Syntax
@ -61,6 +75,14 @@ group "database" {
interval = "10s"
timeout = "2s"
}
check {
type = "script"
name = "check_table"
cmd = "/usr/local/bin/check_mysql_table_status"
args = ["--verbose"]
interval = "60s"
timeout = "5s"
}
}
resources {
cpu = 500
@ -97,8 +119,10 @@ group "database" {
with Consul.
* `check`: A check block defines a health check associated with the service.
Multiple check blocks are allowed for a service. Nomad currently supports
only the `http` and `tcp` Consul Checks.
Multiple check blocks are allowed for a service. Nomad supports the `script`,
`http` and `tcp` Consul Checks. Script checks are not supported for the qemu
driver since the Nomad client doesn't have access to the file system of a
tasks using the Qemu driver.
### Check Syntax
@ -120,8 +144,15 @@ group "database" {
* `protocol`: This indicates the protocol for the http checks. Valid options
are `http` and `https`. We default it to `http`
* `command`: This is the command that the Nomad client runs for doing script based
health check.
* `args`: Additional arguments to the `command` for script based health checks.
## Assumptions
* Consul 0.6.4 or later is needed for using the Script checks.
* Consul 0.6.0 or later is needed for using the TCP checks.
* The service discovery feature in Nomad depends on operators making sure that