github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/spec/createconfig.go (about)

     1  package createconfig
     2  
     3  import (
     4  	"os"
     5  	"strconv"
     6  	"strings"
     7  	"syscall"
     8  
     9  	"github.com/containers/image/v5/manifest"
    10  	"github.com/containers/libpod/libpod"
    11  	"github.com/containers/libpod/libpod/define"
    12  	"github.com/containers/libpod/pkg/namespaces"
    13  	"github.com/containers/libpod/pkg/seccomp"
    14  	"github.com/containers/storage"
    15  	"github.com/docker/go-connections/nat"
    16  	spec "github.com/opencontainers/runtime-spec/specs-go"
    17  	"github.com/opencontainers/runtime-tools/generate"
    18  	"github.com/pkg/errors"
    19  	"github.com/sirupsen/logrus"
    20  )
    21  
    22  // Type constants
    23  const (
    24  	bps = iota
    25  	iops
    26  )
    27  
    28  // CreateResourceConfig represents resource elements in CreateConfig
    29  // structures
    30  type CreateResourceConfig struct {
    31  	BlkioWeight       uint16   // blkio-weight
    32  	BlkioWeightDevice []string // blkio-weight-device
    33  	CPUPeriod         uint64   // cpu-period
    34  	CPUQuota          int64    // cpu-quota
    35  	CPURtPeriod       uint64   // cpu-rt-period
    36  	CPURtRuntime      int64    // cpu-rt-runtime
    37  	CPUShares         uint64   // cpu-shares
    38  	CPUs              float64  // cpus
    39  	CPUsetCPUs        string
    40  	CPUsetMems        string   // cpuset-mems
    41  	DeviceCgroupRules []string //device-cgroup-rule
    42  	DeviceReadBps     []string // device-read-bps
    43  	DeviceReadIOps    []string // device-read-iops
    44  	DeviceWriteBps    []string // device-write-bps
    45  	DeviceWriteIOps   []string // device-write-iops
    46  	DisableOomKiller  bool     // oom-kill-disable
    47  	KernelMemory      int64    // kernel-memory
    48  	Memory            int64    //memory
    49  	MemoryReservation int64    // memory-reservation
    50  	MemorySwap        int64    //memory-swap
    51  	MemorySwappiness  int      // memory-swappiness
    52  	OomScoreAdj       int      //oom-score-adj
    53  	PidsLimit         int64    // pids-limit
    54  	ShmSize           int64
    55  	Ulimit            []string //ulimit
    56  }
    57  
    58  // PidConfig configures the pid namespace for the container
    59  type PidConfig struct {
    60  	PidMode namespaces.PidMode //pid
    61  }
    62  
    63  // IpcConfig configures the ipc namespace for the container
    64  type IpcConfig struct {
    65  	IpcMode namespaces.IpcMode //ipc
    66  }
    67  
    68  // CgroupConfig configures the cgroup namespace for the container
    69  type CgroupConfig struct {
    70  	Cgroups      string
    71  	Cgroupns     string
    72  	CgroupParent string                // cgroup-parent
    73  	CgroupMode   namespaces.CgroupMode //cgroup
    74  }
    75  
    76  // UserConfig configures the user namespace for the container
    77  type UserConfig struct {
    78  	GroupAdd   []string // group-add
    79  	IDMappings *storage.IDMappingOptions
    80  	UsernsMode namespaces.UsernsMode //userns
    81  	User       string                //user
    82  }
    83  
    84  // UtsConfig configures the uts namespace for the container
    85  type UtsConfig struct {
    86  	UtsMode  namespaces.UTSMode //uts
    87  	NoHosts  bool
    88  	HostAdd  []string //add-host
    89  	Hostname string
    90  }
    91  
    92  // NetworkConfig configures the network namespace for the container
    93  type NetworkConfig struct {
    94  	DNSOpt       []string //dns-opt
    95  	DNSSearch    []string //dns-search
    96  	DNSServers   []string //dns
    97  	ExposedPorts map[nat.Port]struct{}
    98  	HTTPProxy    bool
    99  	IP6Address   string                 //ipv6
   100  	IPAddress    string                 //ip
   101  	LinkLocalIP  []string               // link-local-ip
   102  	MacAddress   string                 //mac-address
   103  	NetMode      namespaces.NetworkMode //net
   104  	Network      string                 //network
   105  	NetworkAlias []string               //network-alias
   106  	PortBindings nat.PortMap
   107  	Publish      []string //publish
   108  	PublishAll   bool     //publish-all
   109  }
   110  
   111  // SecurityConfig configures the security features for the container
   112  type SecurityConfig struct {
   113  	CapAdd                  []string // cap-add
   114  	CapDrop                 []string // cap-drop
   115  	CapRequired             []string // cap-required
   116  	LabelOpts               []string //SecurityOpts
   117  	NoNewPrivs              bool     //SecurityOpts
   118  	ApparmorProfile         string   //SecurityOpts
   119  	SeccompProfilePath      string   //SecurityOpts
   120  	SeccompProfileFromImage string   // seccomp profile from the container image
   121  	SeccompPolicy           seccomp.Policy
   122  	SecurityOpts            []string
   123  	Privileged              bool              //privileged
   124  	ReadOnlyRootfs          bool              //read-only
   125  	ReadOnlyTmpfs           bool              //read-only-tmpfs
   126  	Sysctl                  map[string]string //sysctl
   127  }
   128  
   129  // CreateConfig is a pre OCI spec structure.  It represents user input from varlink or the CLI
   130  // swagger:model CreateConfig
   131  type CreateConfig struct {
   132  	Annotations       map[string]string
   133  	Args              []string
   134  	CidFile           string
   135  	ConmonPidFile     string
   136  	Command           []string          // Full command that will be used
   137  	UserCommand       []string          // User-entered command (or image CMD)
   138  	Detach            bool              // detach
   139  	Devices           []string          // device
   140  	Entrypoint        []string          //entrypoint
   141  	Env               map[string]string //env
   142  	HealthCheck       *manifest.Schema2HealthConfig
   143  	Init              bool   // init
   144  	InitPath          string //init-path
   145  	Image             string
   146  	ImageID           string
   147  	RawImageName      string
   148  	BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
   149  	ImageVolumeType   string              // how to handle the image volume, either bind, tmpfs, or ignore
   150  	Interactive       bool                //interactive
   151  	Labels            map[string]string   //label
   152  	LogDriver         string              // log-driver
   153  	LogDriverOpt      []string            // log-opt
   154  	Name              string              //name
   155  	PodmanPath        string
   156  	Pod               string //pod
   157  	Quiet             bool   //quiet
   158  	Resources         CreateResourceConfig
   159  	RestartPolicy     string
   160  	Rm                bool           //rm
   161  	Rmi               bool           //rmi
   162  	StopSignal        syscall.Signal // stop-signal
   163  	StopTimeout       uint           // stop-timeout
   164  	Systemd           bool
   165  	Tmpfs             []string // tmpfs
   166  	Tty               bool     //tty
   167  	Mounts            []spec.Mount
   168  	MountsFlag        []string // mounts
   169  	NamedVolumes      []*libpod.ContainerNamedVolume
   170  	Volumes           []string //volume
   171  	VolumesFrom       []string
   172  	WorkDir           string //workdir
   173  	Rootfs            string
   174  	Security          SecurityConfig
   175  	Syslog            bool // Whether to enable syslog on exit commands
   176  
   177  	// Namespaces
   178  	Pid     PidConfig
   179  	Ipc     IpcConfig
   180  	Cgroup  CgroupConfig
   181  	User    UserConfig
   182  	Uts     UtsConfig
   183  	Network NetworkConfig
   184  }
   185  
   186  func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
   187  func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
   188  
   189  // CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig
   190  func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) {
   191  	return c.createBlockIO()
   192  }
   193  
   194  func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, error) {
   195  	config, err := runtime.GetConfig()
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	storageConfig := runtime.StorageConfig()
   200  
   201  	// We need a cleanup process for containers in the current model.
   202  	// But we can't assume that the caller is Podman - it could be another
   203  	// user of the API.
   204  	// As such, provide a way to specify a path to Podman, so we can
   205  	// still invoke a cleanup process.
   206  	cmd := c.PodmanPath
   207  	if cmd == "" {
   208  		cmd, _ = os.Executable()
   209  	}
   210  
   211  	command := []string{cmd,
   212  		"--root", storageConfig.GraphRoot,
   213  		"--runroot", storageConfig.RunRoot,
   214  		"--log-level", logrus.GetLevel().String(),
   215  		"--cgroup-manager", config.Engine.CgroupManager,
   216  		"--tmpdir", config.Engine.TmpDir,
   217  	}
   218  	if config.Engine.OCIRuntime != "" {
   219  		command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...)
   220  	}
   221  	if storageConfig.GraphDriverName != "" {
   222  		command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...)
   223  	}
   224  	for _, opt := range storageConfig.GraphDriverOptions {
   225  		command = append(command, []string{"--storage-opt", opt}...)
   226  	}
   227  	if config.Engine.EventsLogger != "" {
   228  		command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
   229  	}
   230  
   231  	if c.Syslog {
   232  		command = append(command, "--syslog", "true")
   233  	}
   234  	command = append(command, []string{"container", "cleanup"}...)
   235  
   236  	if c.Rm {
   237  		command = append(command, "--rm")
   238  	}
   239  
   240  	if c.Rmi {
   241  		command = append(command, "--rmi")
   242  	}
   243  
   244  	return command, nil
   245  }
   246  
   247  // GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
   248  func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) {
   249  	var options []libpod.CtrCreateOption
   250  	var err error
   251  
   252  	if c.Interactive {
   253  		options = append(options, libpod.WithStdin())
   254  	}
   255  	if c.Systemd {
   256  		options = append(options, libpod.WithSystemd())
   257  	}
   258  	if c.Name != "" {
   259  		logrus.Debugf("setting container name %s", c.Name)
   260  		options = append(options, libpod.WithName(c.Name))
   261  	}
   262  	if c.Pod != "" {
   263  		logrus.Debugf("adding container to pod %s", c.Pod)
   264  		options = append(options, runtime.WithPod(pod))
   265  	}
   266  
   267  	if len(mounts) != 0 || len(namedVolumes) != 0 {
   268  		destinations := []string{}
   269  
   270  		// Take all mount and named volume destinations.
   271  		for _, mount := range mounts {
   272  			destinations = append(destinations, mount.Destination)
   273  		}
   274  		for _, volume := range namedVolumes {
   275  			destinations = append(destinations, volume.Dest)
   276  		}
   277  
   278  		options = append(options, libpod.WithUserVolumes(destinations))
   279  	}
   280  
   281  	if len(namedVolumes) != 0 {
   282  		options = append(options, libpod.WithNamedVolumes(namedVolumes))
   283  	}
   284  
   285  	if len(c.UserCommand) != 0 {
   286  		options = append(options, libpod.WithCommand(c.UserCommand))
   287  	}
   288  
   289  	// Add entrypoint unconditionally
   290  	// If it's empty it's because it was explicitly set to "" or the image
   291  	// does not have one
   292  	options = append(options, libpod.WithEntrypoint(c.Entrypoint))
   293  
   294  	// TODO: MNT, USER, CGROUP
   295  	options = append(options, libpod.WithStopSignal(c.StopSignal))
   296  	options = append(options, libpod.WithStopTimeout(c.StopTimeout))
   297  
   298  	logPath, logTag := getLoggingOpts(c.LogDriverOpt)
   299  	if logPath != "" {
   300  		options = append(options, libpod.WithLogPath(logPath))
   301  	}
   302  	if logTag != "" {
   303  		options = append(options, libpod.WithLogTag(logTag))
   304  	}
   305  
   306  	if c.LogDriver != "" {
   307  		options = append(options, libpod.WithLogDriver(c.LogDriver))
   308  	}
   309  
   310  	secOpts, err := c.Security.ToCreateOptions()
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	options = append(options, secOpts...)
   315  
   316  	nsOpts, err := c.Cgroup.ToCreateOptions(runtime)
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  	options = append(options, nsOpts...)
   321  
   322  	nsOpts, err = c.Ipc.ToCreateOptions(runtime)
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  	options = append(options, nsOpts...)
   327  
   328  	nsOpts, err = c.Pid.ToCreateOptions(runtime)
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  	options = append(options, nsOpts...)
   333  
   334  	nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	options = append(options, nsOpts...)
   339  
   340  	nsOpts, err = c.Uts.ToCreateOptions(runtime, pod)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  	options = append(options, nsOpts...)
   345  
   346  	nsOpts, err = c.User.ToCreateOptions(runtime)
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  	options = append(options, nsOpts...)
   351  
   352  	// Gather up the options for NewContainer which consist of With... funcs
   353  	options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, c.RawImageName))
   354  	options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile))
   355  	options = append(options, libpod.WithLabels(c.Labels))
   356  	options = append(options, libpod.WithShmSize(c.Resources.ShmSize))
   357  	if c.Rootfs != "" {
   358  		options = append(options, libpod.WithRootFS(c.Rootfs))
   359  	}
   360  	// Default used if not overridden on command line
   361  
   362  	if c.RestartPolicy != "" {
   363  		if c.RestartPolicy == "unless-stopped" {
   364  			return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
   365  		}
   366  
   367  		split := strings.Split(c.RestartPolicy, ":")
   368  		if len(split) > 1 {
   369  			numTries, err := strconv.Atoi(split[1])
   370  			if err != nil {
   371  				return nil, errors.Wrapf(err, "%s is not a valid number of retries for restart policy", split[1])
   372  			}
   373  			if numTries < 0 {
   374  				return nil, errors.Wrapf(define.ErrInvalidArg, "restart policy requires a positive number of retries")
   375  			}
   376  			options = append(options, libpod.WithRestartRetries(uint(numTries)))
   377  		}
   378  		options = append(options, libpod.WithRestartPolicy(split[0]))
   379  	}
   380  
   381  	// Always use a cleanup process to clean up Podman after termination
   382  	exitCmd, err := c.createExitCommand(runtime)
   383  	if err != nil {
   384  		return nil, err
   385  	}
   386  	options = append(options, libpod.WithExitCommand(exitCmd))
   387  
   388  	if c.HealthCheck != nil {
   389  		options = append(options, libpod.WithHealthCheck(c.HealthCheck))
   390  		logrus.Debugf("New container has a health check")
   391  	}
   392  	return options, nil
   393  }
   394  
   395  // AddPrivilegedDevices iterates through host devices and adds all
   396  // host devices to the spec
   397  func AddPrivilegedDevices(g *generate.Generator) error {
   398  	return addPrivilegedDevices(g)
   399  }