mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-04-15 07:16:34 +00:00
* implement refactor for multiple node analyzers --------- Co-authored-by: Diamon Wiggins <38189728+diamonwiggins@users.noreply.github.com>
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
package collect
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
|
)
|
|
|
|
type CollectHostKernelConfigs struct {
|
|
hostCollector *troubleshootv1beta2.HostKernelConfigs
|
|
BundlePath string
|
|
}
|
|
|
|
type KConfigs map[string]string
|
|
|
|
const HostKernelConfigsPath = `host-collectors/system/kernel-configs.json`
|
|
const HostKernelConfigsFileName = `kernel-configs.json`
|
|
|
|
const (
|
|
kConfigBuiltIn string = "y"
|
|
kConfigAsModule string = "m"
|
|
kConfigLeftOut string = "n"
|
|
)
|
|
|
|
func (c *CollectHostKernelConfigs) Title() string {
|
|
return hostCollectorTitleOrDefault(c.hostCollector.HostCollectorMeta, "kernel-configs")
|
|
}
|
|
|
|
func (c *CollectHostKernelConfigs) IsExcluded() (bool, error) {
|
|
return isExcluded(c.hostCollector.Exclude)
|
|
}
|
|
|
|
func (c *CollectHostKernelConfigs) Collect(progressChan chan<- interface{}) (map[string][]byte, error) {
|
|
|
|
kernelRelease, err := getKernelRelease()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get kernel release")
|
|
}
|
|
|
|
var kConfigs KConfigs
|
|
kConfigs, err = loadKConfigs(kernelRelease)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to load kernel configs")
|
|
}
|
|
|
|
b, err := json.Marshal(kConfigs)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to marshal kernel configs")
|
|
}
|
|
|
|
output := NewResult()
|
|
output.SaveResult(c.BundlePath, HostKernelConfigsPath, bytes.NewBuffer(b))
|
|
|
|
return output, nil
|
|
}
|
|
|
|
func getKernelRelease() (string, error) {
|
|
out, err := exec.Command("uname", "-r").Output()
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "failed to determine kernel release using uname -r")
|
|
}
|
|
release := strings.TrimSpace(string(out))
|
|
return release, nil
|
|
}
|
|
|
|
// https://github.com/k0sproject/k0s/blob/ddee3f980443e19620e678a6e1dc136ff053bff9/internal/pkg/sysinfo/probes/linux/kernel.go#L282
|
|
// loadKConfigs checks a list of well-known file system paths for kernel
|
|
// configuration files and tries to parse them.
|
|
func loadKConfigs(kernelRelease string) (KConfigs, error) {
|
|
// At least some references to those paths may be fond here:
|
|
// https://github.com/torvalds/linux/blob/v4.3/init/Kconfig#L794
|
|
// https://github.com/torvalds/linux/blob/v4.3/init/Kconfig#L9
|
|
possiblePaths := []string{
|
|
"/proc/config.gz",
|
|
"/boot/config-" + kernelRelease,
|
|
"/usr/src/linux-" + kernelRelease + "/.config",
|
|
"/usr/src/linux/.config",
|
|
"/usr/lib/modules/" + kernelRelease + "/config",
|
|
"/usr/lib/ostree-boot/config-" + kernelRelease,
|
|
"/usr/lib/kernel/config-" + kernelRelease,
|
|
"/usr/src/linux-headers-" + kernelRelease + "/.config",
|
|
"/lib/modules/" + kernelRelease + "/build/.config",
|
|
}
|
|
|
|
for _, path := range possiblePaths {
|
|
// open file for reading
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
r := io.Reader(bufio.NewReader(f))
|
|
|
|
// This is a gzip file (config.gz), unzip it.
|
|
if filepath.Ext(path) == ".gz" {
|
|
gr, err := gzip.NewReader(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer gr.Close()
|
|
r = gr
|
|
}
|
|
|
|
return parseKConfigs(r)
|
|
}
|
|
|
|
return nil, errors.Errorf("no kernel config files found for kernel release %q", kernelRelease)
|
|
}
|
|
|
|
// parseKConfigs parses `r` line by line, extracting all kernel config options.
|
|
func parseKConfigs(r io.Reader) (KConfigs, error) {
|
|
configs := KConfigs{}
|
|
kConfigLineRegex := regexp.MustCompile(fmt.Sprintf(
|
|
"^(CONFIG_[A-Z0-9_]+)=([%s%s%s])$",
|
|
string(kConfigBuiltIn), string(kConfigLeftOut), string(kConfigAsModule),
|
|
))
|
|
s := bufio.NewScanner(r)
|
|
for s.Scan() {
|
|
if err := s.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if matches := kConfigLineRegex.FindStringSubmatch(s.Text()); matches != nil {
|
|
configs[matches[1]] = matches[2]
|
|
}
|
|
}
|
|
return configs, nil
|
|
}
|
|
|
|
func (c *CollectHostKernelConfigs) RemoteCollect(progressChan chan<- interface{}) (map[string][]byte, error) {
|
|
return nil, ErrRemoteCollectorNotImplemented
|
|
}
|