From 89ae6f13aec9daffe9d48d4288210df685c6b90b Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 7 Jul 2020 17:23:04 -0400 Subject: [PATCH 01/15] command/debug: build the archive with the timestamp dir --- command/debug.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/command/debug.go b/command/debug.go index 26ae5ef0d77..265a66ea830 100644 --- a/command/debug.go +++ b/command/debug.go @@ -229,7 +229,7 @@ func (c *DebugCommand) Run(args []string) int { } archiveFile := stamped + ".tar.gz" - err = TarCZF(archiveFile, tmp) + err = TarCZF(archiveFile, tmp, stamped) if err != nil { c.Ui.Error(fmt.Sprintf("Error creating archive: %s", err.Error())) return 2 @@ -669,8 +669,8 @@ func (c *DebugCommand) trap() { } // TarCZF, like the tar command, recursively builds a gzip compressed tar archive from a -// directory -func TarCZF(archive string, src string) error { +// directory. If not empty, all files in the bundle are prefixed with the target path +func TarCZF(archive string, src, target string) error { // ensure the src actually exists before trying to tar it if _, err := os.Stat(src); err != nil { return fmt.Errorf("Unable to tar files - %v", err.Error()) @@ -707,7 +707,13 @@ func TarCZF(archive string, src string) error { } // remove leading path to the src, so files are relative to the archive - header.Name = strings.TrimPrefix(strings.Replace(file, src, "", -1), string(filepath.Separator)) + path := strings.Replace(file, src, "", -1) + if target != "" { + path = filepath.Join([]string{target, path}...) + } + path = strings.TrimPrefix(path, string(filepath.Separator)) + + header.Name = path if err := tw.WriteHeader(header); err != nil { return err From a390e10ebe81c0aca7f0319bef7455bfa1b69392 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Fri, 10 Jul 2020 11:31:06 -0400 Subject: [PATCH 02/15] command/debug: print interval data so the operator knows its waiting --- command/debug.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/command/debug.go b/command/debug.go index 265a66ea830..972d72ae6b9 100644 --- a/command/debug.go +++ b/command/debug.go @@ -187,12 +187,17 @@ func (c *DebugCommand) Run(args []string) int { ctx, cancel := context.WithCancel(context.Background()) c.ctx = ctx c.cancel = cancel + c.trap() - // Setup the output path format := "2006-01-02-150405Z" c.timestamp = time.Now().UTC().Format(format) stamped := "nomad-debug-" + c.timestamp + c.Ui.Output("==> Starting debugger and capturing cluster data...") + c.Ui.Output(fmt.Sprintf(" Interval: '%s'", interval)) + c.Ui.Output(fmt.Sprintf(" Duration: '%s'", duration)) + + // Create the output path var tmp string if output != "" { tmp = filepath.Join(output, stamped) @@ -212,15 +217,16 @@ func (c *DebugCommand) Run(args []string) int { c.collectDir = tmp - // Capture signals so we can shutdown the monitor API calls on Int - c.trap() - err = c.collect(client) if err != nil { c.Ui.Error(fmt.Sprintf("Error collecting data: %s", err.Error())) return 2 } + if c.ctx.Err() != nil { + return 2 + } + c.writeManifest() if output != "" { @@ -278,11 +284,11 @@ func (c *DebugCommand) collect(client *api.Client) error { c.collectConsul(dir, consul) c.collectVault(dir, vault) + c.collectAgentHosts(client) + c.collectPprofs(client) c.startMonitors(client) c.collectPeriodic(client) - c.collectPprofs(client) - c.collectAgentHosts(client) return nil } @@ -424,16 +430,17 @@ func (c *DebugCommand) collectPprof(path, id string, client *api.Client) { func (c *DebugCommand) collectPeriodic(client *api.Client) { // Not monitoring any logs, just capture the nomad context before exit if len(c.nodeIDs) == 0 && len(c.serverIDs) == 0 { - dir := filepath.Join("nomad", "00") + dir := filepath.Join("nomad", "0000") c.collectNomad(dir, client) return } + start := time.Now().Unix() duration := time.After(c.duration) // Set interval to 0 so that we immediately execute, wait the interval next time interval := time.After(0 * time.Second) var intervalCount int - var dir string + var name, dir string for { select { @@ -442,7 +449,9 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { return case <-interval: - dir = filepath.Join("nomad", fmt.Sprintf("%02d", intervalCount)) + name = fmt.Sprintf("%04d", time.Now().Unix()-start) + dir = filepath.Join("nomad", name) + c.Ui.Output(fmt.Sprintf("==> Capture interval %s", name)) c.collectNomad(dir, client) interval = time.After(c.interval) intervalCount += 1 From 372ce1f63594559fe79610a88400909a9f8f24f0 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 14 Jul 2020 13:35:34 -0400 Subject: [PATCH 03/15] command/debug: use the Consul/Vault env for queries --- command/debug.go | 201 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 143 insertions(+), 58 deletions(-) diff --git a/command/debug.go b/command/debug.go index 972d72ae6b9..42c022e1beb 100644 --- a/command/debug.go +++ b/command/debug.go @@ -24,13 +24,16 @@ import ( type DebugCommand struct { Meta - timestamp string - collectDir string - duration time.Duration - interval time.Duration - logLevel string - nodeIDs []string - serverIDs []string + timestamp string + collectDir string + duration time.Duration + interval time.Duration + logLevel string + nodeIDs []string + serverIDs []string + consul *external + vault *external + consulToken string vaultToken string manifest []string @@ -38,6 +41,15 @@ type DebugCommand struct { cancel context.CancelFunc } +type external struct { + api.TLSConfig + addrVal string + auth string + ssl string + tokenVal string + tokenFile string +} + const ( userAgent = "nomad debug" ) @@ -55,34 +67,78 @@ General Options: Debug Options: - -duration=2m - The duration of the log monitor command. Defaults to 2m. + -duration= + The duration of the log monitor command. Defaults to 2m. + + -interval= + The interval between snapshots of the Nomad state. If unspecified, only one snapshot is + captured. + + -log-level= + The log level to monitor. Defaults to DEBUG. + + -node-id=, + Comma separated list of Nomad client node ids, to monitor for logs and include pprof + profiles. Accepts id prefixes. + + -server-id=, + Comma separated list of Nomad server names, or "leader" to monitor for logs and include pprof + profiles. + + -output= + Path to the parent directory of the output directory. If not specified, an archive is built + in the current directory. + + -consul-http-addr= + The address and port of the Consul HTTP agent. Can be specified by CONSUL_HTTP_ADDR + + -consul-token= + Token used to query Consul. Overrides the CONSUL_HTTP_TOKEN environment + variable and the Consul token file. - -interval=2m - The interval between snapshots of the Nomad state. If unspecified, only one snapshot is - captured. + -consul-token-file= + Path to the Consul token file. Overrides the CONSUL_HTTP_TOKEN_FILE + environment variable. - -log-level=DEBUG - The log level to monitor. Defaults to DEBUG. + -consul-client-cert= + Path to the Consul client cert file. Overrides the CONSUL_CLIENT_CERT + environment variable. - -node-id=n1,n2 - Comma separated list of Nomad client node ids, to monitor for logs and include pprof - profiles. Accepts id prefixes. + -consul-client-key= + Path to the Consul client key file. Overrides the CONSUL_CLIENT_KEY + environment variable. - -server-id=s1,s2 - Comma separated list of Nomad server names, or "leader" to monitor for logs and include pprof - profiles. + -consul-ca-cert= + Path to a CA file to use with Consul. Overrides the CONSUL_CACERT + environment variable and the Consul CA path. - -output=path - Path to the parent directory of the output directory. If not specified, an archive is built - in the current directory. + -consul-ca-path= + Path to a directory of PEM encoded CA cert files to verify the Consul + certificate. Overrides the CONSUL_CAPATH environment variable. - -consul-token - Token used to query Consul. Defaults to CONSUL_HTTP_TOKEN or the contents of - CONSUL_HTTP_TOKEN_FILE + -vault-address= + The address and port of the Vault HTTP agent. Overrides the VAULT_ADDR + environment variable. - -vault-token - Token used to query Vault. Defaults to VAULT_TOKEN + -vault-token= + Token used to query Vault. Overrides the VAULT_TOKEN environment + variable. + + -vault-client-cert= + Path to the Vault client cert file. Overrides the VAULT_CLIENT_CERT + environment variable. + + -vault-client-key= + Path to the Vault client key file. Overrides the VAULT_CLIENT_KEY + environment variable. + + -vault-ca-cert= + Path to a CA file to use with Vault. Overrides the VAULT_CACERT + environment variable and the Vault CA path. + + -vault-ca-path= + Path to a directory of PEM encoded CA cert files to verify the Vault + certificate. Overrides the VAULT_CAPATH environment variable. ` return strings.TrimSpace(helpText) } @@ -124,8 +180,25 @@ func (c *DebugCommand) Run(args []string) int { flags.StringVar(&nodeIDs, "node-id", "", "") flags.StringVar(&serverIDs, "server-id", "", "") flags.StringVar(&output, "output", "", "") - flags.StringVar(&c.consulToken, "consul-token", "", "") - flags.StringVar(&c.vaultToken, "vault-token", "", "") + + c.consul = &external{} + flags.StringVar(&c.consul.addrVal, "consul-http-addr", "", os.Getenv("CONSUL_HTTP_ADDR")) + c.consul.ssl = os.Getenv("CONSUL_HTTP_SSL") + flags.StringVar(&c.consul.auth, "consul-auth", "", os.Getenv("CONSUL_HTTP_AUTH")) + flags.StringVar(&c.consul.tokenVal, "consul-token", "", os.Getenv("CONSUL_HTTP_TOKEN")) + flags.StringVar(&c.consul.tokenFile, "consul-token-file", "", os.Getenv("CONSUL_HTTP_TOKEN_FILE")) + flags.StringVar(&c.consul.ClientCert, "consul-client-cert", "", os.Getenv("CONSUL_CLIENT_CERT")) + flags.StringVar(&c.consul.ClientKey, "consul-client-key", "", os.Getenv("CONSUL_CLIENT_KEY")) + flags.StringVar(&c.consul.CACert, "consul-ca-cert", "", os.Getenv("CONSUL_CACERT")) + flags.StringVar(&c.consul.CAPath, "consul-ca-path", "", os.Getenv("CONSUL_CAPATH")) + + c.vault = &external{} + flags.StringVar(&c.vault.addrVal, "vault-address", "", os.Getenv("VAULT_ADDR")) + flags.StringVar(&c.vault.tokenVal, "vault-token", "", os.Getenv("VAULT_TOKEN")) + flags.StringVar(&c.vault.CACert, "vault-ca-cert", "", os.Getenv("VAULT_CACERT")) + flags.StringVar(&c.vault.CAPath, "vault-ca-path", "", os.Getenv("VAULT_CAPATH")) + flags.StringVar(&c.vault.ClientCert, "vault-client-cert", "", os.Getenv("VAULT_CLIENT_CERT")) + flags.StringVar(&c.vault.ClientKey, "vault-client-key", "", os.Getenv("VAULT_CLIENT_KEY")) if err := flags.Parse(args); err != nil { return 1 @@ -522,35 +595,21 @@ func (c *DebugCommand) collectConsul(dir, consul string) error { return nil } - token := c.consulToken - if token == "" { - token = os.Getenv("CONSUL_HTTP_TOKEN") - } - if token == "" { - file := os.Getenv("CONSUL_HTTP_TOKEN_FILE") - if file != "" { - fh, err := os.Open(file) - if err == nil { - bs, err := ioutil.ReadAll(fh) - if err == nil { - token = strings.TrimSpace(string(bs)) - } - } - } - } - client := http.Client{ Timeout: 2 * time.Second, } + api.ConfigureTLS(&client, &c.consul.TLSConfig) + + addr := c.consul.addr(consul) - req, _ := http.NewRequest("GET", consul+"/v1/agent/self", nil) - req.Header.Add("X-Consul-Token", token) + req, _ := http.NewRequest("GET", addr+"/v1/agent/self", nil) + req.Header.Add("X-Consul-Token", c.consul.token()) req.Header.Add("User-Agent", userAgent) resp, err := client.Do(req) c.writeBody(dir, "consul-agent-self.json", resp, err) - req, _ = http.NewRequest("GET", consul+"/v1/agent/members", nil) - req.Header.Add("X-Consul-Token", token) + req, _ = http.NewRequest("GET", addr+"/v1/agent/members", nil) + req.Header.Add("X-Consul-Token", c.consul.token()) req.Header.Add("User-Agent", userAgent) resp, err = client.Do(req) c.writeBody(dir, "consul-agent-members.json", resp, err) @@ -564,17 +623,15 @@ func (c *DebugCommand) collectVault(dir, vault string) error { return nil } - token := c.vaultToken - if token == "" { - os.Getenv("VAULT_TOKEN") - } - client := http.Client{ Timeout: 2 * time.Second, } + api.ConfigureTLS(&client, &c.vault.TLSConfig) - req, _ := http.NewRequest("GET", vault+"/sys/health", nil) - req.Header.Add("X-Vault-Token", token) + addr := c.vault.addr(vault) + + req, _ := http.NewRequest("GET", addr+"/sys/health", nil) + req.Header.Add("X-Vault-Token", c.vault.token()) req.Header.Add("User-Agent", userAgent) resp, err := client.Do(req) c.writeBody(dir, "vault-sys-health.json", resp, err) @@ -582,6 +639,34 @@ func (c *DebugCommand) collectVault(dir, vault string) error { return nil } +func (c *external) addr(addr string) string { + if addr != "" { + return addr + } + if c.ssl != "" && c.addrVal[0:5] != "https" { + return "https" + c.addrVal[5] + } + return c.addrVal +} + +func (c *external) token() string { + if c.tokenVal != "" { + return c.tokenVal + } + + if c.tokenFile != "" { + fh, err := os.Open(c.tokenFile) + if err == nil { + bs, err := ioutil.ReadAll(fh) + if err == nil { + return strings.TrimSpace(string(bs)) + } + } + } + + return "" +} + // writeBytes writes a file to the archive, recording it in the manifest func (c *DebugCommand) writeBytes(dir, file string, data []byte) error { path := filepath.Join(dir, file) From f1e5f248bc1ee5ad16d2ff06469e4d3e11485f28 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 14 Jul 2020 16:31:39 -0400 Subject: [PATCH 04/15] command/debug: add the operator endpoints --- command/debug.go | 37 ++++++++++++++++++++++++++++++++----- command/debug_test.go | 7 +++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/command/debug.go b/command/debug.go index 42c022e1beb..6fb7cc75607 100644 --- a/command/debug.go +++ b/command/debug.go @@ -13,6 +13,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -29,6 +30,7 @@ type DebugCommand struct { duration time.Duration interval time.Duration logLevel string + stale bool nodeIDs []string serverIDs []string consul *external @@ -45,7 +47,7 @@ type external struct { api.TLSConfig addrVal string auth string - ssl string + ssl bool tokenVal string tokenFile string } @@ -85,6 +87,11 @@ Debug Options: Comma separated list of Nomad server names, or "leader" to monitor for logs and include pprof profiles. + -stale= + If "false", the default, get membership data from the cluster leader. If the cluster is in + an outage unable to establish leadership, it may be necessary to get the configuration from + a non-leader server. + -output= Path to the parent directory of the output directory. If not specified, an archive is built in the current directory. @@ -179,11 +186,13 @@ func (c *DebugCommand) Run(args []string) int { flags.StringVar(&c.logLevel, "log-level", "DEBUG", "") flags.StringVar(&nodeIDs, "node-id", "", "") flags.StringVar(&serverIDs, "server-id", "", "") + flags.BoolVar(&c.stale, "stale", false, "") flags.StringVar(&output, "output", "", "") c.consul = &external{} flags.StringVar(&c.consul.addrVal, "consul-http-addr", "", os.Getenv("CONSUL_HTTP_ADDR")) - c.consul.ssl = os.Getenv("CONSUL_HTTP_SSL") + ssl := os.Getenv("CONSUL_HTTP_SSL") + c.consul.ssl, _ = strconv.ParseBool(ssl) flags.StringVar(&c.consul.auth, "consul-auth", "", os.Getenv("CONSUL_HTTP_AUTH")) flags.StringVar(&c.consul.tokenVal, "consul-token", "", os.Getenv("CONSUL_HTTP_TOKEN")) flags.StringVar(&c.consul.tokenFile, "consul-token-file", "", os.Getenv("CONSUL_HTTP_TOKEN_FILE")) @@ -586,6 +595,24 @@ func (c *DebugCommand) collectNomad(dir string, client *api.Client) error { } c.writeJSON(dir, "volumes.json", vs) + rc, err := client.Operator().RaftGetConfiguration(nil) + if err != nil { + return fmt.Errorf("listing raft configuration: %s", err.Error()) + } + c.writeJSON(dir, "operator-raft.json", rc) + + sc, _, err := client.Operator().SchedulerGetConfiguration(nil) + if err != nil { + return fmt.Errorf("listing scheduler configuration: %s", err.Error()) + } + c.writeJSON(dir, "operator-scheduler.json", sc) + + ah, _, err := client.Operator().AutopilotServerHealth(nil) + if err != nil { + return fmt.Errorf("listing autopilot health: %s", err.Error()) + } + c.writeJSON(dir, "operator-autopilot-health.json", ah) + return nil } @@ -640,11 +667,11 @@ func (c *DebugCommand) collectVault(dir, vault string) error { } func (c *external) addr(addr string) string { - if addr != "" { + if c.addrVal == "" { return addr } - if c.ssl != "" && c.addrVal[0:5] != "https" { - return "https" + c.addrVal[5] + if c.ssl && c.addrVal[0:5] != "https" { + return "https" + string(c.addrVal[4:]) } return c.addrVal } diff --git a/command/debug_test.go b/command/debug_test.go index d88f375e1ec..6a4026b6e73 100644 --- a/command/debug_test.go +++ b/command/debug_test.go @@ -17,6 +17,13 @@ func TestDebugUtils(t *testing.T) { xs = argNodes("") require.Len(t, xs, 0) require.Empty(t, xs) + + // address calculation honors CONSUL_HTTP_SSL + e := &external{addrVal: "http://127.0.0.1:8500", ssl: true} + require.Equal(t, "https://127.0.0.1:8500", e.addr("foo")) + + e = &external{addrVal: "http://127.0.0.1:8500", ssl: false} + require.Equal(t, "http://127.0.0.1:8500", e.addr("foo")) } func TestDebugFails(t *testing.T) { From 632793046e952deb1db448513236777d8a0914cd Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Thu, 16 Jul 2020 11:56:55 -0400 Subject: [PATCH 05/15] command/debug: capture API errors in the archive bundle --- command/debug.go | 151 ++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 88 deletions(-) diff --git a/command/debug.go b/command/debug.go index 6fb7cc75607..3195fecd6d5 100644 --- a/command/debug.go +++ b/command/debug.go @@ -44,7 +44,7 @@ type DebugCommand struct { } type external struct { - api.TLSConfig + tls *api.TLSConfig addrVal string auth string ssl bool @@ -189,25 +189,25 @@ func (c *DebugCommand) Run(args []string) int { flags.BoolVar(&c.stale, "stale", false, "") flags.StringVar(&output, "output", "", "") - c.consul = &external{} + c.consul = &external{tls: &api.TLSConfig{}} flags.StringVar(&c.consul.addrVal, "consul-http-addr", "", os.Getenv("CONSUL_HTTP_ADDR")) ssl := os.Getenv("CONSUL_HTTP_SSL") c.consul.ssl, _ = strconv.ParseBool(ssl) flags.StringVar(&c.consul.auth, "consul-auth", "", os.Getenv("CONSUL_HTTP_AUTH")) flags.StringVar(&c.consul.tokenVal, "consul-token", "", os.Getenv("CONSUL_HTTP_TOKEN")) flags.StringVar(&c.consul.tokenFile, "consul-token-file", "", os.Getenv("CONSUL_HTTP_TOKEN_FILE")) - flags.StringVar(&c.consul.ClientCert, "consul-client-cert", "", os.Getenv("CONSUL_CLIENT_CERT")) - flags.StringVar(&c.consul.ClientKey, "consul-client-key", "", os.Getenv("CONSUL_CLIENT_KEY")) - flags.StringVar(&c.consul.CACert, "consul-ca-cert", "", os.Getenv("CONSUL_CACERT")) - flags.StringVar(&c.consul.CAPath, "consul-ca-path", "", os.Getenv("CONSUL_CAPATH")) + flags.StringVar(&c.consul.tls.ClientCert, "consul-client-cert", "", os.Getenv("CONSUL_CLIENT_CERT")) + flags.StringVar(&c.consul.tls.ClientKey, "consul-client-key", "", os.Getenv("CONSUL_CLIENT_KEY")) + flags.StringVar(&c.consul.tls.CACert, "consul-ca-cert", "", os.Getenv("CONSUL_CACERT")) + flags.StringVar(&c.consul.tls.CAPath, "consul-ca-path", "", os.Getenv("CONSUL_CAPATH")) - c.vault = &external{} + c.vault = &external{tls: &api.TLSConfig{}} flags.StringVar(&c.vault.addrVal, "vault-address", "", os.Getenv("VAULT_ADDR")) flags.StringVar(&c.vault.tokenVal, "vault-token", "", os.Getenv("VAULT_TOKEN")) - flags.StringVar(&c.vault.CACert, "vault-ca-cert", "", os.Getenv("VAULT_CACERT")) - flags.StringVar(&c.vault.CAPath, "vault-ca-path", "", os.Getenv("VAULT_CAPATH")) - flags.StringVar(&c.vault.ClientCert, "vault-client-cert", "", os.Getenv("VAULT_CLIENT_CERT")) - flags.StringVar(&c.vault.ClientKey, "vault-client-key", "", os.Getenv("VAULT_CLIENT_KEY")) + flags.StringVar(&c.vault.tls.CACert, "vault-ca-cert", "", os.Getenv("VAULT_CACERT")) + flags.StringVar(&c.vault.tls.CAPath, "vault-ca-path", "", os.Getenv("VAULT_CAPATH")) + flags.StringVar(&c.vault.tls.ClientCert, "vault-client-cert", "", os.Getenv("VAULT_CLIENT_CERT")) + flags.StringVar(&c.vault.tls.ClientKey, "vault-client-key", "", os.Getenv("VAULT_CLIENT_KEY")) if err := flags.Parse(args); err != nil { return 1 @@ -305,10 +305,6 @@ func (c *DebugCommand) Run(args []string) int { return 2 } - if c.ctx.Err() != nil { - return 2 - } - c.writeManifest() if output != "" { @@ -337,10 +333,7 @@ func (c *DebugCommand) collect(client *api.Client) error { } self, err := client.Agent().Self() - if err != nil { - return fmt.Errorf("agent self: %s", err.Error()) - } - c.writeJSON(dir, "agent-self.json", self) + c.writeJSON(dir, "agent-self.json", self, err) // Fetch data directly from consul and vault. Ignore errors var consul, vault string @@ -460,12 +453,7 @@ func (c *DebugCommand) collectAgentHost(path, id string, client *api.Client) { path = filepath.Join(path, id) - if err != nil { - c.writeBytes(path, "agent-host.log", []byte(err.Error())) - return - } - - c.writeJSON(path, "agent-host.json", host) + c.writeJSON(path, "agent-host.json", host, err) } // collectPprofs captures the /agent/pprof for each listed node @@ -535,6 +523,7 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { dir = filepath.Join("nomad", name) c.Ui.Output(fmt.Sprintf("==> Capture interval %s", name)) c.collectNomad(dir, client) + c.collectOperator(dir, client) interval = time.After(c.interval) intervalCount += 1 @@ -544,6 +533,18 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { } } +// collectOperator captures some cluster meta information +func (c *DebugCommand) collectOperator(dir string, client *api.Client) { + rc, err := client.Operator().RaftGetConfiguration(nil) + c.writeJSON(dir, "operator-raft.json", rc, err) + + sc, _, err := client.Operator().SchedulerGetConfiguration(nil) + c.writeJSON(dir, "operator-scheduler.json", sc, err) + + ah, _, err := client.Operator().AutopilotServerHealth(nil) + c.writeJSON(dir, "operator-autopilot-health.json", ah, err) +} + // collectNomad captures the nomad cluster state func (c *DebugCommand) collectNomad(dir string, client *api.Client) error { err := c.mkdir(dir) @@ -554,80 +555,38 @@ func (c *DebugCommand) collectNomad(dir string, client *api.Client) error { var qo *api.QueryOptions js, _, err := client.Jobs().List(qo) - if err != nil { - return fmt.Errorf("listing jobs: %s", err.Error()) - } - c.writeJSON(dir, "jobs.json", js) + c.writeJSON(dir, "jobs.json", js, err) ds, _, err := client.Deployments().List(qo) - if err != nil { - return fmt.Errorf("listing deployments: %s", err.Error()) - } - c.writeJSON(dir, "deployments.json", ds) + c.writeJSON(dir, "deployments.json", ds, err) es, _, err := client.Evaluations().List(qo) - if err != nil { - return fmt.Errorf("listing evaluations: %s", err.Error()) - } - c.writeJSON(dir, "evaluations.json", es) + c.writeJSON(dir, "evaluations.json", es, err) as, _, err := client.Allocations().List(qo) - if err != nil { - return fmt.Errorf("listing allocations: %s", err.Error()) - } - c.writeJSON(dir, "allocations.json", as) + c.writeJSON(dir, "allocations.json", as, err) ns, _, err := client.Nodes().List(qo) - if err != nil { - return fmt.Errorf("listing nodes: %s", err.Error()) - } - c.writeJSON(dir, "nodes.json", ns) + c.writeJSON(dir, "nodes.json", ns, err) ps, _, err := client.CSIPlugins().List(qo) - if err != nil { - return fmt.Errorf("listing plugins: %s", err.Error()) - } - c.writeJSON(dir, "plugins.json", ps) + c.writeJSON(dir, "plugins.json", ps, err) vs, _, err := client.CSIVolumes().List(qo) - if err != nil { - return fmt.Errorf("listing volumes: %s", err.Error()) - } - c.writeJSON(dir, "volumes.json", vs) - - rc, err := client.Operator().RaftGetConfiguration(nil) - if err != nil { - return fmt.Errorf("listing raft configuration: %s", err.Error()) - } - c.writeJSON(dir, "operator-raft.json", rc) - - sc, _, err := client.Operator().SchedulerGetConfiguration(nil) - if err != nil { - return fmt.Errorf("listing scheduler configuration: %s", err.Error()) - } - c.writeJSON(dir, "operator-scheduler.json", sc) - - ah, _, err := client.Operator().AutopilotServerHealth(nil) - if err != nil { - return fmt.Errorf("listing autopilot health: %s", err.Error()) - } - c.writeJSON(dir, "operator-autopilot-health.json", ah) + c.writeJSON(dir, "volumes.json", vs, err) return nil } // collectConsul calls the Consul API directly to collect data func (c *DebugCommand) collectConsul(dir, consul string) error { - if consul == "" { + addr := c.consul.addr(consul) + if addr == "" { return nil } - client := http.Client{ - Timeout: 2 * time.Second, - } - api.ConfigureTLS(&client, &c.consul.TLSConfig) - - addr := c.consul.addr(consul) + client := api.DefaultHttpClient() + api.ConfigureTLS(client, c.consul.tls) req, _ := http.NewRequest("GET", addr+"/v1/agent/self", nil) req.Header.Add("X-Consul-Token", c.consul.token()) @@ -646,16 +605,13 @@ func (c *DebugCommand) collectConsul(dir, consul string) error { // collectVault calls the Vault API directly to collect data func (c *DebugCommand) collectVault(dir, vault string) error { - if vault == "" { + addr := c.vault.addr(vault) + if addr == "" { return nil } - client := http.Client{ - Timeout: 2 * time.Second, - } - api.ConfigureTLS(&client, &c.vault.TLSConfig) - - addr := c.vault.addr(vault) + client := api.DefaultHttpClient() + api.ConfigureTLS(client, c.vault.tls) req, _ := http.NewRequest("GET", addr+"/sys/health", nil) req.Header.Add("X-Vault-Token", c.vault.token()) @@ -711,28 +667,47 @@ func (c *DebugCommand) writeBytes(dir, file string, data []byte) error { } // writeJSON writes JSON responses from the Nomad API calls to the archive -func (c *DebugCommand) writeJSON(dir, file string, data interface{}) error { +func (c *DebugCommand) writeJSON(dir, file string, data interface{}, err error) error { + if err != nil { + return c.writeError(dir, file, err) + } bytes, err := json.Marshal(data) + if err != nil { + return c.writeError(dir, file, err) + } + return c.writeBytes(dir, file, bytes) +} + +// writeError writes a JSON error object to capture errors in the debug bundle without +// reporting +func (c *DebugCommand) writeError(dir, file string, err error) error { + bytes, err := json.Marshal(errorWrapper{Error: err.Error()}) if err != nil { return err } return c.writeBytes(dir, file, bytes) } +type errorWrapper struct { + Error string +} + // writeBody is a helper that writes the body of an http.Response to the archive func (c *DebugCommand) writeBody(dir, file string, resp *http.Response, err error) { if err != nil { + c.writeError(dir, file, err) return } - defer resp.Body.Close() if resp.ContentLength == 0 { return } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { - return + c.writeError(dir, file, err) } c.writeBytes(dir, file, body) From 5a6c88db0e02d236c91a76c7e5ab89b2e226e352 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Fri, 17 Jul 2020 10:19:47 -0400 Subject: [PATCH 06/15] command/debug: setup defaults correctly --- command/debug.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/command/debug.go b/command/debug.go index 3195fecd6d5..29a85b23075 100644 --- a/command/debug.go +++ b/command/debug.go @@ -190,24 +190,24 @@ func (c *DebugCommand) Run(args []string) int { flags.StringVar(&output, "output", "", "") c.consul = &external{tls: &api.TLSConfig{}} - flags.StringVar(&c.consul.addrVal, "consul-http-addr", "", os.Getenv("CONSUL_HTTP_ADDR")) + flags.StringVar(&c.consul.addrVal, "consul-http-addr", os.Getenv("CONSUL_HTTP_ADDR"), "") ssl := os.Getenv("CONSUL_HTTP_SSL") c.consul.ssl, _ = strconv.ParseBool(ssl) - flags.StringVar(&c.consul.auth, "consul-auth", "", os.Getenv("CONSUL_HTTP_AUTH")) - flags.StringVar(&c.consul.tokenVal, "consul-token", "", os.Getenv("CONSUL_HTTP_TOKEN")) - flags.StringVar(&c.consul.tokenFile, "consul-token-file", "", os.Getenv("CONSUL_HTTP_TOKEN_FILE")) - flags.StringVar(&c.consul.tls.ClientCert, "consul-client-cert", "", os.Getenv("CONSUL_CLIENT_CERT")) - flags.StringVar(&c.consul.tls.ClientKey, "consul-client-key", "", os.Getenv("CONSUL_CLIENT_KEY")) - flags.StringVar(&c.consul.tls.CACert, "consul-ca-cert", "", os.Getenv("CONSUL_CACERT")) - flags.StringVar(&c.consul.tls.CAPath, "consul-ca-path", "", os.Getenv("CONSUL_CAPATH")) + flags.StringVar(&c.consul.auth, "consul-auth", os.Getenv("CONSUL_HTTP_AUTH"), "") + flags.StringVar(&c.consul.tokenVal, "consul-token", os.Getenv("CONSUL_HTTP_TOKEN"), "") + flags.StringVar(&c.consul.tokenFile, "consul-token-file", os.Getenv("CONSUL_HTTP_TOKEN_FILE"), "") + flags.StringVar(&c.consul.tls.ClientCert, "consul-client-cert", os.Getenv("CONSUL_CLIENT_CERT"), "") + flags.StringVar(&c.consul.tls.ClientKey, "consul-client-key", os.Getenv("CONSUL_CLIENT_KEY"), "") + flags.StringVar(&c.consul.tls.CACert, "consul-ca-cert", os.Getenv("CONSUL_CACERT"), "") + flags.StringVar(&c.consul.tls.CAPath, "consul-ca-path", os.Getenv("CONSUL_CAPATH"), "") c.vault = &external{tls: &api.TLSConfig{}} - flags.StringVar(&c.vault.addrVal, "vault-address", "", os.Getenv("VAULT_ADDR")) - flags.StringVar(&c.vault.tokenVal, "vault-token", "", os.Getenv("VAULT_TOKEN")) - flags.StringVar(&c.vault.tls.CACert, "vault-ca-cert", "", os.Getenv("VAULT_CACERT")) - flags.StringVar(&c.vault.tls.CAPath, "vault-ca-path", "", os.Getenv("VAULT_CAPATH")) - flags.StringVar(&c.vault.tls.ClientCert, "vault-client-cert", "", os.Getenv("VAULT_CLIENT_CERT")) - flags.StringVar(&c.vault.tls.ClientKey, "vault-client-key", "", os.Getenv("VAULT_CLIENT_KEY")) + flags.StringVar(&c.vault.addrVal, "vault-address", os.Getenv("VAULT_ADDR"), "") + flags.StringVar(&c.vault.tokenVal, "vault-token", os.Getenv("VAULT_TOKEN"), "") + flags.StringVar(&c.vault.tls.CACert, "vault-ca-cert", os.Getenv("VAULT_CACERT"), "") + flags.StringVar(&c.vault.tls.CAPath, "vault-ca-path", os.Getenv("VAULT_CAPATH"), "") + flags.StringVar(&c.vault.tls.ClientCert, "vault-client-cert", os.Getenv("VAULT_CLIENT_CERT"), "") + flags.StringVar(&c.vault.tls.ClientKey, "vault-client-key", os.Getenv("VAULT_CLIENT_KEY"), "") if err := flags.Parse(args); err != nil { return 1 From d8eff422c0f4266c489e355a0c8ba43057faf41a Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Mon, 20 Jul 2020 11:53:42 -0400 Subject: [PATCH 07/15] command/debug: cleanup output a little --- command/debug.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/command/debug.go b/command/debug.go index 29a85b23075..9b850be15b1 100644 --- a/command/debug.go +++ b/command/debug.go @@ -35,12 +35,9 @@ type DebugCommand struct { serverIDs []string consul *external vault *external - - consulToken string - vaultToken string - manifest []string - ctx context.Context - cancel context.CancelFunc + manifest []string + ctx context.Context + cancel context.CancelFunc } type external struct { @@ -275,9 +272,12 @@ func (c *DebugCommand) Run(args []string) int { c.timestamp = time.Now().UTC().Format(format) stamped := "nomad-debug-" + c.timestamp - c.Ui.Output("==> Starting debugger and capturing cluster data...") - c.Ui.Output(fmt.Sprintf(" Interval: '%s'", interval)) - c.Ui.Output(fmt.Sprintf(" Duration: '%s'", duration)) + c.Ui.Output("Starting debugger and capturing cluster data...") + + if len(c.nodeIDs) > 0 || len(c.serverIDs) > 0 { + c.Ui.Output(fmt.Sprintf(" Interval: '%s'", interval)) + c.Ui.Output(fmt.Sprintf(" Duration: '%s'", duration)) + } // Create the output path var tmp string @@ -521,7 +521,7 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { case <-interval: name = fmt.Sprintf("%04d", time.Now().Unix()-start) dir = filepath.Join("nomad", name) - c.Ui.Output(fmt.Sprintf("==> Capture interval %s", name)) + c.Ui.Output(fmt.Sprintf(" Capture interval %s", name)) c.collectNomad(dir, client) c.collectOperator(dir, client) interval = time.After(c.interval) @@ -627,7 +627,7 @@ func (c *external) addr(addr string) string { return addr } if c.ssl && c.addrVal[0:5] != "https" { - return "https" + string(c.addrVal[4:]) + return "https" + c.addrVal[4:] } return c.addrVal } From 2bc1c8696e87d86405354e70576541cd357794d9 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Mon, 20 Jul 2020 12:37:03 -0400 Subject: [PATCH 08/15] command/debug_test: errors are captured --- command/debug_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/command/debug_test.go b/command/debug_test.go index 6a4026b6e73..cd06808f3ec 100644 --- a/command/debug_test.go +++ b/command/debug_test.go @@ -93,11 +93,11 @@ func TestDebugCapturedFiles(t *testing.T) { // Version is always captured require.FileExists(t, filepath.Join(path, "version", "agent-self.json")) - // Consul and Vault are only captured if they exist + // Consul and Vault contain results or errors _, err := os.Stat(filepath.Join(path, "version", "consul-agent-self.json")) - require.Error(t, err) + require.NoError(t, err) _, err = os.Stat(filepath.Join(path, "version", "vault-sys-health.json")) - require.Error(t, err) + require.NoError(t, err) // Monitor files are only created when selected require.FileExists(t, filepath.Join(path, "server", "leader", "monitor.log")) From bd7ac86bee51671ee2ca0155c0cea817f2da98c6 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Mon, 20 Jul 2020 17:22:58 -0400 Subject: [PATCH 09/15] command/debug: pprof needs to create its directory --- command/debug.go | 4 ++++ command/debug_test.go | 19 ++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/command/debug.go b/command/debug.go index 9b850be15b1..ba698c47e22 100644 --- a/command/debug.go +++ b/command/debug.go @@ -478,6 +478,10 @@ func (c *DebugCommand) collectPprof(path, id string, client *api.Client) { } path = filepath.Join(path, id) + err := c.mkdir(path) + if err != nil { + return + } bs, err := client.Agent().CPUProfile(opts, nil) if err == nil { diff --git a/command/debug_test.go b/command/debug_test.go index cd06808f3ec..bec5ed58047 100644 --- a/command/debug_test.go +++ b/command/debug_test.go @@ -72,20 +72,17 @@ func TestDebugCapturedFiles(t *testing.T) { ui := new(cli.MockUi) cmd := &DebugCommand{Meta: Meta{Ui: ui}} - // Calculate the output name - format := "2006-01-02-150405Z" - stamped := "nomad-debug-" + time.Now().UTC().Format(format) - path := filepath.Join(os.TempDir(), stamped) - defer os.Remove(path) - code := cmd.Run([]string{ "-address", url, "-output", os.TempDir(), "-server-id", "leader", "-duration", "1s", - "-interval", "500ms", + "-interval", "600ms", }) + path := cmd.collectDir + defer os.Remove(path) + require.Empty(t, ui.ErrorWriter.String()) require.Equal(t, 0, code) ui.ErrorWriter.Reset() @@ -106,10 +103,10 @@ func TestDebugCapturedFiles(t *testing.T) { require.FileExists(t, filepath.Join(path, "server", "leader", "goroutine.prof")) // Multiple snapshots are collected, 00 is always created - require.FileExists(t, filepath.Join(path, "nomad", "00", "jobs.json")) - require.FileExists(t, filepath.Join(path, "nomad", "00", "nodes.json")) + require.FileExists(t, filepath.Join(path, "nomad", "0000", "jobs.json")) + require.FileExists(t, filepath.Join(path, "nomad", "0000", "nodes.json")) // Multiple snapshots are collected, 01 requires two intervals - require.FileExists(t, filepath.Join(path, "nomad", "01", "jobs.json")) - require.FileExists(t, filepath.Join(path, "nomad", "01", "nodes.json")) + require.FileExists(t, filepath.Join(path, "nomad", "0001", "jobs.json")) + require.FileExists(t, filepath.Join(path, "nomad", "0001", "nodes.json")) } From 3f16e758a54cfb8fd1221e13fa5b25fa7cdab740 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Sun, 26 Jul 2020 10:25:22 -0400 Subject: [PATCH 10/15] command/debug: count intervals, use file mtime --- command/debug.go | 3 +-- command/debug_test.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/command/debug.go b/command/debug.go index ba698c47e22..b1cab58b08c 100644 --- a/command/debug.go +++ b/command/debug.go @@ -509,7 +509,6 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { return } - start := time.Now().Unix() duration := time.After(c.duration) // Set interval to 0 so that we immediately execute, wait the interval next time interval := time.After(0 * time.Second) @@ -523,7 +522,7 @@ func (c *DebugCommand) collectPeriodic(client *api.Client) { return case <-interval: - name = fmt.Sprintf("%04d", time.Now().Unix()-start) + name = fmt.Sprintf("%04d", intervalCount) dir = filepath.Join("nomad", name) c.Ui.Output(fmt.Sprintf(" Capture interval %s", name)) c.collectNomad(dir, client) diff --git a/command/debug_test.go b/command/debug_test.go index bec5ed58047..2204110d5c9 100644 --- a/command/debug_test.go +++ b/command/debug_test.go @@ -76,7 +76,7 @@ func TestDebugCapturedFiles(t *testing.T) { "-address", url, "-output", os.TempDir(), "-server-id", "leader", - "-duration", "1s", + "-duration", "1300ms", "-interval", "600ms", }) From dfac3895dbf6b6c01dd9bae45a4da4e81cc97173 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Sun, 26 Jul 2020 11:17:12 -0400 Subject: [PATCH 11/15] command/debug: check nil config before type conversion --- command/debug.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/command/debug.go b/command/debug.go index b1cab58b08c..fbf5842268a 100644 --- a/command/debug.go +++ b/command/debug.go @@ -338,23 +338,30 @@ func (c *DebugCommand) collect(client *api.Client) error { // Fetch data directly from consul and vault. Ignore errors var consul, vault string - m, ok := self.Config["Consul"].(map[string]interface{}) + r, ok := self.Config["Consul"] if ok { - raw := m["Addr"] - consul, _ = raw.(string) - raw = m["EnableSSL"] - ssl, _ := raw.(bool) - if ssl { - consul = "https://" + consul - } else { - consul = "http://" + consul + m, ok := r.(map[string]interface{}) + if ok { + + raw := m["Addr"] + consul, _ = raw.(string) + raw = m["EnableSSL"] + ssl, _ := raw.(bool) + if ssl { + consul = "https://" + consul + } else { + consul = "http://" + consul + } } } - m, ok = self.Config["Vault"].(map[string]interface{}) + r, ok = self.Config["Vault"] if ok { - raw := m["Addr"] - vault, _ = raw.(string) + m, ok := r.(map[string]interface{}) + if ok { + raw := m["Addr"] + vault, _ = raw.(string) + } } c.collectConsul(dir, consul) From bd65a232508b0edc618fa081f93b926a061e7eb2 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 11 Aug 2020 10:03:45 -0400 Subject: [PATCH 12/15] command/debug.go: use the cleaner `ioutil.ReadFile` Co-authored-by: Mahmood Ali --- command/debug.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/command/debug.go b/command/debug.go index fbf5842268a..6a59230bec6 100644 --- a/command/debug.go +++ b/command/debug.go @@ -648,12 +648,9 @@ func (c *external) token() string { } if c.tokenFile != "" { - fh, err := os.Open(c.tokenFile) + bs, err := ioutil.ReadFile(c.tokenFile) if err == nil { - bs, err := ioutil.ReadAll(fh) - if err == nil { - return strings.TrimSpace(string(bs)) - } + return strings.TrimSpace(string(bs)) } } From cbd0cb7b33b042fb9e530b779e01a4d187ea788a Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 11 Aug 2020 10:58:06 -0400 Subject: [PATCH 13/15] command/debug: move external to the bottom, `addr` parses better --- command/debug.go | 82 +++++++++++++++++++++++++------------------ command/debug_test.go | 6 ++++ 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/command/debug.go b/command/debug.go index 6a59230bec6..9f9b43fce6c 100644 --- a/command/debug.go +++ b/command/debug.go @@ -40,15 +40,6 @@ type DebugCommand struct { cancel context.CancelFunc } -type external struct { - tls *api.TLSConfig - addrVal string - auth string - ssl bool - tokenVal string - tokenFile string -} - const ( userAgent = "nomad debug" ) @@ -632,31 +623,6 @@ func (c *DebugCommand) collectVault(dir, vault string) error { return nil } -func (c *external) addr(addr string) string { - if c.addrVal == "" { - return addr - } - if c.ssl && c.addrVal[0:5] != "https" { - return "https" + c.addrVal[4:] - } - return c.addrVal -} - -func (c *external) token() string { - if c.tokenVal != "" { - return c.tokenVal - } - - if c.tokenFile != "" { - bs, err := ioutil.ReadFile(c.tokenFile) - if err == nil { - return strings.TrimSpace(string(bs)) - } - } - - return "" -} - // writeBytes writes a file to the archive, recording it in the manifest func (c *DebugCommand) writeBytes(dir, file string, data []byte) error { path := filepath.Join(dir, file) @@ -851,3 +817,51 @@ func argNodes(input string) []string { } return out } + +// external holds address configuration for Consul and Vault APIs +type external struct { + tls *api.TLSConfig + addrVal string + auth string + ssl bool + tokenVal string + tokenFile string +} + +func (e *external) addr(defaultAddr string) string { + if e.addrVal == "" { + return defaultAddr + } + + if !e.ssl { + if strings.HasPrefix(e.addrVal, "http:") { + return e.addrVal + } + return "http://" + e.addrVal + } + + if strings.HasPrefix(e.addrVal, "https:") { + return e.addrVal + } + + if strings.HasPrefix(e.addrVal, "http:") { + return "https:" + e.addrVal[5:] + } + + return "https://" + e.addrVal +} + +func (e *external) token() string { + if e.tokenVal != "" { + return e.tokenVal + } + + if e.tokenFile != "" { + bs, err := ioutil.ReadFile(e.tokenFile) + if err == nil { + return strings.TrimSpace(string(bs)) + } + } + + return "" +} diff --git a/command/debug_test.go b/command/debug_test.go index 2204110d5c9..9f16564197c 100644 --- a/command/debug_test.go +++ b/command/debug_test.go @@ -24,6 +24,12 @@ func TestDebugUtils(t *testing.T) { e = &external{addrVal: "http://127.0.0.1:8500", ssl: false} require.Equal(t, "http://127.0.0.1:8500", e.addr("foo")) + + e = &external{addrVal: "127.0.0.1:8500", ssl: false} + require.Equal(t, "http://127.0.0.1:8500", e.addr("foo")) + + e = &external{addrVal: "127.0.0.1:8500", ssl: true} + require.Equal(t, "https://127.0.0.1:8500", e.addr("foo")) } func TestDebugFails(t *testing.T) { From a7cb4978a787758e652e763ec8a6c7c8f85efca0 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 11 Aug 2020 12:28:56 -0400 Subject: [PATCH 14/15] command/debug: copy api.defaultHttpClient in here --- command/debug.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/command/debug.go b/command/debug.go index 9f9b43fce6c..8a489ae1d51 100644 --- a/command/debug.go +++ b/command/debug.go @@ -4,6 +4,7 @@ import ( "archive/tar" "compress/gzip" "context" + "crypto/tls" "encoding/json" "fmt" "html/template" @@ -18,6 +19,7 @@ import ( "syscall" "time" + "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/nomad/api" "github.com/posener/complete" ) @@ -586,7 +588,7 @@ func (c *DebugCommand) collectConsul(dir, consul string) error { return nil } - client := api.DefaultHttpClient() + client := defaultHttpClient() api.ConfigureTLS(client, c.consul.tls) req, _ := http.NewRequest("GET", addr+"/v1/agent/self", nil) @@ -611,7 +613,7 @@ func (c *DebugCommand) collectVault(dir, vault string) error { return nil } - client := api.DefaultHttpClient() + client := defaultHttpClient() api.ConfigureTLS(client, c.vault.tls) req, _ := http.NewRequest("GET", addr+"/sys/health", nil) @@ -865,3 +867,15 @@ func (e *external) token() string { return "" } + +// defaultHttpClient configures a basic httpClient +func defaultHttpClient() *http.Client { + httpClient := cleanhttp.DefaultClient() + transport := httpClient.Transport.(*http.Transport) + transport.TLSHandshakeTimeout = 10 * time.Second + transport.TLSClientConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + } + + return httpClient +} From e69c2c07aa6d1b4b7b67a90fee0916735ce9e374 Mon Sep 17 00:00:00 2001 From: Lang Martin Date: Tue, 11 Aug 2020 12:55:32 -0400 Subject: [PATCH 15/15] command/debug: nil check now that we're not returning on error --- command/debug.go | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/command/debug.go b/command/debug.go index 8a489ae1d51..36901af427e 100644 --- a/command/debug.go +++ b/command/debug.go @@ -331,29 +331,31 @@ func (c *DebugCommand) collect(client *api.Client) error { // Fetch data directly from consul and vault. Ignore errors var consul, vault string - r, ok := self.Config["Consul"] - if ok { - m, ok := r.(map[string]interface{}) + if self != nil { + r, ok := self.Config["Consul"] if ok { - - raw := m["Addr"] - consul, _ = raw.(string) - raw = m["EnableSSL"] - ssl, _ := raw.(bool) - if ssl { - consul = "https://" + consul - } else { - consul = "http://" + consul + m, ok := r.(map[string]interface{}) + if ok { + + raw := m["Addr"] + consul, _ = raw.(string) + raw = m["EnableSSL"] + ssl, _ := raw.(bool) + if ssl { + consul = "https://" + consul + } else { + consul = "http://" + consul + } } } - } - r, ok = self.Config["Vault"] - if ok { - m, ok := r.(map[string]interface{}) + r, ok = self.Config["Vault"] if ok { - raw := m["Addr"] - vault, _ = raw.(string) + m, ok := r.(map[string]interface{}) + if ok { + raw := m["Addr"] + vault, _ = raw.(string) + } } }