mirror of
				https://github.com/containers/podman.git
				synced 2025-11-01 02:42:11 +08:00 
			
		
		
		
	 9c4611f166
			
		
	
	9c4611f166
	
	
	
		
			
			when using the compatibility mode as rootless, containers that were created were not setting their host names correctly due to the netmode not being set. Fixes: #7934 Signed-off-by: baude <bbaude@redhat.com>
		
			
				
	
	
		
			276 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package compat
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/containers/common/pkg/config"
 | |
| 	"github.com/containers/podman/v2/libpod"
 | |
| 	"github.com/containers/podman/v2/libpod/define"
 | |
| 	image2 "github.com/containers/podman/v2/libpod/image"
 | |
| 	"github.com/containers/podman/v2/pkg/api/handlers"
 | |
| 	"github.com/containers/podman/v2/pkg/api/handlers/utils"
 | |
| 	"github.com/containers/podman/v2/pkg/namespaces"
 | |
| 	"github.com/containers/podman/v2/pkg/rootless"
 | |
| 	"github.com/containers/podman/v2/pkg/signal"
 | |
| 	createconfig "github.com/containers/podman/v2/pkg/spec"
 | |
| 	"github.com/containers/podman/v2/pkg/specgen"
 | |
| 	"github.com/containers/storage"
 | |
| 	"github.com/gorilla/schema"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"golang.org/x/sys/unix"
 | |
| )
 | |
| 
 | |
| func CreateContainer(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value("runtime").(*libpod.Runtime)
 | |
| 	decoder := r.Context().Value("decoder").(*schema.Decoder)
 | |
| 	input := handlers.CreateContainerConfig{}
 | |
| 	query := struct {
 | |
| 		Name string `schema:"name"`
 | |
| 	}{
 | |
| 		// override any golang type defaults
 | |
| 	}
 | |
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
 | |
| 		utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
 | |
| 			errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
 | |
| 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
 | |
| 		return
 | |
| 	}
 | |
| 	if len(input.HostConfig.Links) > 0 {
 | |
| 		utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
 | |
| 		return
 | |
| 	}
 | |
| 	newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
 | |
| 	if err != nil {
 | |
| 		if errors.Cause(err) == define.ErrNoSuchImage {
 | |
| 			utils.Error(w, "No such image", http.StatusNotFound, err)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
 | |
| 		return
 | |
| 	}
 | |
| 	containerConfig, err := runtime.GetConfig()
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "GetConfig()"))
 | |
| 		return
 | |
| 	}
 | |
| 	cc, err := makeCreateConfig(r.Context(), containerConfig, input, newImage)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()"))
 | |
| 		return
 | |
| 	}
 | |
| 	cc.Name = query.Name
 | |
| 	utils.CreateContainer(r.Context(), w, runtime, &cc)
 | |
| }
 | |
| 
 | |
| func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
 | |
| 	var (
 | |
| 		err  error
 | |
| 		init bool
 | |
| 	)
 | |
| 	env := make(map[string]string)
 | |
| 	stopSignal := unix.SIGTERM
 | |
