diff --git a/client/alloc_runner_test.go b/client/alloc_runner_test.go index d5228386546..6b49fcb533f 100644 --- a/client/alloc_runner_test.go +++ b/client/alloc_runner_test.go @@ -31,7 +31,7 @@ func testAllocRunner(restarts bool) (*MockAllocStateUpdater, *AllocRunner) { conf.AllocDir = os.TempDir() upd := &MockAllocStateUpdater{} alloc := mock.Alloc() - consulClient, _ := NewConsulService(logger, "127.0.0.1:8500") + consulClient, _ := NewConsulService(logger, "127.0.0.1:8500", "", "", false, false) if !restarts { alloc.Job.Type = structs.JobTypeBatch *alloc.Job.LookupTaskGroup(alloc.TaskGroup).RestartPolicy = structs.RestartPolicy{Attempts: 0} @@ -142,7 +142,7 @@ func TestAllocRunner_SaveRestoreState(t *testing.T) { } // Create a new alloc runner - consulClient, err := NewConsulService(ar.logger, "127.0.0.1:8500") + consulClient, err := NewConsulService(ar.logger, "127.0.0.1:8500", "", "", false, false) ar2 := NewAllocRunner(ar.logger, ar.config, upd.Update, &structs.Allocation{ID: ar.alloc.ID}, consulClient) err = ar2.RestoreState() diff --git a/client/client.go b/client/client.go index 39a9188de65..7ed4b7f1a05 100644 --- a/client/client.go +++ b/client/client.go @@ -98,22 +98,19 @@ func NewClient(cfg *config.Config) (*Client, error) { // Create a logger logger := log.New(cfg.LogOutput, "", log.LstdFlags) - // Create the consul service - consulAddr := cfg.ReadDefault("consul.address", "127.0.0.1:8500") - consulService, err := NewConsulService(logger, consulAddr) - if err != nil { - return nil, fmt.Errorf("failed to create the consul client: %v", err) - } - // Create the client c := &Client{ - config: cfg, - start: time.Now(), - consulService: consulService, - connPool: nomad.NewPool(cfg.LogOutput, clientRPCCache, clientMaxStreams, nil), - logger: logger, - allocs: make(map[string]*AllocRunner), - shutdownCh: make(chan struct{}), + config: cfg, + start: time.Now(), + connPool: nomad.NewPool(cfg.LogOutput, clientRPCCache, clientMaxStreams, nil), + logger: logger, + allocs: make(map[string]*AllocRunner), + shutdownCh: make(chan struct{}), + } + + // Setup the Consul Service + if err := c.setupConsulService(); err != nil { + return nil, fmt.Errorf("failed to create the consul service: %v", err) } // Initialize the client @@ -152,6 +149,21 @@ func NewClient(cfg *config.Config) (*Client, error) { return c, nil } +func (c *Client) setupConsulService() error { + var consulService *ConsulService + var err error + addr := c.config.ReadDefault("consul.address", "127.0.0.1:8500") + token := c.config.Read("consul.token") + auth := c.config.Read("consul.auth") + enableSSL := c.config.ReadBoolDefault("consul.ssl", false) + verifySSL := c.config.ReadBoolDefault("consul.verifyssl", false) + if consulService, err = NewConsulService(c.logger, addr, token, auth, enableSSL, verifySSL); err != nil { + return err + } + c.consulService = consulService + return nil +} + // init is used to initialize the client and perform any setup // needed before we begin starting its various components. func (c *Client) init() error { diff --git a/client/consul.go b/client/consul.go index d60c0d744ec..3bb92e45468 100644 --- a/client/consul.go +++ b/client/consul.go @@ -1,9 +1,12 @@ package client import ( + "crypto/tls" "fmt" "log" + "net/http" "net/url" + "strings" "sync" "time" @@ -53,11 +56,42 @@ type ConsulService struct { trackedTskLock sync.Mutex } -func NewConsulService(logger *log.Logger, consulAddr string) (*ConsulService, error) { +func NewConsulService(logger *log.Logger, consulAddr string, token string, + auth string, enableSSL bool, verifySSL bool) (*ConsulService, error) { var err error var c *consul.Client cfg := consul.DefaultConfig() cfg.Address = consulAddr + if token != "" { + cfg.Token = token + } + + if auth != "" { + var username, password string + if strings.Contains(auth, ":") { + split := strings.SplitN(auth, ":", 2) + username = split[0] + password = split[1] + } else { + username = auth + } + + cfg.HttpAuth = &consul.HttpBasicAuth{ + Username: username, + Password: password, + } + } + if enableSSL { + cfg.Scheme = "https" + } + if enableSSL && !verifySSL { + cfg.HttpClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + + } if c, err = consul.NewClient(cfg); err != nil { return nil, err } diff --git a/client/consul_test.go b/client/consul_test.go index 901b655f171..c4cc2fe2e28 100644 --- a/client/consul_test.go +++ b/client/consul_test.go @@ -10,7 +10,7 @@ import ( func newConsulService() *ConsulService { logger := log.New(os.Stdout, "logger: ", log.Lshortfile) - c, _ := NewConsulService(logger, "") + c, _ := NewConsulService(logger, "", "", "", false, false) return c } diff --git a/client/task_runner_test.go b/client/task_runner_test.go index ae9a2c4c509..4557b6b5530 100644 --- a/client/task_runner_test.go +++ b/client/task_runner_test.go @@ -32,7 +32,7 @@ func testTaskRunner(restarts bool) (*MockTaskStateUpdater, *TaskRunner) { upd := &MockTaskStateUpdater{} alloc := mock.Alloc() task := alloc.Job.TaskGroups[0].Tasks[0] - consulClient, _ := NewConsulService(logger, "127.0.0.1:8500") + consulClient, _ := NewConsulService(logger, "127.0.0.1:8500", "", "", false, false) // Initialize the port listing. This should be done by the offer process but // we have a mock so that doesn't happen. task.Resources.Networks[0].ReservedPorts = []structs.Port{{"", 80}} @@ -164,7 +164,7 @@ func TestTaskRunner_SaveRestoreState(t *testing.T) { } // Create a new task runner - consulClient, _ := NewConsulService(tr.logger, "127.0.0.1:8500") + consulClient, _ := NewConsulService(tr.logger, "127.0.0.1:8500", "", "", false, false) tr2 := NewTaskRunner(tr.logger, tr.config, upd.Update, tr.ctx, tr.allocID, &structs.Task{Name: tr.task.Name}, tr.state, tr.restartTracker, consulClient) diff --git a/website/source/docs/agent/config.html.md b/website/source/docs/agent/config.html.md index 99c66545f16..cfc3f4789b6 100644 --- a/website/source/docs/agent/config.html.md +++ b/website/source/docs/agent/config.html.md @@ -231,6 +231,19 @@ documentation [here](/docs/drivers/index.html) `host:port`. The default is the same as the Consul default address, `127.0.0.1:8500`. +* `consul.token`: Token is used to provide a per-request ACL token.This options + overrides the agent's default token + +* `consul.auth`: The auth information to use for http access to the Consul + Agent. + +* `consul.ssl`: This boolean option sets the transport scheme to talk to the Consul + Agent as `https`. This option is unset by default and so the default transport + scheme for the consul api client is `http`. + +* `consul.verifyssl`: This option disables SSL verification when the transport + scheme for the Consul API client is `https`. This is set to true by default. + * `driver.whitelist`: A comma seperated list of whitelisted drivers (e.g. "docker,qemu"). If specified, drivers not in the whitelist will be disabled. If the whitelist is empty, all drivers are fingerprinted and enabled where diff --git a/website/source/docs/jobspec/servicediscovery.html.md b/website/source/docs/jobspec/servicediscovery.html.md index 87245c136ff..4bb6062e8f6 100644 --- a/website/source/docs/jobspec/servicediscovery.html.md +++ b/website/source/docs/jobspec/servicediscovery.html.md @@ -24,6 +24,20 @@ Nomad does not currently run Consul for you. override the default Consul Agent HTTP port that Nomad uses to connect to Consul. The default for this is `127.0.0.1:8500`. +* `consul.token`: Token is used to provide a per-request ACL token.This options + overrides the agent's default token + +* `consul.auth`: The auth information to use for http access to the Consul + Agent. + +* `consul.ssl`: This boolean option sets the transport scheme to talk to the Consul + Agent as `https`. This option is unset by default and so the default transport + scheme for the consul api client is `http`. + +* `consul.verifyssl`: This option disables SSL verification when the transport + scheme for the Consul API client is `https`. This is set to true by default. + + ## Service Definition Syntax The service blocks in a Task definition defines a service which Nomad will