github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/api/handlers/compat/containers_create.go (about) 1 package compat 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 9 "github.com/containers/common/pkg/config" 10 "github.com/containers/libpod/libpod" 11 image2 "github.com/containers/libpod/libpod/image" 12 "github.com/containers/libpod/pkg/api/handlers" 13 "github.com/containers/libpod/pkg/api/handlers/utils" 14 "github.com/containers/libpod/pkg/namespaces" 15 "github.com/containers/libpod/pkg/signal" 16 createconfig "github.com/containers/libpod/pkg/spec" 17 "github.com/containers/storage" 18 "github.com/gorilla/schema" 19 "github.com/pkg/errors" 20 "golang.org/x/sys/unix" 21 ) 22 23 func CreateContainer(w http.ResponseWriter, r *http.Request) { 24 runtime := r.Context().Value("runtime").(*libpod.Runtime) 25 decoder := r.Context().Value("decoder").(*schema.Decoder) 26 input := handlers.CreateContainerConfig{} 27 query := struct { 28 Name string `schema:"name"` 29 }{ 30 // override any golang type defaults 31 } 32 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 33 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 34 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 35 return 36 } 37 if err := json.NewDecoder(r.Body).Decode(&input); err != nil { 38 utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) 39 return 40 } 41 if len(input.HostConfig.Links) > 0 { 42 utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter")) 43 } 44 newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image) 45 if err != nil { 46 utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()")) 47 return 48 } 49 defaultContainerConfig, err := runtime.GetConfig() 50 if err != nil { 51 utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "GetConfig()")) 52 return 53 } 54 cc, err := makeCreateConfig(defaultContainerConfig, input, newImage) 55 if err != nil { 56 utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()")) 57 return 58 } 59 cc.Name = query.Name 60 utils.CreateContainer(r.Context(), w, runtime, &cc) 61 } 62 63 func makeCreateConfig(defaultContainerConfig *config.Config, input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) { 64 var ( 65 err error 66 init bool 67 tmpfs []string 68 volumes []string 69 ) 70 env := make(map[string]string) 71 stopSignal := unix.SIGTERM 72 if len(input.StopSignal) > 0 { 73 stopSignal, err = signal.ParseSignal(input.StopSignal) 74 if err != nil { 75 return createconfig.CreateConfig{}, err 76 } 77 } 78 79 workDir := "/" 80 if len(input.WorkingDir) > 0 { 81 workDir = input.WorkingDir 82 } 83 84 stopTimeout := defaultContainerConfig.Engine.StopTimeout 85 if input.StopTimeout != nil { 86 stopTimeout = uint(*input.StopTimeout) 87 } 88 c := createconfig.CgroupConfig{ 89 Cgroups: "", // podman 90 Cgroupns: "", // podman 91 CgroupParent: "", // podman 92 CgroupMode: "", // podman 93 } 94 security := createconfig.SecurityConfig{ 95 CapAdd: input.HostConfig.CapAdd, 96 CapDrop: input.HostConfig.CapDrop, 97 LabelOpts: nil, // podman 98 NoNewPrivs: false, // podman 99 ApparmorProfile: "", // podman 100 SeccompProfilePath: "", 101 SecurityOpts: input.HostConfig.SecurityOpt, 102 Privileged: input.HostConfig.Privileged, 103 ReadOnlyRootfs: input.HostConfig.ReadonlyRootfs, 104 ReadOnlyTmpfs: false, // podman-only 105 Sysctl: input.HostConfig.Sysctls, 106 } 107 108 network := createconfig.NetworkConfig{ 109 DNSOpt: input.HostConfig.DNSOptions, 110 DNSSearch: input.HostConfig.DNSSearch, 111 DNSServers: input.HostConfig.DNS, 112 ExposedPorts: input.ExposedPorts, 113 HTTPProxy: false, // podman 114 IP6Address: "", 115 IPAddress: "", 116 LinkLocalIP: nil, // docker-only 117 MacAddress: input.MacAddress, 118 // NetMode: nil, 119 Network: input.HostConfig.NetworkMode.NetworkName(), 120 NetworkAlias: nil, // docker-only now 121 PortBindings: input.HostConfig.PortBindings, 122 Publish: nil, // podmanseccompPath 123 PublishAll: input.HostConfig.PublishAllPorts, 124 } 125 126 uts := createconfig.UtsConfig{ 127 UtsMode: namespaces.UTSMode(input.HostConfig.UTSMode), 128 NoHosts: false, //podman 129 HostAdd: input.HostConfig.ExtraHosts, 130 Hostname: input.Hostname, 131 } 132 133 z := createconfig.UserConfig{ 134 GroupAdd: input.HostConfig.GroupAdd, 135 IDMappings: &storage.IDMappingOptions{}, // podman //TODO <--- fix this, 136 UsernsMode: namespaces.UsernsMode(input.HostConfig.UsernsMode), 137 User: input.User, 138 } 139 pidConfig := createconfig.PidConfig{PidMode: namespaces.PidMode(input.HostConfig.PidMode)} 140 for k := range input.Volumes { 141 volumes = append(volumes, k) 142 } 143 144 // Docker is more flexible about its input where podman throws 145 // away incorrectly formatted variables so we cannot reuse the 146 // parsing of the env input 147 // [Foo Other=one Blank=] 148 for _, e := range input.Env { 149 splitEnv := strings.Split(e, "=") 150 switch len(splitEnv) { 151 case 0: 152 continue 153 case 1: 154 env[splitEnv[0]] = "" 155 default: 156 env[splitEnv[0]] = strings.Join(splitEnv[1:], "=") 157 } 158 } 159 160 // format the tmpfs mounts into a []string from map 161 for k, v := range input.HostConfig.Tmpfs { 162 tmpfs = append(tmpfs, fmt.Sprintf("%s:%s", k, v)) 163 } 164 165 if input.HostConfig.Init != nil && *input.HostConfig.Init { 166 init = true 167 } 168 169 m := createconfig.CreateConfig{ 170 Annotations: nil, // podman 171 Args: nil, 172 Cgroup: c, 173 CidFile: "", 174 ConmonPidFile: "", // podman 175 Command: input.Cmd, 176 UserCommand: input.Cmd, // podman 177 Detach: false, // 178 // Devices: input.HostConfig.Devices, 179 Entrypoint: input.Entrypoint, 180 Env: env, 181 HealthCheck: nil, // 182 Init: init, 183 InitPath: "", // tbd 184 Image: input.Image, 185 ImageID: newImage.ID(), 186 BuiltinImgVolumes: nil, // podman 187 ImageVolumeType: "", // podman 188 Interactive: false, 189 // IpcMode: input.HostConfig.IpcMode, 190 Labels: input.Labels, 191 LogDriver: input.HostConfig.LogConfig.Type, // is this correct 192 // LogDriverOpt: input.HostConfig.LogConfig.Config, 193 Name: input.Name, 194 Network: network, 195 Pod: "", // podman 196 PodmanPath: "", // podman 197 Quiet: false, // front-end only 198 Resources: createconfig.CreateResourceConfig{}, 199 RestartPolicy: input.HostConfig.RestartPolicy.Name, 200 Rm: input.HostConfig.AutoRemove, 201 StopSignal: stopSignal, 202 StopTimeout: stopTimeout, 203 Systemd: false, // podman 204 Tmpfs: tmpfs, 205 User: z, 206 Uts: uts, 207 Tty: input.Tty, 208 Mounts: nil, // we populate 209 // MountsFlag: input.HostConfig.Mounts, 210 NamedVolumes: nil, // we populate 211 Volumes: volumes, 212 VolumesFrom: input.HostConfig.VolumesFrom, 213 WorkDir: workDir, 214 Rootfs: "", // podman 215 Security: security, 216 Syslog: false, // podman 217 218 Pid: pidConfig, 219 } 220 return m, nil 221 }