package collect import ( "bufio" "bytes" "encoding/json" "fmt" "os/exec" "github.com/pkg/errors" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" ) type ServiceInfo struct { Unit string `json:"Unit"` Load string `json:"Load"` Active string `json:"Active"` Sub string `json:"Sub"` } const systemctlFormat = `%s %s %s %s` // this leaves off the description const HostServicesPath = `host-collectors/system/systemctl_services.json` const HostServicesFileName = `systemctl_services.json` type CollectHostServices struct { hostCollector *troubleshootv1beta2.HostServices BundlePath string } func (c *CollectHostServices) Title() string { return hostCollectorTitleOrDefault(c.hostCollector.HostCollectorMeta, "Block Devices") } func (c *CollectHostServices) IsExcluded() (bool, error) { return isExcluded(c.hostCollector.Exclude) } func (c *CollectHostServices) Collect(progressChan chan<- interface{}) (map[string][]byte, error) { var devices []ServiceInfo cmd := exec.Command("systemctl", "list-units", "--type=service", "--no-legend", "--all") stdout, err := cmd.Output() if err != nil { return nil, errors.Wrapf(err, "failed to execute systemctl") } buf := bytes.NewBuffer(stdout) scanner := bufio.NewScanner(buf) for scanner.Scan() { bdi := ServiceInfo{} fmt.Sscanf( scanner.Text(), systemctlFormat, &bdi.Unit, &bdi.Load, &bdi.Active, &bdi.Sub, ) devices = append(devices, bdi) } b, err := json.Marshal(devices) if err != nil { return nil, errors.Wrap(err, "failed to marshal systemctl service info") } output := NewResult() output.SaveResult(c.BundlePath, HostServicesPath, bytes.NewBuffer(b)) return map[string][]byte{ HostServicesPath: b, }, nil } func (c *CollectHostServices) RemoteCollect(progressChan chan<- interface{}) (map[string][]byte, error) { return nil, ErrRemoteCollectorNotImplemented }