diff options
Diffstat (limited to 'pkg/systemd/generate/systemdgen.go')
-rw-r--r-- | pkg/systemd/generate/systemdgen.go | 237 |
1 files changed, 0 insertions, 237 deletions
diff --git a/pkg/systemd/generate/systemdgen.go b/pkg/systemd/generate/systemdgen.go deleted file mode 100644 index 73fe52c0e..000000000 --- a/pkg/systemd/generate/systemdgen.go +++ /dev/null @@ -1,237 +0,0 @@ -package generate - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - "text/template" - "time" - - "github.com/containers/libpod/version" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// EnvVariable "PODMAN_SYSTEMD_UNIT" is set in all generated systemd units and -// is set to the unit's (unique) name. -const EnvVariable = "PODMAN_SYSTEMD_UNIT" - -// ContainerInfo contains data required for generating a container's systemd -// unit file. -type ContainerInfo struct { - // ServiceName of the systemd service. - ServiceName string - // Name or ID of the container. - ContainerName string - // InfraContainer of the pod. - InfraContainer string - // StopTimeout sets the timeout Podman waits before killing the container - // during service stop. - StopTimeout uint - // RestartPolicy of the systemd unit (e.g., no, on-failure, always). - RestartPolicy string - // PIDFile of the service. Required for forking services. Must point to the - // PID of the associated conmon process. - PIDFile string - // GenerateTimestamp, if set the generated unit file has a time stamp. - GenerateTimestamp bool - // BoundToServices are the services this service binds to. Note that this - // service runs after them. - BoundToServices []string - // RequiredServices are services this service requires. Note that this - // service runs before them. - RequiredServices []string - // PodmanVersion for the header. Will be set internally. Will be auto-filled - // if left empty. - PodmanVersion string - // Executable is the path to the podman executable. Will be auto-filled if - // left empty. - Executable string - // TimeStamp at the time of creating the unit file. Will be set internally. - TimeStamp string - // New controls if a new container is created or if an existing one is started. - New bool - // CreateCommand is the full command plus arguments of the process the - // container has been created with. - CreateCommand []string - // RunCommand is a post-processed variant of CreateCommand and used for - // the ExecStart field in generic unit files. - RunCommand string - // EnvVariable is generate.EnvVariable and must not be set. - EnvVariable string -} - -var restartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"} - -// validateRestartPolicy checks that the user-provided policy is valid. -func validateRestartPolicy(restart string) error { - for _, i := range restartPolicies { - if i == restart { - return nil - } - } - return errors.Errorf("%s is not a valid restart policy", restart) -} - -const containerTemplate = `# {{.ServiceName}}.service -# autogenerated by Podman {{.PodmanVersion}} -{{- if .TimeStamp}} -# {{.TimeStamp}} -{{- end}} - -[Unit] -Description=Podman {{.ServiceName}}.service -Documentation=man:podman-generate-systemd(1) -Wants=network.target -After=network-online.target -{{- if .BoundToServices}} -RefuseManualStart=yes -RefuseManualStop=yes -BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -{{- end}} -{{- if .RequiredServices}} -Requires={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -{{- end}} - -[Service] -Environment={{.EnvVariable}}=%n -Restart={{.RestartPolicy}} -{{- if .New}} -ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid -ExecStart={{.RunCommand}} -ExecStop={{.Executable}} stop --ignore --cidfile %t/%n-cid {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} -ExecStopPost={{.Executable}} rm --ignore -f --cidfile %t/%n-cid -PIDFile=%t/%n-pid -{{- else}} -ExecStart={{.Executable}} start {{.ContainerName}} -ExecStop={{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerName}} -PIDFile={{.PIDFile}} -{{- end}} -KillMode=none -Type=forking - -[Install] -WantedBy=multi-user.target default.target` - -// Options include different options to control the unit file generation. -type Options struct { - // When set, generate service files in the current working directory and - // return the paths to these files instead of returning all contents in one - // big string. - Files bool - // New controls if a new container is created or if an existing one is started. - New bool -} - -// CreateContainerSystemdUnit creates a systemd unit file for a container. -func CreateContainerSystemdUnit(info *ContainerInfo, opts Options) (string, error) { - if err := validateRestartPolicy(info.RestartPolicy); err != nil { - return "", err - } - - // Make sure the executable is set. - if info.Executable == "" { - executable, err := os.Executable() - if err != nil { - executable = "/usr/bin/podman" - logrus.Warnf("Could not obtain podman executable location, using default %s", executable) - } - info.Executable = executable - } - - info.EnvVariable = EnvVariable - - // Assemble the ExecStart command when creating a new container. - // - // Note that we cannot catch all corner cases here such that users - // *must* manually check the generated files. A container might have - // been created via a Python script, which would certainly yield an - // invalid `info.CreateCommand`. Hence, we're doing a best effort unit - // generation and don't try aiming at completeness. - if opts.New { - // The create command must at least have three arguments: - // /usr/bin/podman run $IMAGE - index := 2 - if info.CreateCommand[1] == "container" { - index = 3 - } - if len(info.CreateCommand) < index+1 { - return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand) - } - // We're hard-coding the first five arguments and append the - // CreateCommand with a stripped command and subcomand. - command := []string{ - info.Executable, - "run", - "--conmon-pidfile", "%t/%n-pid", - "--cidfile", "%t/%n-cid", - "--cgroups=no-conmon", - } - - // Enforce detaching - // - // since we use systemd `Type=forking` service - // @see https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type= - // when we generated systemd service file with the --new param, - // `ExecStart` will have `/usr/bin/podman run ...` - // if `info.CreateCommand` has no `-d` or `--detach` param, - // podman will run the container in default attached mode, - // as a result, `systemd start` will wait the `podman run` command exit until failed with timeout error. - hasDetachParam := false - for _, p := range info.CreateCommand[index:] { - if p == "--detach" || p == "-d" { - hasDetachParam = true - } - } - if !hasDetachParam { - command = append(command, "-d") - } - - command = append(command, info.CreateCommand[index:]...) - info.RunCommand = strings.Join(command, " ") - info.New = true - } - - if info.PodmanVersion == "" { - info.PodmanVersion = version.Version - } - if info.GenerateTimestamp { - info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate)) - } - - // Sort the slices to assure a deterministic output. - sort.Strings(info.RequiredServices) - sort.Strings(info.BoundToServices) - - // Generate the template and compile it. - templ, err := template.New("systemd_service_file").Parse(containerTemplate) - if err != nil { - return "", errors.Wrap(err, "error parsing systemd service template") - } - - var buf bytes.Buffer - if err := templ.Execute(&buf, info); err != nil { - return "", err - } - - if !opts.Files { - return buf.String(), nil - } - - buf.WriteByte('\n') - cwd, err := os.Getwd() - if err != nil { - return "", errors.Wrap(err, "error getting current working directory") - } - path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName)) - if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil { - return "", errors.Wrap(err, "error generating systemd unit") - } - return path, nil -} |