| 	if len(input.StopSignal) > 0 {
 | |
| 		stopSignal, err = signal.ParseSignal(input.StopSignal)
 | |
| 		if err != nil {
 | |
| 			return createconfig.CreateConfig{}, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	workDir, err := newImage.WorkingDir(ctx)
 | |
| 	if err != nil {
 | |
| 		return createconfig.CreateConfig{}, err
 | |
| 	}
 | |
| 	if workDir == "" {
 | |
| 		workDir = "/"
 | |
| 	}
 | |
| 	if len(input.WorkingDir) > 0 {
 | |
| 		workDir = input.WorkingDir
 | |
| 	}
 | |
| 
 | |
| 	// Only use image's Cmd when the user does not set the entrypoint
 | |
| 	if input.Entrypoint == nil && len(input.Cmd) == 0 {
 | |
| 		cmdSlice, err := newImage.Cmd(ctx)
 | |
| 		if err != nil {
 | |
| 			return createconfig.CreateConfig{}, err
 | |
| 		}
 | |
| 		input.Cmd = cmdSlice
 | |
| 	}
 | |
| 
 | |
| 	if input.Entrypoint == nil {
 | |
| 		entrypointSlice, err := newImage.Entrypoint(ctx)
 | |
| 		if err != nil {
 | |
| 			return createconfig.CreateConfig{}, err
 | |
| 		}
 | |
| 		input.Entrypoint = entrypointSlice
 | |
| 	}
 | |
| 
 | |
| 	stopTimeout := containerConfig.Engine.StopTimeout
 | |
| 	if input.StopTimeout != nil {
 | |
| 		stopTimeout = uint(*input.StopTimeout)
 | |
| 	}
 | |
| 	c := createconfig.CgroupConfig{
 | |
| 		Cgroups:      "", // podman
 | |
| 		Cgroupns:     "", // podman
 | |
| 		CgroupParent: "", // podman
 | |
| 		CgroupMode:   "", // podman
 | |
| 	}
 | |
| 	security := createconfig.SecurityConfig{
 | |
| 		CapAdd:             input.HostConfig.CapAdd,
 | |
| 		CapDrop:            input.HostConfig.CapDrop,
 | |
| 		LabelOpts:          nil,   // podman
 | |
| 		NoNewPrivs:         false, // podman
 | |
| 		ApparmorProfile:    "",    // podman
 | |
| 		SeccompProfilePath: "",
 | |
| 		SecurityOpts:       input.HostConfig.SecurityOpt,
 | |
| 		Privileged:         input.HostConfig.Privileged,
 | |
| 		ReadOnlyRootfs:     input.HostConfig.ReadonlyRootfs,
 | |
| 		ReadOnlyTmpfs:      false, // podman-only
 | |
| 		Sysctl:             input.HostConfig.Sysctls,
 | |
| 	}
 | |
| 
 | |
| 	var netmode namespaces.NetworkMode
 | |
| 	if rootless.IsRootless() {
 | |
| 		netmode = namespaces.NetworkMode(specgen.Slirp)
 | |
| 	}
 | |
| 
 | |
| 	network := createconfig.NetworkConfig{
 | |
| 		DNSOpt:       input.HostConfig.DNSOptions,
 | |
| 		DNSSearch:    input.HostConfig.DNSSearch,
 | |
| 		DNSServers:   input.HostConfig.DNS,
 | |
| 		ExposedPorts: input.ExposedPorts,
 | |
| 		HTTPProxy:    false, // podman
 | |
| 		IP6Address:   "",
 | |
| 		IPAddress:    "",
 | |
| 		LinkLocalIP:  nil, // docker-only
 | |
| 		MacAddress:   input.MacAddress,
 | |
| 		NetMode:      netmode,
 | |
| 		Network:      input.HostConfig.NetworkMode.NetworkName(),
 | |
| 		NetworkAlias: nil, // docker-only now
 | |
| 		PortBindings: input.HostConfig.PortBindings,
 | |
| 		Publish:      nil, // podmanseccompPath
 | |
| 		PublishAll:   input.HostConfig.PublishAllPorts,
 | |
| 	}
 | |
| 
 | |
| 	uts := createconfig.UtsConfig{
 | |
| 		UtsMode:  namespaces.UTSMode(input.HostConfig.UTSMode),
 | |
| 		NoHosts:  false, //podman
 | |
| 		HostAdd:  input.HostConfig.ExtraHosts,
 | |
| 		Hostname: input.Hostname,
 | |
| 	}
 | |
| 
 | |
| 	z := createconfig.UserConfig{
 | |
| 		GroupAdd:   input.HostConfig.GroupAdd,
 | |
| 		IDMappings: &storage.IDMappingOptions{}, // podman //TODO <--- fix this,
 | |
| 		UsernsMode: namespaces.UsernsMode(input.HostConfig.UsernsMode),
 | |
| 		User:       input.User,
 | |
| 	}
 | |
| 	pidConfig := createconfig.PidConfig{PidMode: namespaces.PidMode(input.HostConfig.PidMode)}
 | |
| 	// TODO: We should check that these binds are all listed in the `Volumes`
 | |
| 	// key since it doesn't make sense to define a `Binds` element for a
 | |
| 	// container path which isn't defined as a volume
 | |
| 	volumes := input.HostConfig.Binds
 | |
| 
 | |
| 	// Docker is more flexible about its input where podman throws
 | |
| 	// away incorrectly formatted variables so we cannot reuse the
 | |
| 	// parsing of the env input
 | |
| 	// [Foo Other=one Blank=]
 | |
| 	imgEnv, err := newImage.Env(ctx)
 | |
| 	if err != nil {
 | |
| 		return createconfig.CreateConfig{}, err
 | |
| 	}
 | |
| 	input.Env = append(imgEnv, input.Env...)
 | |
| 	for _, e := range input.Env {
 | |
| 		splitEnv := strings.Split(e, "=")
 | |
| 		switch len(splitEnv) {
 | |
| 		case 0:
 | |
| 			continue
 | |
| 		case 1:
 | |
| 			env[splitEnv[0]] = ""
 | |
| 		default:
 | |
| 			env[splitEnv[0]] = strings.Join(splitEnv[1:], "=")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// format the tmpfs mounts into a []string from map
 | |
| 	tmpfs := make([]string, 0, len(input.HostConfig.Tmpfs))
 | |
| 	for k, v := range input.HostConfig.Tmpfs {
 | |
| 		tmpfs = append(tmpfs, fmt.Sprintf("%s:%s", k, v))
 | |
| 	}
 | |
| 
 | |
| 	if input.HostConfig.Init != nil && *input.HostConfig.Init {
 | |
| 		init = true
 | |
| 	}
 | |
| 
 | |
| 	m := createconfig.CreateConfig{
 | |
| 		Annotations:   nil, // podman
 | |
| 		Args:          nil,
 | |
| 		Cgroup:        c,
 | |
| 		CidFile:       "",
 | |
| 		ConmonPidFile: "", // podman
 | |
| 		Command:       input.Cmd,
 | |
| 		UserCommand:   input.Cmd, // podman
 | |
| 		Detach:        false,     //
 | |
| 		// Devices:            input.HostConfig.Devices,
 | |
| 		Entrypoint:        input.Entrypoint,
 | |
| 		Env:               env,
 | |
| 		HealthCheck:       nil, //
 | |
| 		Init:              init,
 | |
| 		InitPath:          "", // tbd
 | |
| 		Image:             input.Image,
 | |
| 		ImageID:           newImage.ID(),
 | |
| 		BuiltinImgVolumes: nil, // podman
 | |
| 		ImageVolumeType:   "",  // podman
 | |
| 		Interactive:       input.OpenStdin,
 | |
| 		// IpcMode:           input.HostConfig.IpcMode,
 | |
| 		Labels:    input.Labels,
 | |
| 		LogDriver: input.HostConfig.LogConfig.Type, // is this correct
 | |
| 		// LogDriverOpt:       input.HostConfig.LogConfig.Config,
 | |
| 		Name:          input.Name,
 | |
| 		Network:       network,
 | |
| 		Pod:           "",    // podman
 | |
| 		PodmanPath:    "",    // podman
 | |
| 		Quiet:         false, // front-end only
 | |
| 		Resources:     createconfig.CreateResourceConfig{},
 | |
| 		RestartPolicy: input.HostConfig.RestartPolicy.Name,
 | |
| 		Rm:            input.HostConfig.AutoRemove,
 | |
| 		StopSignal:    stopSignal,
 | |
| 		StopTimeout:   stopTimeout,
 | |
| 		Systemd:       false, // podman
 | |
| 		Tmpfs:         tmpfs,
 | |
| 		User:          z,
 | |
| 		Uts:           uts,
 | |
| 		Tty:           input.Tty,
 | |
| 		Mounts:        nil, // we populate
 | |
| 		// MountsFlag:         input.HostConfig.Mounts,
 | |
| 		NamedVolumes: nil, // we populate
 | |
| 		Volumes:      volumes,
 | |
| 		VolumesFrom:  input.HostConfig.VolumesFrom,
 | |
| 		WorkDir:      workDir,
 | |
| 		Rootfs:       "", // podman
 | |
| 		Security:     security,
 | |
| 		Syslog:       false, // podman
 | |
| 
 | |
| 		Pid: pidConfig,
 | |
| 	}
 | |
| 
 | |
| 	fullCmd := append(input.Entrypoint, input.Cmd...)
 | |
| 	if len(fullCmd) > 0 {
 | |
| 		m.PodmanPath = fullCmd[0]
 | |
| 		if len(fullCmd) == 1 {
 | |
| 			m.Args = fullCmd
 | |
| 		} else {
 | |
| 			m.Args = fullCmd[1:]
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return m, nil
 | |
| }
 |