internal/service/serviceinstall.go (190 lines of code) (raw):

package service import ( "fmt" "os" "strings" "github.com/Azure/run-command-handler-linux/internal/constants" "github.com/Azure/run-command-handler-linux/pkg/servicehandler" "github.com/Azure/run-command-handler-linux/pkg/systemd" "github.com/go-kit/kit/log" "github.com/pkg/errors" ) const ( systemdUnitName = "managedruncommand.service" systemdUnitConfigurationPath = "misc/managedruncommand.service" runcommand_working_directory_placeholder = "%run_command_working_directory%" runcommand_output_directory_placeholder = "%run_command_output_directory%" systemdUnitConfigurationTemplate = `[Unit] Description=Managed RunCommand Service [Service] User=root Restart=always RestartSec=5 WorkingDirectory=%run_command_working_directory% ExecStart=%run_command_working_directory%/bin/immediate-run-command-handler StandardOutput=append:%run_command_output_directory% StandardError=append:%run_command_output_directory% [Install] WantedBy=multi-user.target` ) func Register(ctx *log.Context) error { if !isSystemdSupported(ctx) { return errors.New("Systemd not supported. Failed to register service") } targetVersion := os.Getenv(constants.ExtensionVersionEnvName) ctx.Log("message", "trying to register extension with version: "+targetVersion) ctx.Log("message", "Generating service configuration files") systemdUnitContent := generateServiceConfigurationContent(ctx) serviceHandler := getSystemdHandler(ctx) isInstalled, err := IsInstalled(ctx) if err != nil { return err } // If the service is installed, check if it needs to be upgraded. if isInstalled { installedVersion, err := serviceHandler.GetInstalledVersion(ctx) if err != nil { return err } if installedVersion == targetVersion { ctx.Log("message", "installed service already matches the target version") return nil } } ctx.Log("message", "Registering service using version: "+targetVersion) ctx.Log("message", "Making immediate-run-command-handler executable") execDirectory := os.Getenv(constants.ExtensionPathEnvName) + "/bin/immediate-run-command-handler" err = os.Chmod(execDirectory, 0744) if err != nil { return errors.Wrap(err, "error while marking the immediate run command binary as executable") } err = serviceHandler.Register(ctx, systemdUnitContent) if err != nil { return err } err = Start(ctx) if err != nil { return err } ctx.Log("message", "Service registration complete") return nil } func DeRegister(ctx *log.Context) error { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "Deregistering service") err := serviceHandler.DeRegister(ctx) if err != nil { return err } ctx.Log("message", "Service deregistration complete") } return nil } func Start(ctx *log.Context) error { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "Starting service") err := serviceHandler.Start() if err != nil { return err } ctx.Log("message", "Service started") } return nil } func Disable(ctx *log.Context) error { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "Stopping service") err := serviceHandler.Stop() if err != nil { return err } ctx.Log("message", "Service stopped") ctx.Log("message", "Disabling service") err = serviceHandler.Disable() if err != nil { return err } ctx.Log("message", "Service disabled") } return nil } func Enable(ctx *log.Context) error { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "enabling service") err := serviceHandler.Enable() if err != nil { return err } ctx.Log("message", "Service enabled") } return nil } func Stop(ctx *log.Context) error { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "Stopping service") err := serviceHandler.Stop() if err != nil { return err } ctx.Log("message", "Service stopped") } return nil } func IsActive(ctx *log.Context) (bool, error) { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) isActive, err := serviceHandler.IsActive() if err != nil { return false, err } ctx.Log("message", fmt.Sprintf("Service is active : %v", isActive)) return isActive, nil } return false, nil } func IsEnabled(ctx *log.Context) (bool, error) { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) isEnabled, err := serviceHandler.IsEnabled() ctx.Log("message", fmt.Sprintf("Service is enabled : %v", isEnabled)) return isEnabled, err } return false, nil } func IsInstalled(ctx *log.Context) (bool, error) { if isSystemdSupported(ctx) { serviceHandler := getSystemdHandler(ctx) ctx.Log("message", "Checking if service is installed") isInstalled, err := serviceHandler.IsInstalled() ctx.Log("message", fmt.Sprintf("Service is installed: %v", isInstalled)) return isInstalled, err } return false, nil } func getSystemdHandler(ctx *log.Context) *servicehandler.Handler { ctx.Log("message", "Getting service handler for "+systemdUnitName) config := servicehandler.NewConfiguration(systemdUnitName) handler := servicehandler.NewHandler(systemd.NewUnitManager(), config, ctx) return &handler } func generateServiceConfigurationContent(ctx *log.Context) string { workingDirectory := os.Getenv(constants.ExtensionPathEnvName) systemdConfigContentWithOutputDir := strings.ReplaceAll(systemdUnitConfigurationTemplate, runcommand_output_directory_placeholder, constants.ImmediateRCOutputDirectory) systemdConfigContent := strings.ReplaceAll(systemdConfigContentWithOutputDir, runcommand_working_directory_placeholder, workingDirectory) ctx.Log("message", "Using working directory: "+workingDirectory) return systemdConfigContent } func isSystemdSupported(ctx *log.Context) bool { ctx.Log("message", "Check if systemd is present on the system before applying next operation") result := systemd.IsSystemDPresent() if result { ctx.Log("message", "systemd was found on the system") } else { ctx.Log("message", "systemd was not found on the system") } return result }