pkg/systemd/manager.go (121 lines of code) (raw):

package systemd import ( "fmt" "os" "os/exec" "path" "strings" "github.com/Azure/run-command-handler-linux/pkg/versionutil" "github.com/go-kit/kit/log" "github.com/pkg/errors" ) const ( systemctl = "systemctl" systemctl_daemonreload = "daemon-reload" systemctl_disable = "disable" systemctl_enable = "enable" systemctl_isactive = "is-active" systemctl_isenabled = "is-enabled" systemctl_start = "start" systemctl_status = "status" systemctl_stop = "stop" unitConfigurationBasePath_preferred = "/etc/systemd/system" // system units created by the administrator path unitConfigurationBasePath_alternative = "/usr/local/lib/systemd/system" // system units installed by the administrator path unitConfigurationFilePermission = 0644 // rw-r--r-- ) type Manager struct { } func NewUnitManager() *Manager { return &Manager{} } func (mgr *Manager) StartUnit(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to start unit") err := exec.Command(systemctl, systemctl_start, unitName).Run() return err } func (mgr *Manager) StopUnit(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to stop unit") err := exec.Command(systemctl, systemctl_stop, unitName).Run() return err } func (mgr *Manager) EnableUnit(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to enable unit") err := exec.Command(systemctl, systemctl_enable, unitName).Run() return err } func (mgr *Manager) DisableUnit(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to disable unit") err := exec.Command(systemctl, systemctl_disable, unitName).Run() return err } func (mgr *Manager) DaemonReload(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to reload daemon") err := exec.Command(systemctl, systemctl_daemonreload).Run() return err } func (mgr *Manager) IsUnitActive(unitName string, ctx *log.Context) error { ctx.Log("message", "running command to check if unit is active") err := exec.Command(systemctl, systemctl_isactive, unitName).Run() return err } func (mgr *Manager) IsUnitEnabled(unitName string, ctx *log.Context) (bool, error) { ctx.Log("message", "running command to check if unit is already enabled") output, err := exec.Command(systemctl, systemctl_isenabled, unitName).Output() sanitizedOutput := strings.Replace(string(output), "\n", "", -1) ctx.Log("message", fmt.Sprintf("%v %v output: %v", systemctl, systemctl_isenabled, sanitizedOutput)) if sanitizedOutput == "enabled" { return true, nil } else if sanitizedOutput == "disabled" { return false, nil } return false, err } func (mgr *Manager) IsUnitInstalled(unitName string, ctx *log.Context) (bool, error) { filePath, err := GetUnitConfigurationFilePath(unitName, ctx) if err != nil { return false, err } ctx.Log("message", fmt.Sprintf("Checking if unit file %v exists to verify presence of installed service", filePath)) _, err = os.Stat(filePath) if os.IsNotExist(err) { return false, nil } else if err != nil { return false, errors.Wrap(err, "Error occurred while checking file existence") } return true, nil } func (*Manager) CreateUnitConfigurationFile(unitName string, content []byte, ctx *log.Context) error { unitConfigPath, err := GetUnitConfigurationFilePath(unitName, ctx) if err != nil { return err } ctx.Log("message", "creating unit configuration file in "+unitConfigPath) return os.WriteFile(unitConfigPath, content, unitConfigurationFilePermission) } func (*Manager) RemoveUnitConfigurationFile(unitName string, ctx *log.Context) error { unitConfigPath, err := GetUnitConfigurationFilePath(unitName, ctx) if err != nil { return err } ctx.Log("message", "removing unit configuration file from "+unitConfigPath) return os.Remove(unitConfigPath) } // Gets the installed version of the extension. The version will look at the service definition and extract it from the // ExecStart field as there isn't a way to include a version parameter in the definition. The field looks as follows: // ExecStart=/var/lib/waagent/Microsoft.CPlat.Core.RunCOmmandHandlerLinux-1.0.0/bin/immediate-run-command-handler func (*Manager) GetInstalledVersion(unitName string, ctx *log.Context) (string, error) { unitConfigPath, err := GetUnitConfigurationFilePath(unitName, ctx) if err != nil { return "", err } ctx.Log("message", "getting content from "+unitConfigPath) content, err := os.ReadFile(unitConfigPath) if err != nil { return "", err } return versionutil.ExtractFromServiceDefinition(string(content), ctx) } var GetUnitConfigurationFilePath = func(unitName string, ctx *log.Context) (string, error) { base_path, err := GetSystemDConfigurationBasePath(ctx) if err != nil { return "", err } return path.Join(base_path, unitName), nil }