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 }