github.com/AbhinandanKurakure/podman/v3@v3.4.10/pkg/systemd/generate/common.go (about)

     1  package generate
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  
     7  	"github.com/containers/podman/v3/pkg/systemd/define"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  // minTimeoutStopSec is the minimal stop timeout for generated systemd units.
    12  // Once exceeded, processes of the services are killed and the cgroup(s) are
    13  // cleaned up.
    14  const minTimeoutStopSec = 60
    15  
    16  // validateRestartPolicy checks that the user-provided policy is valid.
    17  func validateRestartPolicy(restart string) error {
    18  	for _, i := range define.RestartPolicies {
    19  		if i == restart {
    20  			return nil
    21  		}
    22  	}
    23  	return errors.Errorf("%s is not a valid restart policy", restart)
    24  }
    25  
    26  const headerTemplate = `# {{{{.ServiceName}}}}.service
    27  {{{{- if (eq .GenerateNoHeader false) }}}}
    28  # autogenerated by Podman {{{{.PodmanVersion}}}}
    29  {{{{- if .TimeStamp}}}}
    30  # {{{{.TimeStamp}}}}
    31  {{{{- end}}}}
    32  {{{{- end}}}}
    33  
    34  [Unit]
    35  Description=Podman {{{{.ServiceName}}}}.service
    36  Documentation=man:podman-generate-systemd(1)
    37  Wants=network-online.target
    38  After=network-online.target
    39  RequiresMountsFor={{{{.RunRoot}}}}
    40  `
    41  
    42  // filterPodFlags removes --pod, --pod-id-file and --infra-conmon-pidfile from the specified command.
    43  // argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint.
    44  func filterPodFlags(command []string, argCount int) []string {
    45  	processed := []string{}
    46  	for i := 0; i < len(command)-argCount; i++ {
    47  		s := command[i]
    48  		if s == "--pod" || s == "--pod-id-file" || s == "--infra-conmon-pidfile" {
    49  			i++
    50  			continue
    51  		}
    52  		if strings.HasPrefix(s, "--pod=") ||
    53  			strings.HasPrefix(s, "--pod-id-file=") ||
    54  			strings.HasPrefix(s, "--infra-conmon-pidfile=") {
    55  			continue
    56  		}
    57  		processed = append(processed, s)
    58  	}
    59  	processed = append(processed, command[len(command)-argCount:]...)
    60  	return processed
    61  }
    62  
    63  // filterCommonContainerFlags removes --sdnotify, --rm and --cgroups from the specified command.
    64  // argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint.
    65  func filterCommonContainerFlags(command []string, argCount int) []string {
    66  	processed := []string{}
    67  	for i := 0; i < len(command)-argCount; i++ {
    68  		s := command[i]
    69  
    70  		switch {
    71  		case s == "--rm":
    72  			// Boolean flags support --flag and --flag={true,false}.
    73  			continue
    74  		case s == "--sdnotify", s == "--cgroups", s == "--cidfile", s == "--restart":
    75  			i++
    76  			continue
    77  		case strings.HasPrefix(s, "--rm="),
    78  			strings.HasPrefix(s, "--cgroups="),
    79  			strings.HasPrefix(s, "--cidfile="),
    80  			strings.HasPrefix(s, "--restart="):
    81  			continue
    82  		}
    83  		processed = append(processed, s)
    84  	}
    85  	processed = append(processed, command[len(command)-argCount:]...)
    86  	return processed
    87  }
    88  
    89  // escapeSystemdArguments makes sure that all arguments with at least one whitespace
    90  // are quoted to make sure those are interpreted as one argument instead of
    91  // multiple ones. Also make sure to escape all characters which have a special
    92  // meaning to systemd -> $,% and \
    93  // see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines
    94  func escapeSystemdArguments(command []string) []string {
    95  	for i := range command {
    96  		command[i] = escapeSystemdArg(command[i])
    97  	}
    98  	return command
    99  }
   100  
   101  func escapeSystemdArg(arg string) string {
   102  	arg = strings.ReplaceAll(arg, "$", "$$")
   103  	arg = strings.ReplaceAll(arg, "%", "%%")
   104  	if strings.ContainsAny(arg, " \t") {
   105  		arg = strconv.Quote(arg)
   106  	} else if strings.Contains(arg, `\`) {
   107  		// strconv.Quote also escapes backslashes so
   108  		// we should replace only if strconv.Quote was not used
   109  		arg = strings.ReplaceAll(arg, `\`, `\\`)
   110  	}
   111  	return arg
   112  }
   113  
   114  func removeDetachArg(args []string, argCount int) []string {
   115  	// "--detach=false" could also be in the container entrypoint
   116  	// split them off so we do not remove it there
   117  	realArgs := args[len(args)-argCount:]
   118  	flagArgs := removeArg("-d=false", args[:len(args)-argCount])
   119  	flagArgs = removeArg("--detach=false", flagArgs)
   120  	return append(flagArgs, realArgs...)
   121  }
   122  
   123  func removeReplaceArg(args []string, argCount int) []string {
   124  	// "--replace=false" could also be in the container entrypoint
   125  	// split them off so we do not remove it there
   126  	realArgs := args[len(args)-argCount:]
   127  	flagArgs := removeArg("--replace=false", args[:len(args)-argCount])
   128  	return append(flagArgs, realArgs...)
   129  }
   130  
   131  func removeArg(arg string, args []string) []string {
   132  	newArgs := []string{}
   133  	for _, a := range args {
   134  		if a != arg {
   135  			newArgs = append(newArgs, a)
   136  		}
   137  	}
   138  	return newArgs
   139  }