diff options
Diffstat (limited to 'pkg/api/handlers/compat')
-rw-r--r-- | pkg/api/handlers/compat/containers.go | 48 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_archive.go | 40 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_create.go | 474 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_stats.go | 12 | ||||
-rw-r--r-- | pkg/api/handlers/compat/events.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/compat/exec.go | 6 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 192 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_prune.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_remove.go | 5 | ||||
-rw-r--r-- | pkg/api/handlers/compat/info.go | 141 | ||||
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/secrets.go | 16 | ||||
-rw-r--r-- | pkg/api/handlers/compat/swagger.go | 67 | ||||
-rw-r--r-- | pkg/api/handlers/compat/version.go | 9 | ||||
-rw-r--r-- | pkg/api/handlers/compat/volumes.go | 8 |
16 files changed, 731 insertions, 301 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 1c339730e..616f0a138 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -254,7 +254,7 @@ func KillContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL { + if sig == 0 || sig == syscall.SIGKILL { opts := entities.WaitOptions{ Condition: []define.ContainerStatus{define.ContainerStateExited, define.ContainerStateStopped}, Interval: time.Millisecond * 250, @@ -341,8 +341,8 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error for idx, portMapping := range portMappings { ports[idx] = types.Port{ IP: portMapping.HostIP, - PrivatePort: uint16(portMapping.ContainerPort), - PublicPort: uint16(portMapping.HostPort), + PrivatePort: portMapping.ContainerPort, + PublicPort: portMapping.HostPort, Type: portMapping.Protocol, } } @@ -369,26 +369,28 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error return nil, err } - return &handlers.Container{Container: types.Container{ - ID: l.ID(), - Names: []string{fmt.Sprintf("/%s", l.Name())}, - Image: imageName, - ImageID: "sha256:" + imageID, - Command: strings.Join(l.Command(), " "), - Created: l.CreatedTime().Unix(), - Ports: ports, - SizeRw: sizeRW, - SizeRootFs: sizeRootFs, - Labels: l.Labels(), - State: stateStr, - Status: status, - HostConfig: struct { - NetworkMode string `json:",omitempty"` - }{ - "host"}, - NetworkSettings: &networkSettings, - Mounts: mounts, - }, + return &handlers.Container{ + Container: types.Container{ + ID: l.ID(), + Names: []string{fmt.Sprintf("/%s", l.Name())}, + Image: imageName, + ImageID: "sha256:" + imageID, + Command: strings.Join(l.Command(), " "), + Created: l.CreatedTime().Unix(), + Ports: ports, + SizeRw: sizeRW, + SizeRootFs: sizeRootFs, + Labels: l.Labels(), + State: stateStr, + Status: status, + HostConfig: struct { + NetworkMode string `json:",omitempty"` + }{ + "host", + }, + NetworkSettings: &networkSettings, + Mounts: mounts, + }, ContainerCreateConfig: types.ContainerCreateConfig{}, }, nil } diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 45b13818b..77fbbe38a 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "os" + "strings" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" @@ -94,11 +95,10 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { query := struct { - Path string `schema:"path"` - Chown bool `schema:"copyUIDGID"` - Rename string `schema:"rename"` - // TODO handle params below - NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"` + Path string `schema:"path"` + Chown bool `schema:"copyUIDGID"` + Rename string `schema:"rename"` + NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"` }{ Chown: utils.IsLibpodRequest(r), // backward compatibility } @@ -112,7 +112,7 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, var rename map[string]string if query.Rename != "" { if err := json.Unmarshal([]byte(query.Rename), &rename); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) + utils.Error(w, http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query field 'rename'")) return } } @@ -120,15 +120,25 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, containerName := utils.GetName(r) containerEngine := abi.ContainerEngine{Libpod: runtime} - copyOptions := entities.CopyOptions{Chown: query.Chown, Rename: rename} - copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, copyOptions) - if errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err) { - // 404 is returned for an absent container and path. The - // clients must deal with it accordingly. - utils.Error(w, http.StatusNotFound, errors.Wrap(err, "the container doesn't exists")) - return - } else if err != nil { - utils.Error(w, http.StatusInternalServerError, err) + copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, + entities.CopyOptions{ + Chown: query.Chown, + NoOverwriteDirNonDir: query.NoOverwriteDirNonDir, + Rename: rename, + }) + if err != nil { + switch { + case errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err): + // 404 is returned for an absent container and path. The + // clients must deal with it accordingly. + utils.Error(w, http.StatusNotFound, errors.Wrap(err, "the container doesn't exists")) + case strings.Contains(err.Error(), "copier: put: error creating file"): + // Not the best test but need to break this out for compatibility + // See vendor/github.com/containers/buildah/copier/copier.go:1585 + utils.Error(w, http.StatusBadRequest, err) + default: + utils.Error(w, http.StatusInternalServerError, err) + } return } diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index cd592a975..67ec52047 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -2,18 +2,29 @@ package compat import ( "encoding/json" + "fmt" + "net" "net/http" + "os" + "path/filepath" + "strconv" + "strings" - "github.com/containers/podman/v4/cmd/podman/common" + "github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/cgroups" + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/libpod" + "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/api/handlers" "github.com/containers/podman/v4/pkg/api/handlers/utils" api "github.com/containers/podman/v4/pkg/api/types" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/infra/abi" + "github.com/containers/podman/v4/pkg/rootless" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/specgenutil" "github.com/containers/storage" + "github.com/docker/docker/api/types/mount" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -70,7 +81,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { } // Take body structure and convert to cliopts - cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc) + cliOpts, args, err := cliOpts(body, rtc) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "make cli opts()")) return @@ -107,3 +118,462 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { } utils.WriteResponse(w, http.StatusCreated, createResponse) } + +func stringMaptoArray(m map[string]string) []string { + a := make([]string, 0, len(m)) + for k, v := range m { + a = append(a, fmt.Sprintf("%s=%s", k, v)) + } + return a +} + +// cliOpts converts a compat input struct to cliopts +func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.ContainerCreateOptions, []string, error) { + var ( + capAdd []string + cappDrop []string + entrypoint *string + init bool + specPorts []types.PortMapping + ) + + if cc.HostConfig.Init != nil { + init = *cc.HostConfig.Init + } + + // Iterate devices and convert to CLI expected string + devices := make([]string, 0, len(cc.HostConfig.Devices)) + for _, dev := range cc.HostConfig.Devices { + devices = append(devices, fmt.Sprintf("%s:%s:%s", dev.PathOnHost, dev.PathInContainer, dev.CgroupPermissions)) + } + + // iterate blkreaddevicebps + readBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadBps)) + for _, dev := range cc.HostConfig.BlkioDeviceReadBps { + readBps = append(readBps, dev.String()) + } + + // iterate blkreaddeviceiops + readIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadIOps)) + for _, dev := range cc.HostConfig.BlkioDeviceReadIOps { + readIops = append(readIops, dev.String()) + } + + // iterate blkwritedevicebps + writeBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteBps)) + for _, dev := range cc.HostConfig.BlkioDeviceWriteBps { + writeBps = append(writeBps, dev.String()) + } + + // iterate blkwritedeviceiops + writeIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteIOps)) + for _, dev := range cc.HostConfig.BlkioDeviceWriteIOps { + writeIops = append(writeIops, dev.String()) + } + + // entrypoint + // can be a string or slice. if it is a slice, we need to + // marshall it to json; otherwise it should just be the string + // value + if len(cc.Config.Entrypoint) > 0 { + entrypoint = &cc.Config.Entrypoint[0] + if len(cc.Config.Entrypoint) > 1 { + b, err := json.Marshal(cc.Config.Entrypoint) + if err != nil { + return nil, nil, err + } + jsonString := string(b) + entrypoint = &jsonString + } + } + + // expose ports + expose := make([]string, 0, len(cc.Config.ExposedPorts)) + for p := range cc.Config.ExposedPorts { + expose = append(expose, fmt.Sprintf("%s/%s", p.Port(), p.Proto())) + } + + // mounts type=tmpfs/bind,source=...,target=...=,opt=val + volSources := make(map[string]bool) + volDestinations := make(map[string]bool) + mounts := make([]string, 0, len(cc.HostConfig.Mounts)) + var builder strings.Builder + for _, m := range cc.HostConfig.Mounts { + addField(&builder, "type", string(m.Type)) + addField(&builder, "source", m.Source) + addField(&builder, "target", m.Target) + + // Store source/dest so we don't add duplicates if a volume is + // also mentioned in cc.Volumes. + // Which Docker Compose v2.0 does, for unclear reasons... + volSources[m.Source] = true + volDestinations[m.Target] = true + + if m.ReadOnly { + addField(&builder, "ro", "true") + } + addField(&builder, "consistency", string(m.Consistency)) + // Map any specialized mount options that intersect between *Options and cli options + switch m.Type { + case mount.TypeBind: + if m.BindOptions != nil { + addField(&builder, "bind-propagation", string(m.BindOptions.Propagation)) + addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive)) + } + case mount.TypeTmpfs: + if m.TmpfsOptions != nil { + addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10)) + addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 8)) + } + case mount.TypeVolume: + // All current VolumeOpts are handled above + // See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts() + } + mounts = append(mounts, builder.String()) + builder.Reset() + } + + // dns + dns := make([]net.IP, 0, len(cc.HostConfig.DNS)) + for _, d := range cc.HostConfig.DNS { + dns = append(dns, net.ParseIP(d)) + } + + // publish + for port, pbs := range cc.HostConfig.PortBindings { + for _, pb := range pbs { + var hostport int + var err error + if pb.HostPort != "" { + hostport, err = strconv.Atoi(pb.HostPort) + } + if err != nil { + return nil, nil, err + } + tmpPort := types.PortMapping{ + HostIP: pb.HostIP, + ContainerPort: uint16(port.Int()), + HostPort: uint16(hostport), + Range: 0, + Protocol: port.Proto(), + } + specPorts = append(specPorts, tmpPort) + } + } + + // special case for NetworkMode, the podman default is slirp4netns for + // rootless but for better docker compat we want bridge. + netmode := string(cc.HostConfig.NetworkMode) + if netmode == "" || netmode == "default" { + netmode = "bridge" + } + nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{netmode}) + if err != nil { + return nil, nil, err + } + + // network + // Note: we cannot emulate compat exactly here. we only allow specifics of networks to be + // defined when there is only one network. + netInfo := entities.NetOptions{ + AddHosts: cc.HostConfig.ExtraHosts, + DNSOptions: cc.HostConfig.DNSOptions, + DNSSearch: cc.HostConfig.DNSSearch, + DNSServers: dns, + Network: nsmode, + PublishPorts: specPorts, + NetworkOptions: netOpts, + NoHosts: rtc.Containers.NoHosts, + } + + // network names + switch { + case len(cc.NetworkingConfig.EndpointsConfig) > 0: + endpointsConfig := cc.NetworkingConfig.EndpointsConfig + networks := make(map[string]types.PerNetworkOptions, len(endpointsConfig)) + for netName, endpoint := range endpointsConfig { + netOpts := types.PerNetworkOptions{} + if endpoint != nil { + netOpts.Aliases = endpoint.Aliases + + // if IP address is provided + if len(endpoint.IPAddress) > 0 { + staticIP := net.ParseIP(endpoint.IPAddress) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ip address %q", endpoint.IPAddress) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + + if endpoint.IPAMConfig != nil { + // if IPAMConfig.IPv4Address is provided + if len(endpoint.IPAMConfig.IPv4Address) > 0 { + staticIP := net.ParseIP(endpoint.IPAMConfig.IPv4Address) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ipv4 address %q", endpoint.IPAMConfig.IPv4Address) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + // if IPAMConfig.IPv6Address is provided + if len(endpoint.IPAMConfig.IPv6Address) > 0 { + staticIP := net.ParseIP(endpoint.IPAMConfig.IPv6Address) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ipv6 address %q", endpoint.IPAMConfig.IPv6Address) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + } + // If MAC address is provided + if len(endpoint.MacAddress) > 0 { + staticMac, err := net.ParseMAC(endpoint.MacAddress) + if err != nil { + return nil, nil, errors.Errorf("failed to parse the mac address %q", endpoint.MacAddress) + } + netOpts.StaticMAC = types.HardwareAddr(staticMac) + } + } + + networks[netName] = netOpts + } + + netInfo.Networks = networks + case len(cc.HostConfig.NetworkMode) > 0: + netInfo.Networks = networks + } + + parsedTmp := make([]string, 0, len(cc.HostConfig.Tmpfs)) + for path, options := range cc.HostConfig.Tmpfs { + finalString := path + if options != "" { + finalString += ":" + options + } + parsedTmp = append(parsedTmp, finalString) + } + + // Note: several options here are marked as "don't need". this is based + // on speculation by Matt and I. We think that these come into play later + // like with start. We believe this is just a difference in podman/compat + cliOpts := entities.ContainerCreateOptions{ + // Attach: nil, // don't need? + Authfile: "", + CapAdd: append(capAdd, cc.HostConfig.CapAdd...), + CapDrop: append(cappDrop, cc.HostConfig.CapDrop...), + CgroupParent: cc.HostConfig.CgroupParent, + CIDFile: cc.HostConfig.ContainerIDFile, + CPUPeriod: uint64(cc.HostConfig.CPUPeriod), + CPUQuota: cc.HostConfig.CPUQuota, + CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod), + CPURTRuntime: cc.HostConfig.CPURealtimeRuntime, + CPUShares: uint64(cc.HostConfig.CPUShares), + // CPUS: 0, // don't need? + CPUSetCPUs: cc.HostConfig.CpusetCpus, + CPUSetMems: cc.HostConfig.CpusetMems, + // Detach: false, // don't need + // DetachKeys: "", // don't need + Devices: devices, + DeviceCgroupRule: nil, + DeviceReadBPs: readBps, + DeviceReadIOPs: readIops, + DeviceWriteBPs: writeBps, + DeviceWriteIOPs: writeIops, + Entrypoint: entrypoint, + Env: cc.Config.Env, + Expose: expose, + GroupAdd: cc.HostConfig.GroupAdd, + Hostname: cc.Config.Hostname, + ImageVolume: "bind", + Init: init, + Interactive: cc.Config.OpenStdin, + IPC: string(cc.HostConfig.IpcMode), + Label: stringMaptoArray(cc.Config.Labels), + LogDriver: cc.HostConfig.LogConfig.Type, + LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config), + Name: cc.Name, + OOMScoreAdj: &cc.HostConfig.OomScoreAdj, + Arch: "", + OS: "", + Variant: "", + PID: string(cc.HostConfig.PidMode), + PIDsLimit: cc.HostConfig.PidsLimit, + Privileged: cc.HostConfig.Privileged, + PublishAll: cc.HostConfig.PublishAllPorts, + Quiet: false, + ReadOnly: cc.HostConfig.ReadonlyRootfs, + ReadOnlyTmpFS: true, // podman default + Rm: cc.HostConfig.AutoRemove, + SecurityOpt: cc.HostConfig.SecurityOpt, + StopSignal: cc.Config.StopSignal, + StorageOpts: stringMaptoArray(cc.HostConfig.StorageOpt), + Sysctl: stringMaptoArray(cc.HostConfig.Sysctls), + Systemd: "true", // podman default + TmpFS: parsedTmp, + TTY: cc.Config.Tty, + UnsetEnv: cc.UnsetEnv, + UnsetEnvAll: cc.UnsetEnvAll, + User: cc.Config.User, + UserNS: string(cc.HostConfig.UsernsMode), + UTS: string(cc.HostConfig.UTSMode), + Mount: mounts, + VolumesFrom: cc.HostConfig.VolumesFrom, + Workdir: cc.Config.WorkingDir, + Net: &netInfo, + HealthInterval: define.DefaultHealthCheckInterval, + HealthRetries: define.DefaultHealthCheckRetries, + HealthTimeout: define.DefaultHealthCheckTimeout, + HealthStartPeriod: define.DefaultHealthCheckStartPeriod, + } + if !rootless.IsRootless() { + var ulimits []string + if len(cc.HostConfig.Ulimits) > 0 { + for _, ul := range cc.HostConfig.Ulimits { + ulimits = append(ulimits, ul.String()) + } + cliOpts.Ulimit = ulimits + } + } + if cc.HostConfig.Resources.NanoCPUs > 0 { + if cliOpts.CPUPeriod != 0 || cliOpts.CPUQuota != 0 { + return nil, nil, errors.Errorf("NanoCpus conflicts with CpuPeriod and CpuQuota") + } + cliOpts.CPUPeriod = 100000 + cliOpts.CPUQuota = cc.HostConfig.Resources.NanoCPUs / 10000 + } + + // volumes + for _, vol := range cc.HostConfig.Binds { + cliOpts.Volume = append(cliOpts.Volume, vol) + // Extract the destination so we don't add duplicate mounts in + // the volumes phase. + splitVol := specgen.SplitVolumeString(vol) + switch len(splitVol) { + case 1: + volDestinations[vol] = true + default: + volSources[splitVol[0]] = true + volDestinations[splitVol[1]] = true + } + } + // Anonymous volumes are added differently from other volumes, in their + // own special field, for reasons known only to Docker. Still use the + // format of `-v` so we can just append them in there. + // Unfortunately, these may be duplicates of existing mounts in Binds. + // So... We need to catch that. + // This also handles volumes duplicated between cc.HostConfig.Mounts and + // cc.Volumes, as seen in compose v2.0. + for vol := range cc.Volumes { + if _, ok := volDestinations[filepath.Clean(vol)]; ok { + continue + } + cliOpts.Volume = append(cliOpts.Volume, vol) + } + // Make mount points for compat volumes + for vol := range volSources { + // This might be a named volume. + // Assume it is if it's not an absolute path. + if !filepath.IsAbs(vol) { + continue + } + // If volume already exists, there is nothing to do + if _, err := os.Stat(vol); err == nil { + continue + } + if err := os.MkdirAll(vol, 0o755); err != nil { + if !os.IsExist(err) { + return nil, nil, errors.Wrapf(err, "error making volume mountpoint for volume %s", vol) + } + } + } + if len(cc.HostConfig.BlkioWeightDevice) > 0 { + devices := make([]string, 0, len(cc.HostConfig.BlkioWeightDevice)) + for _, d := range cc.HostConfig.BlkioWeightDevice { + devices = append(devices, d.String()) + } + cliOpts.BlkIOWeightDevice = devices + } + if cc.HostConfig.BlkioWeight > 0 { + cliOpts.BlkIOWeight = strconv.Itoa(int(cc.HostConfig.BlkioWeight)) + } + + if cc.HostConfig.Memory > 0 { + cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory)) + } + + if cc.HostConfig.MemoryReservation > 0 { + cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation)) + } + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return nil, nil, err + } + if cc.HostConfig.MemorySwap > 0 && (!rootless.IsRootless() || (rootless.IsRootless() && cgroupsv2)) { + cliOpts.MemorySwap = strconv.Itoa(int(cc.HostConfig.MemorySwap)) + } + + if cc.Config.StopTimeout != nil { + cliOpts.StopTimeout = uint(*cc.Config.StopTimeout) + } + + if cc.HostConfig.ShmSize > 0 { + cliOpts.ShmSize = strconv.Itoa(int(cc.HostConfig.ShmSize)) + } + + if len(cc.HostConfig.RestartPolicy.Name) > 0 { + policy := cc.HostConfig.RestartPolicy.Name + // only add restart count on failure + if cc.HostConfig.RestartPolicy.IsOnFailure() { + policy += fmt.Sprintf(":%d", cc.HostConfig.RestartPolicy.MaximumRetryCount) + } + cliOpts.Restart = policy + } + + if cc.HostConfig.MemorySwappiness != nil && (!rootless.IsRootless() || rootless.IsRootless() && cgroupsv2 && rtc.Engine.CgroupManager == "systemd") { + cliOpts.MemorySwappiness = *cc.HostConfig.MemorySwappiness + } else { + cliOpts.MemorySwappiness = -1 + } + if cc.HostConfig.OomKillDisable != nil { + cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable + } + if cc.Config.Healthcheck != nil { + finCmd := "" + for _, str := range cc.Config.Healthcheck.Test { + finCmd = finCmd + str + " " + } + if len(finCmd) > 1 { + finCmd = finCmd[:len(finCmd)-1] + } + cliOpts.HealthCmd = finCmd + if cc.Config.Healthcheck.Interval > 0 { + cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String() + } + if cc.Config.Healthcheck.Retries > 0 { + cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries) + } + if cc.Config.Healthcheck.StartPeriod > 0 { + cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String() + } + if cc.Config.Healthcheck.Timeout > 0 { + cliOpts.HealthTimeout = cc.Config.Healthcheck.Timeout.String() + } + } + + // specgen assumes the image name is arg[0] + cmd := []string{cc.Config.Image} + cmd = append(cmd, cc.Config.Cmd...) + return &cliOpts, cmd, nil +} + +// addField is a helper function to populate mount options +func addField(b *strings.Builder, name, value string) { + if value == "" { + return + } + + if b.Len() > 0 { + b.WriteRune(',') + } + b.WriteString(name) + b.WriteRune('=') + b.WriteString(value) +} diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go index 77b16b03e..6855e369b 100644 --- a/pkg/api/handlers/compat/containers_stats.go +++ b/pkg/api/handlers/compat/containers_stats.go @@ -44,18 +44,6 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { return } - // If the container isn't running, then let's not bother and return - // immediately. - state, err := ctnr.State() - if err != nil { - utils.InternalServerError(w, err) - return - } - if state != define.ContainerStateRunning { - utils.Error(w, http.StatusConflict, define.ErrCtrStateInvalid) - return - } - stats, err := ctnr.GetContainerStats(nil) if err != nil { utils.InternalServerError(w, errors.Wrapf(err, "failed to obtain Container %s stats", name)) diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 03b3d54bc..6bcb7bd32 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -63,7 +63,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { errorChannel <- runtime.Events(r.Context(), readOpts) }() - var flush = func() {} + flush := func() {} if flusher, ok := w.(http.Flusher); ok { flush = flusher.Flush } diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go index def16d1b5..a8b45c685 100644 --- a/pkg/api/handlers/compat/exec.go +++ b/pkg/api/handlers/compat/exec.go @@ -11,6 +11,7 @@ import ( "github.com/containers/podman/v4/pkg/api/handlers/utils" "github.com/containers/podman/v4/pkg/api/server/idle" api "github.com/containers/podman/v4/pkg/api/types" + "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/specgenutil" "github.com/gorilla/mux" "github.com/pkg/errors" @@ -93,10 +94,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) { return } - resp := new(handlers.ExecCreateResponse) - resp.ID = sessID - - utils.WriteResponse(w, http.StatusCreated, resp) + utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: sessID}) } // ExecInspectHandler inspects a given exec session. diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index a690cdd40..76a28fadf 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -165,7 +165,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure")) return } - utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: commitImage.ID()}) // nolint + utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: commitImage.ID()}) // nolint } func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) { @@ -460,8 +460,6 @@ func GetImages(w http.ResponseWriter, r *http.Request) { } func LoadImages(w http.ResponseWriter, r *http.Request) { - // TODO this is basically wrong - // TODO ... improve these ^ messages to something useful decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 318688222..7e599f4d3 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -70,67 +70,70 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { }() query := struct { - AddHosts string `schema:"extrahosts"` - AdditionalCapabilities string `schema:"addcaps"` - AllPlatforms bool `schema:"allplatforms"` - Annotations string `schema:"annotations"` - AppArmor string `schema:"apparmor"` - BuildArgs string `schema:"buildargs"` - CacheFrom string `schema:"cachefrom"` - CgroupParent string `schema:"cgroupparent"` // nolint - Compression uint64 `schema:"compression"` - ConfigureNetwork string `schema:"networkmode"` - CpuPeriod uint64 `schema:"cpuperiod"` // nolint - CpuQuota int64 `schema:"cpuquota"` // nolint - CpuSetCpus string `schema:"cpusetcpus"` // nolint - CpuSetMems string `schema:"cpusetmems"` // nolint - CpuShares uint64 `schema:"cpushares"` // nolint - DNSOptions string `schema:"dnsoptions"` - DNSSearch string `schema:"dnssearch"` - DNSServers string `schema:"dnsservers"` - Devices string `schema:"devices"` - Dockerfile string `schema:"dockerfile"` - DropCapabilities string `schema:"dropcaps"` - Envs []string `schema:"setenv"` - Excludes string `schema:"excludes"` - ForceRm bool `schema:"forcerm"` - From string `schema:"from"` - HTTPProxy bool `schema:"httpproxy"` - IdentityLabel bool `schema:"identitylabel"` - Ignore bool `schema:"ignore"` - Isolation string `schema:"isolation"` - Jobs int `schema:"jobs"` // nolint - LabelOpts string `schema:"labelopts"` - Labels string `schema:"labels"` - Layers bool `schema:"layers"` - LogRusage bool `schema:"rusage"` - Manifest string `schema:"manifest"` - MemSwap int64 `schema:"memswap"` - Memory int64 `schema:"memory"` - NamespaceOptions string `schema:"nsoptions"` - NoCache bool `schema:"nocache"` - OSFeatures []string `schema:"osfeature"` - OSVersion string `schema:"osversion"` - OutputFormat string `schema:"outputformat"` - Platform []string `schema:"platform"` - Pull bool `schema:"pull"` - PullPolicy string `schema:"pullpolicy"` - Quiet bool `schema:"q"` - Registry string `schema:"registry"` - Rm bool `schema:"rm"` - RusageLogFile string `schema:"rusagelogfile"` - Remote string `schema:"remote"` - Seccomp string `schema:"seccomp"` - Secrets string `schema:"secrets"` - SecurityOpt string `schema:"securityopt"` - ShmSize int `schema:"shmsize"` - Squash bool `schema:"squash"` - TLSVerify bool `schema:"tlsVerify"` - Tags []string `schema:"t"` - Target string `schema:"target"` - Timestamp int64 `schema:"timestamp"` - Ulimits string `schema:"ulimits"` - UnsetEnvs []string `schema:"unsetenv"` + AddHosts string `schema:"extrahosts"` + AdditionalCapabilities string `schema:"addcaps"` + AdditionalBuildContexts string `schema:"additionalbuildcontexts"` + AllPlatforms bool `schema:"allplatforms"` + Annotations string `schema:"annotations"` + AppArmor string `schema:"apparmor"` + BuildArgs string `schema:"buildargs"` + CacheFrom string `schema:"cachefrom"` + CgroupParent string `schema:"cgroupparent"` // nolint + Compression uint64 `schema:"compression"` + ConfigureNetwork string `schema:"networkmode"` + CPPFlags string `schema:"cppflags"` + CpuPeriod uint64 `schema:"cpuperiod"` // nolint + CpuQuota int64 `schema:"cpuquota"` // nolint + CpuSetCpus string `schema:"cpusetcpus"` // nolint + CpuSetMems string `schema:"cpusetmems"` // nolint + CpuShares uint64 `schema:"cpushares"` // nolint + DNSOptions string `schema:"dnsoptions"` + DNSSearch string `schema:"dnssearch"` + DNSServers string `schema:"dnsservers"` + Devices string `schema:"devices"` + Dockerfile string `schema:"dockerfile"` + DropCapabilities string `schema:"dropcaps"` + Envs []string `schema:"setenv"` + Excludes string `schema:"excludes"` + ForceRm bool `schema:"forcerm"` + From string `schema:"from"` + HTTPProxy bool `schema:"httpproxy"` + IdentityLabel bool `schema:"identitylabel"` + Ignore bool `schema:"ignore"` + Isolation string `schema:"isolation"` + Jobs int `schema:"jobs"` // nolint + LabelOpts string `schema:"labelopts"` + Labels string `schema:"labels"` + Layers bool `schema:"layers"` + LogRusage bool `schema:"rusage"` + Manifest string `schema:"manifest"` + MemSwap int64 `schema:"memswap"` + Memory int64 `schema:"memory"` + NamespaceOptions string `schema:"nsoptions"` + NoCache bool `schema:"nocache"` + OmitHistory bool `schema:"omithistory"` + OSFeatures []string `schema:"osfeature"` + OSVersion string `schema:"osversion"` + OutputFormat string `schema:"outputformat"` + Platform []string `schema:"platform"` + Pull bool `schema:"pull"` + PullPolicy string `schema:"pullpolicy"` + Quiet bool `schema:"q"` + Registry string `schema:"registry"` + Rm bool `schema:"rm"` + RusageLogFile string `schema:"rusagelogfile"` + Remote string `schema:"remote"` + Seccomp string `schema:"seccomp"` + Secrets string `schema:"secrets"` + SecurityOpt string `schema:"securityopt"` + ShmSize int `schema:"shmsize"` + Squash bool `schema:"squash"` + TLSVerify bool `schema:"tlsVerify"` + Tags []string `schema:"t"` + Target string `schema:"target"` + Timestamp int64 `schema:"timestamp"` + Ulimits string `schema:"ulimits"` + UnsetEnvs []string `schema:"unsetenv"` }{ Dockerfile: "Dockerfile", IdentityLabel: true, @@ -170,7 +173,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { // convert addcaps formats containerFiles := []string{} - // Tells if query paramemter `dockerfile` is set or not. + // Tells if query parameter `dockerfile` is set or not. dockerFileSet := false if utils.IsLibpodRequest(r) && query.Remote != "" { // The context directory could be a URL. Try to handle that. @@ -374,6 +377,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { additionalTags = append(additionalTags, possiblyNormalizedTag) } + var additionalBuildContexts = map[string]*buildahDefine.AdditionalBuildContext{} + if _, found := r.URL.Query()["additionalbuildcontexts"]; found { + if err := json.Unmarshal([]byte(query.AdditionalBuildContexts), &additionalBuildContexts); err != nil { + utils.BadRequest(w, "additionalbuildcontexts", query.AdditionalBuildContexts, err) + return + } + } + var buildArgs = map[string]string{} if _, found := r.URL.Query()["buildargs"]; found { if err := json.Unmarshal([]byte(query.BuildArgs), &buildArgs); err != nil { @@ -399,6 +410,15 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } } + // convert cppflags formats + var cppflags = []string{} + if _, found := r.URL.Query()["cppflags"]; found { + if err := json.Unmarshal([]byte(query.CPPFlags), &cppflags); err != nil { + utils.BadRequest(w, "cppflags", query.CPPFlags, err) + return + } + } + // convert nsoptions formats nsoptions := buildah.NamespaceOptions{} if _, found := r.URL.Query()["nsoptions"]; found { @@ -552,11 +572,13 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) buildOptions := buildahDefine.BuildOptions{ - AddCapabilities: addCaps, - AdditionalTags: additionalTags, - Annotations: annotations, - Args: buildArgs, - AllPlatforms: query.AllPlatforms, + AddCapabilities: addCaps, + AdditionalBuildContexts: additionalBuildContexts, + AdditionalTags: additionalTags, + Annotations: annotations, + CPPFlags: cppflags, + Args: buildArgs, + AllPlatforms: query.AllPlatforms, CommonBuildOpts: &buildah.CommonBuildOptions{ AddHost: addhosts, ApparmorProfile: apparmor, @@ -574,6 +596,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { LabelOpts: labelOpts, Memory: query.Memory, MemorySwap: query.MemSwap, + OmitHistory: query.OmitHistory, SeccompProfilePath: seccomp, ShmSize: strconv.Itoa(query.ShmSize), Ulimit: ulimits, @@ -605,7 +628,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Output: output, OutputFormat: format, PullPolicy: pullPolicy, - PullPushRetryDelay: time.Duration(2 * time.Second), + PullPushRetryDelay: 2 * time.Second, Quiet: query.Quiet, Registry: registry, RemoveIntermediateCtrs: query.Rm, @@ -674,15 +697,17 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { enc := json.NewEncoder(body) enc.SetEscapeHTML(true) + var stepErrors []string for { - m := struct { + type BuildResponse struct { Stream string `json:"stream,omitempty"` Error *jsonmessage.JSONError `json:"errorDetail,omitempty"` // NOTE: `error` is being deprecated check https://github.com/moby/moby/blob/master/pkg/jsonmessage/jsonmessage.go#L148 ErrorMessage string `json:"error,omitempty"` // deprecate this slowly Aux json.RawMessage `json:"aux,omitempty"` - }{} + } + m := BuildResponse{} select { case e := <-stdout.Chan(): @@ -698,12 +723,27 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } flush() case e := <-auxout.Chan(): - m.Stream = string(e) - if err := enc.Encode(m); err != nil { - stderr.Write([]byte(err.Error())) + if !query.Quiet { + m.Stream = string(e) + if err := enc.Encode(m); err != nil { + stderr.Write([]byte(err.Error())) + } + flush() + } else { + stepErrors = append(stepErrors, string(e)) } - flush() case e := <-stderr.Chan(): + // Docker-API Compat parity : Build failed so + // output all step errors irrespective of quiet + // flag. + for _, stepError := range stepErrors { + t := BuildResponse{} + t.Stream = stepError + if err := enc.Encode(t); err != nil { + stderr.Write([]byte(err.Error())) + } + flush() + } m.ErrorMessage = string(e) m.Error = &jsonmessage.JSONError{ Message: m.ErrorMessage, @@ -776,7 +816,7 @@ func extractTarFile(r *http.Request) (string, error) { } path := filepath.Join(anchorDir, "tarBall") - tarBall, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + tarBall, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return "", err } @@ -790,7 +830,7 @@ func extractTarFile(r *http.Request) (string, error) { } buildDir := filepath.Join(anchorDir, "build") - err = os.Mkdir(buildDir, 0700) + err = os.Mkdir(buildDir, 0o700) if err != nil { return "", err } diff --git a/pkg/api/handlers/compat/images_prune.go b/pkg/api/handlers/compat/images_prune.go index 46524fcff..02cadbbbe 100644 --- a/pkg/api/handlers/compat/images_prune.go +++ b/pkg/api/handlers/compat/images_prune.go @@ -17,9 +17,7 @@ import ( ) func PruneImages(w http.ResponseWriter, r *http.Request) { - var ( - filters []string - ) + var filters []string runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go index f45b38c66..35bcb36aa 100644 --- a/pkg/api/handlers/compat/images_remove.go +++ b/pkg/api/handlers/compat/images_remove.go @@ -52,7 +52,10 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) { utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) return } - + if errors.Cause(err) == storage.ErrImageUsedByContainer { + utils.Error(w, http.StatusConflict, errors.Wrapf(err, "image %s is in use", name)) + return + } utils.Error(w, http.StatusInternalServerError, err) return } diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go index 6286fdaee..85547570a 100644 --- a/pkg/api/handlers/compat/info.go +++ b/pkg/api/handlers/compat/info.go @@ -53,75 +53,76 @@ func GetInfo(w http.ResponseWriter, r *http.Request) { // FIXME: Need to expose if runtime supports Checkpointing // liveRestoreEnabled := criu.CheckForCriu() && configInfo.RuntimeSupportsCheckpoint() - info := &handlers.Info{Info: docker.Info{ - Architecture: goRuntime.GOARCH, - BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, - BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, - CPUCfsPeriod: sysInfo.CPUCfsPeriod, - CPUCfsQuota: sysInfo.CPUCfsQuota, - CPUSet: sysInfo.Cpuset, - CPUShares: sysInfo.CPUShares, - CgroupDriver: configInfo.Engine.CgroupManager, - ClusterAdvertise: "", - ClusterStore: "", - ContainerdCommit: docker.Commit{}, - Containers: infoData.Store.ContainerStore.Number, - ContainersPaused: stateInfo[define.ContainerStatePaused], - ContainersRunning: stateInfo[define.ContainerStateRunning], - ContainersStopped: stateInfo[define.ContainerStateStopped] + stateInfo[define.ContainerStateExited], - Debug: log.IsLevelEnabled(log.DebugLevel), - DefaultRuntime: configInfo.Engine.OCIRuntime, - DockerRootDir: infoData.Store.GraphRoot, - Driver: infoData.Store.GraphDriverName, - DriverStatus: getGraphStatus(infoData.Store.GraphStatus), - ExperimentalBuild: true, - GenericResources: nil, - HTTPProxy: getEnv("http_proxy"), - HTTPSProxy: getEnv("https_proxy"), - ID: uuid.New().String(), - IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, - Images: infoData.Store.ImageStore.Number, - IndexServerAddress: "", - InitBinary: "", - InitCommit: docker.Commit{}, - Isolation: "", - KernelMemoryTCP: false, - KernelVersion: infoData.Host.Kernel, - Labels: nil, - LiveRestoreEnabled: false, - LoggingDriver: "", - MemTotal: infoData.Host.MemTotal, - MemoryLimit: sysInfo.MemoryLimit, - NCPU: goRuntime.NumCPU(), - NEventsListener: 0, - NFd: getFdCount(), - NGoroutines: goRuntime.NumGoroutine(), - Name: infoData.Host.Hostname, - NoProxy: getEnv("no_proxy"), - OSType: goRuntime.GOOS, - OSVersion: infoData.Host.Distribution.Version, - OomKillDisable: sysInfo.OomKillDisable, - OperatingSystem: infoData.Host.Distribution.Distribution, - PidsLimit: sysInfo.PidsLimit, - Plugins: docker.PluginsInfo{ - Volume: infoData.Plugins.Volume, - Network: infoData.Plugins.Network, - Log: infoData.Plugins.Log, + info := &handlers.Info{ + Info: docker.Info{ + Architecture: goRuntime.GOARCH, + BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, + BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, + CPUCfsPeriod: sysInfo.CPUCfsPeriod, + CPUCfsQuota: sysInfo.CPUCfsQuota, + CPUSet: sysInfo.Cpuset, + CPUShares: sysInfo.CPUShares, + CgroupDriver: configInfo.Engine.CgroupManager, + ClusterAdvertise: "", + ClusterStore: "", + ContainerdCommit: docker.Commit{}, + Containers: infoData.Store.ContainerStore.Number, + ContainersPaused: stateInfo[define.ContainerStatePaused], + ContainersRunning: stateInfo[define.ContainerStateRunning], + ContainersStopped: stateInfo[define.ContainerStateStopped] + stateInfo[define.ContainerStateExited], + Debug: log.IsLevelEnabled(log.DebugLevel), + DefaultRuntime: configInfo.Engine.OCIRuntime, + DockerRootDir: infoData.Store.GraphRoot, + Driver: infoData.Store.GraphDriverName, + DriverStatus: getGraphStatus(infoData.Store.GraphStatus), + ExperimentalBuild: true, + GenericResources: nil, + HTTPProxy: getEnv("http_proxy"), + HTTPSProxy: getEnv("https_proxy"), + ID: uuid.New().String(), + IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, + Images: infoData.Store.ImageStore.Number, + IndexServerAddress: "", + InitBinary: "", + InitCommit: docker.Commit{}, + Isolation: "", + KernelMemoryTCP: false, + KernelVersion: infoData.Host.Kernel, + Labels: nil, + LiveRestoreEnabled: false, + LoggingDriver: "", + MemTotal: infoData.Host.MemTotal, + MemoryLimit: sysInfo.MemoryLimit, + NCPU: goRuntime.NumCPU(), + NEventsListener: 0, + NFd: getFdCount(), + NGoroutines: goRuntime.NumGoroutine(), + Name: infoData.Host.Hostname, + NoProxy: getEnv("no_proxy"), + OSType: goRuntime.GOOS, + OSVersion: infoData.Host.Distribution.Version, + OomKillDisable: sysInfo.OomKillDisable, + OperatingSystem: infoData.Host.Distribution.Distribution, + PidsLimit: sysInfo.PidsLimit, + Plugins: docker.PluginsInfo{ + Volume: infoData.Plugins.Volume, + Network: infoData.Plugins.Network, + Log: infoData.Plugins.Log, + }, + ProductLicense: "Apache-2.0", + RegistryConfig: getServiceConfig(runtime), + RuncCommit: docker.Commit{}, + Runtimes: getRuntimes(configInfo), + SecurityOptions: getSecOpts(sysInfo), + ServerVersion: versionInfo.Version, + SwapLimit: sysInfo.SwapLimit, + Swarm: swarm.Info{ + LocalNodeState: swarm.LocalNodeStateInactive, + }, + SystemStatus: nil, + SystemTime: time.Now().Format(time.RFC3339Nano), + Warnings: []string{}, }, - ProductLicense: "Apache-2.0", - RegistryConfig: getServiceConfig(runtime), - RuncCommit: docker.Commit{}, - Runtimes: getRuntimes(configInfo), - SecurityOptions: getSecOpts(sysInfo), - ServerVersion: versionInfo.Version, - SwapLimit: sysInfo.SwapLimit, - Swarm: swarm.Info{ - LocalNodeState: swarm.LocalNodeStateInactive, - }, - SystemStatus: nil, - SystemTime: time.Now().Format(time.RFC3339Nano), - Warnings: []string{}, - }, BuildahVersion: infoData.Host.BuildahVersion, CPURealtimePeriod: sysInfo.CPURealtimePeriod, CPURealtimeRuntime: sysInfo.CPURealtimeRuntime, @@ -186,7 +187,7 @@ func getSecOpts(sysInfo *sysinfo.SysInfo) []string { } func getRuntimes(configInfo *config.Config) map[string]docker.Runtime { - var runtimes = map[string]docker.Runtime{} + runtimes := map[string]docker.Runtime{} for name, paths := range configInfo.Engine.OCIRuntimes { runtimes[name] = docker.Runtime{ Path: paths[0], @@ -206,7 +207,7 @@ func getFdCount() (count int) { // Just ignoring Container errors here... func getContainersState(r *libpod.Runtime) map[define.ContainerStatus]int { - var states = map[define.ContainerStatus]int{} + states := map[define.ContainerStatus]int{} ctnrs, err := r.GetAllContainers() if err == nil { for _, ctnr := range ctnrs { diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 89d914e0a..6fdd5c6a7 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -298,9 +298,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) { func Connect(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - var ( - netConnect types.NetworkConnect - ) + var netConnect types.NetworkConnect if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()")) return diff --git a/pkg/api/handlers/compat/secrets.go b/pkg/api/handlers/compat/secrets.go index 0c2306dc8..5031bf76b 100644 --- a/pkg/api/handlers/compat/secrets.go +++ b/pkg/api/handlers/compat/secrets.go @@ -16,9 +16,7 @@ import ( ) func ListSecrets(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filtersMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) @@ -51,9 +49,7 @@ func ListSecrets(w http.ResponseWriter, r *http.Request) { } func InspectSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) names := []string{name} ic := abi.ContainerEngine{Libpod: runtime} @@ -84,9 +80,7 @@ func InspectSecret(w http.ResponseWriter, r *http.Request) { } func RemoveSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) opts := entities.SecretRmOptions{} name := utils.GetName(r) @@ -104,9 +98,7 @@ func RemoveSecret(w http.ResponseWriter, r *http.Request) { } func CreateSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) opts := entities.SecretCreateOptions{} createParams := struct { *entities.SecretCreateRequest diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go deleted file mode 100644 index 86527da6e..000000000 --- a/pkg/api/handlers/compat/swagger.go +++ /dev/null @@ -1,67 +0,0 @@ -package compat - -import ( - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/docker/docker/api/types" -) - -// Create container -// swagger:response ContainerCreateResponse -type swagCtrCreateResponse struct { - // in:body - Body struct { - entities.ContainerCreateResponse - } -} - -// Wait container -// swagger:response ContainerWaitResponse -type swagCtrWaitResponse struct { - // in:body - Body struct { - // container exit code - StatusCode int - Error struct { - Message string - } - } -} - -// Network inspect -// swagger:response CompatNetworkInspect -type swagCompatNetworkInspect struct { - // in:body - Body types.NetworkResource -} - -// Network list -// swagger:response CompatNetworkList -type swagCompatNetworkList struct { - // in:body - Body []types.NetworkResource -} - -// Network create -// swagger:model NetworkCreateRequest -type NetworkCreateRequest struct { - types.NetworkCreateRequest -} - -// Network create -// swagger:response CompatNetworkCreate -type swagCompatNetworkCreateResponse struct { - // in:body - Body struct{ types.NetworkCreate } -} - -// Network disconnect -// swagger:model NetworkCompatConnectRequest -type swagCompatNetworkConnectRequest struct { - types.NetworkConnect -} - -// Network disconnect -// swagger:model NetworkCompatDisconnectRequest -type swagCompatNetworkDisconnectRequest struct { - types.NetworkDisconnect -} diff --git a/pkg/api/handlers/compat/version.go b/pkg/api/handlers/compat/version.go index b113fbc90..cfc3468c2 100644 --- a/pkg/api/handlers/compat/version.go +++ b/pkg/api/handlers/compat/version.go @@ -57,13 +57,15 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) { Version: conmon.Version, Details: map[string]string{ "Package": conmon.Package, - }}, + }, + }, { Name: fmt.Sprintf("OCI Runtime (%s)", oci.Name), Version: oci.Version, Details: map[string]string{ "Package": oci.Package, - }}, + }, + }, } components = append(components, additional...) } @@ -89,5 +91,6 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) { MinAPIVersion: fmt.Sprintf("%d.%d", minVersion.Major, minVersion.Minor), Os: components[0].Details["Os"], Version: components[0].Version, - }}) + }, + }) } diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go index c8e4339b0..ff0a7af02 100644 --- a/pkg/api/handlers/compat/volumes.go +++ b/pkg/api/handlers/compat/volumes.go @@ -180,9 +180,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { } func InspectVolume(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) vol, err := runtime.GetVolume(name) if err != nil { @@ -263,9 +261,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { } func PruneVolumes(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()")) |