github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/specgen/generate/container_create.go (about)

     1  package generate
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  
     7  	"github.com/containers/common/pkg/config"
     8  	"github.com/containers/libpod/libpod"
     9  	"github.com/containers/libpod/libpod/define"
    10  	"github.com/containers/libpod/pkg/specgen"
    11  	"github.com/containers/storage"
    12  	"github.com/pkg/errors"
    13  	"github.com/sirupsen/logrus"
    14  )
    15  
    16  // MakeContainer creates a container based on the SpecGenerator
    17  func MakeContainer(rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Container, error) {
    18  	if err := s.Validate(); err != nil {
    19  		return nil, errors.Wrap(err, "invalid config provided")
    20  	}
    21  	rtc, err := rt.GetConfig()
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  
    26  	options, err := createContainerOptions(rt, s)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	podmanPath, err := os.Executable()
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	options = append(options, createExitCommandOption(s, rt.StorageConfig(), rtc, podmanPath))
    36  	newImage, err := rt.ImageRuntime().NewFromLocal(s.Image)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	options = append(options, libpod.WithRootFSFromImage(newImage.ID(), s.Image, s.RawImageName))
    42  
    43  	runtimeSpec, err := SpecGenToOCI(s, rt, newImage)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return rt.NewContainer(context.Background(), runtimeSpec, options...)
    48  }
    49  
    50  func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator) ([]libpod.CtrCreateOption, error) {
    51  	var options []libpod.CtrCreateOption
    52  	var err error
    53  
    54  	if s.Stdin {
    55  		options = append(options, libpod.WithStdin())
    56  	}
    57  	if len(s.Systemd) > 0 {
    58  		options = append(options, libpod.WithSystemd())
    59  	}
    60  	if len(s.Name) > 0 {
    61  		logrus.Debugf("setting container name %s", s.Name)
    62  		options = append(options, libpod.WithName(s.Name))
    63  	}
    64  	if s.Pod != "" {
    65  		pod, err := rt.LookupPod(s.Pod)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  		logrus.Debugf("adding container to pod %s", s.Pod)
    70  		options = append(options, rt.WithPod(pod))
    71  	}
    72  	destinations := []string{}
    73  	//	// Take all mount and named volume destinations.
    74  	for _, mount := range s.Mounts {
    75  		destinations = append(destinations, mount.Destination)
    76  	}
    77  	for _, volume := range s.Volumes {
    78  		destinations = append(destinations, volume.Dest)
    79  	}
    80  	options = append(options, libpod.WithUserVolumes(destinations))
    81  
    82  	if len(s.Volumes) != 0 {
    83  		var volumes []*libpod.ContainerNamedVolume
    84  		for _, v := range s.Volumes {
    85  			volumes = append(volumes, &libpod.ContainerNamedVolume{
    86  				Name:    v.Name,
    87  				Dest:    v.Dest,
    88  				Options: v.Options,
    89  			})
    90  		}
    91  		options = append(options, libpod.WithNamedVolumes(volumes))
    92  	}
    93  
    94  	if len(s.Command) != 0 {
    95  		options = append(options, libpod.WithCommand(s.Command))
    96  	}
    97  
    98  	options = append(options, libpod.WithEntrypoint(s.Entrypoint))
    99  	if s.StopSignal != nil {
   100  		options = append(options, libpod.WithStopSignal(*s.StopSignal))
   101  	}
   102  	if s.StopTimeout != nil {
   103  		options = append(options, libpod.WithStopTimeout(*s.StopTimeout))
   104  	}
   105  	if s.LogConfiguration != nil {
   106  		if len(s.LogConfiguration.Path) > 0 {
   107  			options = append(options, libpod.WithLogPath(s.LogConfiguration.Path))
   108  		}
   109  		if len(s.LogConfiguration.Options) > 0 && s.LogConfiguration.Options["tag"] != "" {
   110  			// Note: I'm really guessing here.
   111  			options = append(options, libpod.WithLogTag(s.LogConfiguration.Options["tag"]))
   112  		}
   113  
   114  		if len(s.LogConfiguration.Driver) > 0 {
   115  			options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver))
   116  		}
   117  	}
   118  
   119  	// Security options
   120  	if len(s.SelinuxOpts) > 0 {
   121  		options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
   122  	}
   123  	options = append(options, libpod.WithPrivileged(s.Privileged))
   124  
   125  	// Get namespace related options
   126  	namespaceOptions, err := GenerateNamespaceContainerOpts(s, rt)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	options = append(options, namespaceOptions...)
   131  
   132  	if len(s.ConmonPidFile) > 0 {
   133  		options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile))
   134  	}
   135  	options = append(options, libpod.WithLabels(s.Labels))
   136  	if s.ShmSize != nil {
   137  		options = append(options, libpod.WithShmSize(*s.ShmSize))
   138  	}
   139  	if s.Rootfs != "" {
   140  		options = append(options, libpod.WithRootFS(s.Rootfs))
   141  	}
   142  	// Default used if not overridden on command line
   143  
   144  	if s.RestartPolicy != "" {
   145  		if s.RestartPolicy == "unless-stopped" {
   146  			return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
   147  		}
   148  		if s.RestartRetries != nil {
   149  			options = append(options, libpod.WithRestartRetries(*s.RestartRetries))
   150  		}
   151  		options = append(options, libpod.WithRestartPolicy(s.RestartPolicy))
   152  	}
   153  
   154  	if s.ContainerHealthCheckConfig.HealthConfig != nil {
   155  		options = append(options, libpod.WithHealthCheck(s.ContainerHealthCheckConfig.HealthConfig))
   156  		logrus.Debugf("New container has a health check")
   157  	}
   158  	return options, nil
   159  }
   160  
   161  func createExitCommandOption(s *specgen.SpecGenerator, storageConfig storage.StoreOptions, config *config.Config, podmanPath string) libpod.CtrCreateOption {
   162  	// We need a cleanup process for containers in the current model.
   163  	// But we can't assume that the caller is Podman - it could be another
   164  	// user of the API.
   165  	// As such, provide a way to specify a path to Podman, so we can
   166  	// still invoke a cleanup process.
   167  
   168  	command := []string{podmanPath,
   169  		"--root", storageConfig.GraphRoot,
   170  		"--runroot", storageConfig.RunRoot,
   171  		"--log-level", logrus.GetLevel().String(),
   172  		"--cgroup-manager", config.Engine.CgroupManager,
   173  		"--tmpdir", config.Engine.TmpDir,
   174  	}
   175  	if config.Engine.OCIRuntime != "" {
   176  		command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...)
   177  	}
   178  	if storageConfig.GraphDriverName != "" {
   179  		command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...)
   180  	}
   181  	for _, opt := range storageConfig.GraphDriverOptions {
   182  		command = append(command, []string{"--storage-opt", opt}...)
   183  	}
   184  	if config.Engine.EventsLogger != "" {
   185  		command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
   186  	}
   187  
   188  	// TODO Mheon wants to leave this for now
   189  	//if s.sys {
   190  	//	command = append(command, "--syslog", "true")
   191  	//}
   192  	command = append(command, []string{"container", "cleanup"}...)
   193  
   194  	if s.Remove {
   195  		command = append(command, "--rm")
   196  	}
   197  	return libpod.WithExitCommand(command)
   198  }