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  }