diff --git a/client/alloc_runner_test.go b/client/alloc_runner_test.go index d5228386546d..6b49fcb533f9 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 39a9188de650..7ed4b7f1a050 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 d60c0d744ec0..3bb92e45468e 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 901b655f171a..c4cc2fe2e28e 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 ae9a2c4c5091..4557b6b55303 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 99c66545f164..cfc3f4789b6a 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 87245c136ffd..4bb6062e8f64 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