github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/operator/nodeagent/dep/systemd.go (about)

     1  package dep
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"strings"
     9  
    10  	"github.com/caos/orbos/mntr"
    11  )
    12  
    13  type SystemD struct {
    14  	monitor mntr.Monitor
    15  }
    16  
    17  func NewSystemD(monitor mntr.Monitor) *SystemD {
    18  	return &SystemD{monitor}
    19  }
    20  
    21  func (s *SystemD) Disable(binary string) error {
    22  
    23  	errBuf := new(bytes.Buffer)
    24  	defer errBuf.Reset()
    25  
    26  	cmd := exec.Command("systemctl", "stop", binary)
    27  	cmd.Stderr = errBuf
    28  	if s.monitor.IsVerbose() {
    29  		fmt.Println(strings.Join(cmd.Args, " "))
    30  		cmd.Stdout = os.Stdout
    31  	}
    32  	err := cmd.Run()
    33  	if err != nil {
    34  		errString := errBuf.String()
    35  		if strings.Contains(errString, "not loaded") {
    36  			err = nil
    37  		} else {
    38  			return fmt.Errorf("stopping %s by systemd failed with stderr %s: %w", binary, errString, err)
    39  		}
    40  	}
    41  
    42  	errBuf.Reset()
    43  	cmd = exec.Command("systemctl", "disable", binary)
    44  	cmd.Stderr = errBuf
    45  	if s.monitor.IsVerbose() {
    46  		fmt.Println(strings.Join(cmd.Args, " "))
    47  		cmd.Stdout = os.Stdout
    48  	}
    49  	if err := cmd.Run(); err != nil {
    50  		errString := errBuf.String()
    51  		if strings.Contains(errString, "No such file or directory") {
    52  			err = nil
    53  		} else {
    54  			return fmt.Errorf("disabling %s by systemd failed with stderr %s: %w", binary, errString, err)
    55  		}
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  func (s *SystemD) Start(binary string) error {
    62  	errBuf := new(bytes.Buffer)
    63  	defer errBuf.Reset()
    64  
    65  	cmd := exec.Command("systemctl", "restart", binary)
    66  	cmd.Stderr = errBuf
    67  
    68  	if err := cmd.Run(); err != nil {
    69  		return fmt.Errorf("restarting %s from systemd failed with stderr %s: %w", binary, errBuf.String(), err)
    70  	}
    71  	return nil
    72  }
    73  
    74  func (s *SystemD) Enable(binary string) error {
    75  
    76  	errBuf := new(bytes.Buffer)
    77  	defer errBuf.Reset()
    78  
    79  	cmd := exec.Command("systemctl", "enable", binary)
    80  	cmd.Stderr = errBuf
    81  	if s.monitor.IsVerbose() {
    82  		fmt.Println(strings.Join(cmd.Args, " "))
    83  		cmd.Stdout = os.Stdout
    84  	}
    85  
    86  	if err := cmd.Run(); err != nil {
    87  		return fmt.Errorf("enabling systemd unit %s failed with stderr %s: %w", binary, errBuf.String(), err)
    88  	}
    89  
    90  	if !s.Active(binary) {
    91  		return s.Start(binary)
    92  	}
    93  	return nil
    94  }
    95  
    96  func (s *SystemD) Active(binary string) bool {
    97  	cmd := exec.Command("systemctl", "is-active", binary)
    98  	if s.monitor.IsVerbose() {
    99  		fmt.Println(strings.Join(cmd.Args, " "))
   100  		cmd.Stdout = os.Stdout
   101  	}
   102  	return cmd.Run() == nil
   103  }
   104  
   105  func (s *SystemD) UnitPath(unit string) (string, error) {
   106  
   107  	const showProperty = "FragmentPath"
   108  	const expectOutputPrefix = showProperty + "="
   109  
   110  	errBuf := new(bytes.Buffer)
   111  	defer errBuf.Reset()
   112  	outBuf := new(bytes.Buffer)
   113  	defer outBuf.Reset()
   114  	cmd := exec.Command("systemctl", "show", "-p", showProperty, unit)
   115  	cmd.Stderr = errBuf
   116  	cmd.Stdout = outBuf
   117  	err := cmd.Run()
   118  	errStr := errBuf.String()
   119  	outStr := outBuf.String()
   120  	s.monitor.WithFields(map[string]interface{}{
   121  		"stdout": outStr,
   122  		"stderr": errStr,
   123  	}).Debug("Executed " + strings.Join(cmd.Args, " "))
   124  	if err != nil {
   125  		return "", fmt.Errorf("getting systemd unit path for %s failed with stderr %s: %w", unit, errStr, err)
   126  	}
   127  
   128  	if !strings.HasPrefix(outStr, expectOutputPrefix) {
   129  		return "", fmt.Errorf("expected prefix %s but got %s", expectOutputPrefix, outStr)
   130  	}
   131  
   132  	return strings.Trim(strings.TrimPrefix(outStr, expectOutputPrefix), "\n"), nil
   133  }