Files
troubleshoot/pkg/analyze/host_services.go
Gerard Nguyen f0b8de68ae feat: multiple nodes analyzers (#1667)
* implement refactor for multiple node analyzers

---------

Co-authored-by: Diamon Wiggins <38189728+diamonwiggins@users.noreply.github.com>
2024-11-04 14:17:39 +11:00

130 lines
3.3 KiB
Go

package analyzer
import (
"encoding/json"
"fmt"
"strings"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/collect"
)
type AnalyzeHostServices struct {
hostAnalyzer *troubleshootv1beta2.HostServicesAnalyze
}
func (a *AnalyzeHostServices) Title() string {
return hostAnalyzerTitleOrDefault(a.hostAnalyzer.AnalyzeMeta, "Host Services")
}
func (a *AnalyzeHostServices) IsExcluded() (bool, error) {
return isExcluded(a.hostAnalyzer.Exclude)
}
func (a *AnalyzeHostServices) Analyze(
getCollectedFileContents func(string) ([]byte, error), findFiles getChildCollectedFileContents,
) ([]*AnalyzeResult, error) {
result := AnalyzeResult{Title: a.Title()}
collectedContents, err := retrieveCollectedContents(
getCollectedFileContents,
collect.HostServicesPath,
collect.NodeInfoBaseDir,
collect.HostServicesFileName,
)
if err != nil {
return []*AnalyzeResult{&result}, err
}
results, err := analyzeHostCollectorResults(collectedContents, a.hostAnalyzer.Outcomes, a.CheckCondition, a.Title())
if err != nil {
return nil, errors.Wrap(err, "failed to analyze host services")
}
return results, nil
}
// <service> <op> <state>
// example: ufw.service = active
func compareHostServicesConditionalToActual(conditional string, services []collect.ServiceInfo) (res bool, err error) {
parts := strings.Split(conditional, " ")
if len(parts) != 3 {
return false, fmt.Errorf("expected exactly 3 parts, got %d", len(parts))
}
matchParams := strings.Split(parts[2], ",")
activeMatch := matchParams[0]
subMatch := ""
loadMatch := ""
if len(matchParams) > 1 {
subMatch = matchParams[1]
}
if len(matchParams) > 2 {
loadMatch = matchParams[2]
}
switch parts[1] {
case "=", "==":
for _, service := range services {
if isServiceMatch(service.Unit, parts[0]) {
isMatch := true
if activeMatch != "" && activeMatch != "*" {
isMatch = isMatch && (activeMatch == service.Active)
}
if subMatch != "" && subMatch != "*" {
isMatch = isMatch && (subMatch == service.Sub)
}
if loadMatch != "" && loadMatch != "*" {
isMatch = isMatch && (loadMatch == service.Load)
}
return isMatch, nil
}
}
return false, nil
case "!=", "<>":
for _, service := range services {
if isServiceMatch(service.Unit, parts[0]) {
isMatch := false
if activeMatch != "" && activeMatch != "*" {
isMatch = isMatch || (activeMatch != service.Active)
}
if subMatch != "" && subMatch != "*" {
isMatch = isMatch || (subMatch != service.Sub)
}
if loadMatch != "" && loadMatch != "*" {
isMatch = isMatch || (loadMatch != service.Load)
}
return isMatch, nil
}
}
return false, nil
}
return false, fmt.Errorf("unexpected operator %q", parts[1])
}
func isServiceMatch(serviceName string, matchName string) bool {
if serviceName == matchName {
return true
}
if strings.HasPrefix(serviceName, matchName) {
return true
}
return false
}
func (a *AnalyzeHostServices) CheckCondition(when string, data []byte) (bool, error) {
var services []collect.ServiceInfo
if err := json.Unmarshal(data, &services); err != nil {
return false, fmt.Errorf("failed to unmarshal data into ServiceInfo: %v", err)
}
return compareHostServicesConditionalToActual(when, services)
}