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

     1  package sysctl
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  
    11  	"github.com/caos/orbos/internal/operator/common"
    12  	"github.com/caos/orbos/internal/operator/nodeagent"
    13  	"github.com/caos/orbos/internal/operator/nodeagent/dep/middleware"
    14  	"github.com/caos/orbos/mntr"
    15  )
    16  
    17  type Installer interface {
    18  	isSysctl()
    19  	nodeagent.Installer
    20  }
    21  type sysctlDep struct {
    22  	monitor mntr.Monitor
    23  }
    24  
    25  func New(monitor mntr.Monitor) Installer {
    26  	return &sysctlDep{monitor: monitor}
    27  }
    28  
    29  func (sysctlDep) isSysctl() {}
    30  
    31  func (sysctlDep) Is(other nodeagent.Installer) bool {
    32  	_, ok := middleware.Unwrap(other).(Installer)
    33  	return ok
    34  }
    35  
    36  func (sysctlDep) String() string { return "sysctl" }
    37  
    38  func (*sysctlDep) Equals(other nodeagent.Installer) bool {
    39  	_, ok := other.(*sysctlDep)
    40  	return ok
    41  }
    42  
    43  func (*sysctlDep) InstalledFilter() []string { return nil }
    44  
    45  var supportedModules = []common.KernelModule{common.IpForward, common.NonLocalBind, common.BridgeNfCallIptables, common.BridgeNfCallIp6tables}
    46  
    47  func Contains(this common.Package, that common.Package) bool {
    48  	if that.Config == nil {
    49  		return true
    50  	}
    51  
    52  	for thatKey, thatValue := range that.Config {
    53  		if this.Config == nil {
    54  			return false
    55  		}
    56  		if thisValue, ok := this.Config[thatKey]; !ok || thatValue == "1" && thisValue != "1" {
    57  			return false
    58  		}
    59  	}
    60  	return true
    61  }
    62  
    63  func Enable(pkg *common.Package, property common.KernelModule) {
    64  	if pkg.Config == nil {
    65  		pkg.Config = make(map[string]string)
    66  	}
    67  
    68  	for idx := range supportedModules {
    69  		module := supportedModules[idx]
    70  		if _, ok := pkg.Config[string(module)]; !ok {
    71  			pkg.Config[string(module)] = "0"
    72  		}
    73  	}
    74  	pkg.Config[string(property)] = "1"
    75  }
    76  
    77  func (s *sysctlDep) Current() (pkg common.Package, err error) {
    78  
    79  	for idx := range supportedModules {
    80  		module := supportedModules[idx]
    81  		if err := currentSysctlConfig(s.monitor, module, &pkg); err != nil {
    82  			return pkg, err
    83  		}
    84  	}
    85  
    86  	return pkg, nil
    87  }
    88  
    89  func (s *sysctlDep) Ensure(_ common.Package, ensure common.Package, _ bool) error {
    90  
    91  	if err := ioutil.WriteFile("/etc/sysctl.d/90-orbiter.conf", []byte(fmt.Sprintf(
    92  		`%s = %s
    93  %s = %s
    94  %s = %s
    95  %s = %s
    96  `,
    97  		string(common.IpForward), oneOrZero(ensure.Config, common.IpForward),
    98  		string(common.NonLocalBind), oneOrZero(ensure.Config, common.NonLocalBind),
    99  		string(common.BridgeNfCallIptables), oneOrZero(ensure.Config, common.BridgeNfCallIptables),
   100  		string(common.BridgeNfCallIp6tables), oneOrZero(ensure.Config, common.BridgeNfCallIp6tables),
   101  	)), os.ModePerm); err != nil {
   102  		return err
   103  	}
   104  
   105  	cmd := exec.Command("sysctl", "--system")
   106  	if output, err := cmd.CombinedOutput(); err != nil {
   107  		return fmt.Errorf("running %s failed with stderr %s: %w", strings.Join(cmd.Args, " "), string(output), err)
   108  	}
   109  	return nil
   110  }
   111  
   112  func oneOrZero(cfg map[string]string, property common.KernelModule) string {
   113  	val := cfg[string(property)]
   114  	if val == "1" {
   115  		return val
   116  	}
   117  	return "0"
   118  }
   119  
   120  func currentSysctlConfig(monitor mntr.Monitor, property common.KernelModule, pkg *common.Package) error {
   121  
   122  	propertyStr := string(property)
   123  
   124  	outBuf := new(bytes.Buffer)
   125  	defer outBuf.Reset()
   126  	errBuf := new(bytes.Buffer)
   127  	defer errBuf.Reset()
   128  
   129  	cmd := exec.Command("sysctl", propertyStr)
   130  	cmd.Stderr = errBuf
   131  	cmd.Stdout = outBuf
   132  
   133  	fullCmd := strings.Join(cmd.Args, " ")
   134  	monitor.WithFields(map[string]interface{}{"cmd": fullCmd}).Debug("Executing")
   135  
   136  	if err := cmd.Run(); err != nil {
   137  		errStr := errBuf.String()
   138  		if !strings.Contains(errStr, "No such file or directory") {
   139  			return fmt.Errorf("running %s failed with stderr %s: %w", fullCmd, errStr, err)
   140  		}
   141  	}
   142  
   143  	if pkg.Config == nil {
   144  		pkg.Config = make(map[string]string)
   145  	}
   146  	pkg.Config[propertyStr] = "0"
   147  	enabled := outBuf.String() == fmt.Sprintf("%s = 1\n", property)
   148  	if enabled {
   149  		pkg.Config[propertyStr] = "1"
   150  	}
   151  
   152  	return nil
   153  }