summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/common/create.go13
-rw-r--r--cmd/podman/common/create_opts.go19
-rw-r--r--cmd/podman/containers/create.go16
-rw-r--r--cmd/podman/containers/port.go50
-rw-r--r--cmd/podman/containers/ps.go183
-rw-r--r--cmd/podman/containers/start.go3
-rw-r--r--cmd/podman/containers/stats.go12
-rw-r--r--cmd/podman/diff/diff.go2
-rw-r--r--cmd/podman/images/buildx.go11
-rw-r--r--cmd/podman/images/prune.go5
-rw-r--r--cmd/podman/images/pull.go2
-rw-r--r--cmd/podman/images/scp.go33
-rw-r--r--cmd/podman/images/search.go30
-rw-r--r--cmd/podman/machine/list.go9
-rw-r--r--cmd/podman/machine/stop.go8
-rw-r--r--cmd/podman/play/kube.go8
-rw-r--r--cmd/podman/pods/create.go12
-rw-r--r--cmd/podman/registry/remote.go8
-rw-r--r--cmd/podman/root.go2
-rw-r--r--cmd/podman/system/connection/list.go8
-rw-r--r--cmd/podman/system/connection/remove.go27
-rw-r--r--cmd/podman/system/dial_stdio.go145
-rw-r--r--cmd/podman/system/service_abi.go2
-rw-r--r--cmd/podman/system/unshare.go10
-rw-r--r--cmd/podman/system/version.go4
25 files changed, 362 insertions, 260 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index a3ff37c19..4598e535d 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
+ commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -319,6 +320,9 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
"Kernel memory limit "+sizeWithUnitFormat,
)
_ = cmd.RegisterFlagCompletionFunc(kernelMemoryFlagName, completion.AutocompleteNone)
+ // kernel-memory is deprecated in the runtime spec.
+ _ = createFlags.MarkHidden("kernel-memory")
+
logDriverFlagName := "log-driver"
createFlags.StringVar(
&cf.LogDriver,
@@ -406,7 +410,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
createFlags.StringVar(
&cf.Variant,
variantFlagName, "",
- "Use _VARIANT_ instead of the running architecture variant for choosing images",
+ "Use `VARIANT` instead of the running architecture variant for choosing images",
)
_ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
@@ -586,12 +590,9 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(timeoutFlagName, completion.AutocompleteNone)
- // Flag for TLS verification, so that `run` and `create` commands can make use of it.
- // Make sure to use `=` while using this flag i.e `--tls-verify=false/true`
- tlsVerifyFlagName := "tls-verify"
- createFlags.BoolVar(
+ commonFlag.OptionalBoolFlag(createFlags,
&cf.TLSVerify,
- tlsVerifyFlagName, true,
+ "tls-verify",
"Require HTTPS and verify certificates when contacting registries for pulling images",
)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 09ac61f2e..6283eb28e 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -18,6 +18,7 @@ import (
"github.com/containers/podman/v3/pkg/specgen"
"github.com/docker/docker/api/types/mount"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func stringMaptoArray(m map[string]string) []string {
@@ -104,15 +105,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
addField(&builder, "target", m.Target)
addField(&builder, "ro", strconv.FormatBool(m.ReadOnly))
addField(&builder, "consistency", string(m.Consistency))
-
// Map any specialized mount options that intersect between *Options and cli options
switch m.Type {
case mount.TypeBind:
- addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
- addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
+ if m.BindOptions != nil {
+ addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
+ addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
+ }
case mount.TypeTmpfs:
- addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
- addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10))
+ if m.TmpfsOptions != nil {
+ addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
+ addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10))
+ }
case mount.TypeVolume:
// All current VolumeOpts are handled above
// See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts()
@@ -288,7 +292,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
Rm: cc.HostConfig.AutoRemove,
SecurityOpt: cc.HostConfig.SecurityOpt,
StopSignal: cc.Config.StopSignal,
- StorageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
+ StorageOpts: stringMaptoArray(cc.HostConfig.StorageOpt),
Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
Systemd: "true", // podman default
TmpFS: parsedTmp,
@@ -380,6 +384,9 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
if cc.HostConfig.Memory > 0 {
cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory))
}
+ if cc.HostConfig.KernelMemory > 0 {
+ logrus.Warnf("The --kernel-memory flag has been deprecated. May not work properly on your system.")
+ }
if cc.HostConfig.MemoryReservation > 0 {
cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation))
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index bfeeb7ebe..d35c1a192 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -303,6 +303,11 @@ func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (strin
}
}
+ skipTLSVerify := types.OptionalBoolUndefined
+ if cliVals.TLSVerify.Present() {
+ skipTLSVerify = types.NewOptionalBool(!cliVals.TLSVerify.Value())
+ }
+
pullReport, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{
Authfile: cliVals.Authfile,
Quiet: cliVals.Quiet,
@@ -311,7 +316,7 @@ func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (strin
Variant: cliVals.Variant,
SignaturePolicy: cliVals.SignaturePolicy,
PullPolicy: pullPolicy,
- SkipTLSVerify: types.NewOptionalBool(!cliVals.TLSVerify), // If Flag changed for TLS Verification
+ SkipTLSVerify: skipTLSVerify,
})
if pullErr != nil {
return "", pullErr
@@ -372,15 +377,10 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
}
infraOpts := entities.ContainerCreateOptions{ImageVolume: "bind", Net: netOpts, Quiet: true}
- rawImageName := config.DefaultInfraImage
- name, err := PullImage(rawImageName, infraOpts)
- if err != nil {
- fmt.Println(err)
- }
- imageName := name
+ imageName := config.DefaultInfraImage
podGen.InfraImage = imageName
podGen.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
- podGen.InfraContainerSpec.RawImageName = rawImageName
+ podGen.InfraContainerSpec.RawImageName = imageName
podGen.InfraContainerSpec.NetworkOptions = podGen.NetworkOptions
err = specgenutil.FillOutSpecGen(podGen.InfraContainerSpec, &infraOpts, []string{})
if err != nil {
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index f309390c3..0e582ae52 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -8,7 +8,6 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
- "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -73,7 +72,8 @@ func port(_ *cobra.Command, args []string) error {
var (
container string
err error
- userPort types.OCICNIPortMapping
+ userPort uint16
+ userProto string
)
if len(args) == 0 && !portOpts.Latest && !portOpts.All {
@@ -101,16 +101,12 @@ func port(_ *cobra.Command, args []string) error {
fields = append(fields, "tcp")
}
- portNum, err := strconv.Atoi(fields[0])
+ portNum, err := strconv.ParseUint(fields[0], 10, 16)
if err != nil {
return err
}
- userPort = types.OCICNIPortMapping{
- HostPort: 0,
- ContainerPort: int32(portNum),
- Protocol: fields[1],
- HostIP: "",
- }
+ userPort = uint16(portNum)
+ userProto = fields[1]
}
reports, err := registry.ContainerEngine().ContainerPort(registry.GetContext(), container, portOpts)
@@ -120,24 +116,36 @@ func port(_ *cobra.Command, args []string) error {
var found bool
// Iterate mappings
for _, report := range reports {
+ allPrefix := ""
+ if portOpts.All {
+ allPrefix = report.Id[:12] + "\t"
+ }
for _, v := range report.Ports {
hostIP := v.HostIP
// Set host IP to 0.0.0.0 if blank
if hostIP == "" {
hostIP = "0.0.0.0"
}
- if portOpts.All {
- fmt.Printf("%s\t", report.Id[:12])
- }
- // If not searching by port or port/proto, then dump what we see
- if port == "" {
- fmt.Printf("%d/%s -> %s:%d\n", v.ContainerPort, v.Protocol, hostIP, v.HostPort)
- continue
- }
- if v.ContainerPort == userPort.ContainerPort {
- fmt.Printf("%s:%d\n", hostIP, v.HostPort)
- found = true
- break
+ protocols := strings.Split(v.Protocol, ",")
+ for _, protocol := range protocols {
+ // If not searching by port or port/proto, then dump what we see
+ if port == "" {
+ for i := uint16(0); i < v.Range; i++ {
+ fmt.Printf("%s%d/%s -> %s:%d\n", allPrefix, v.ContainerPort+i, protocol, hostIP, v.HostPort+i)
+ }
+ continue
+ }
+ // check if the proto matches and if the port is in the range
+ // this is faster than looping over the range for no reason
+ if v.Protocol == userProto &&
+ v.ContainerPort <= userPort &&
+ v.ContainerPort+v.Range > userPort {
+ // we have to add the current range to the host port
+ hostPort := v.HostPort + userPort - v.ContainerPort
+ fmt.Printf("%s%s:%d\n", allPrefix, hostIP, hostPort)
+ found = true
+ break
+ }
}
}
if !found && port != "" {
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 9687cd5bd..712de327c 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -3,8 +3,6 @@ package containers
import (
"fmt"
"os"
- "sort"
- "strconv"
"strings"
"time"
@@ -477,174 +475,31 @@ func (l psReporter) UTS() string {
// portsToString converts the ports used to a string of the from "port1, port2"
// and also groups a continuous list of ports into a readable format.
-func portsToString(ports []types.OCICNIPortMapping) string {
+// The format is IP:HostPort(-Range)->ContainerPort(-Range)/Proto
+func portsToString(ports []types.PortMapping) string {
if len(ports) == 0 {
return ""
}
- // Sort the ports, so grouping continuous ports become easy.
- sort.Slice(ports, func(i, j int) bool {
- return comparePorts(ports[i], ports[j])
- })
-
- portGroups := [][]types.OCICNIPortMapping{}
- currentGroup := []types.OCICNIPortMapping{}
- for i, v := range ports {
- var prevPort, nextPort *int32
- if i > 0 {
- prevPort = &ports[i-1].ContainerPort
- }
- if i+1 < len(ports) {
- nextPort = &ports[i+1].ContainerPort
- }
-
- port := v.ContainerPort
-
- // Helper functions
- addToCurrentGroup := func(x types.OCICNIPortMapping) {
- currentGroup = append(currentGroup, x)
- }
-
- addToPortGroup := func(x types.OCICNIPortMapping) {
- portGroups = append(portGroups, []types.OCICNIPortMapping{x})
- }
-
- finishCurrentGroup := func() {
- portGroups = append(portGroups, currentGroup)
- currentGroup = []types.OCICNIPortMapping{}
- }
-
- // Single entry slice
- if prevPort == nil && nextPort == nil {
- addToPortGroup(v)
- }
-
- // Start of the slice with len > 0
- if prevPort == nil && nextPort != nil {
- isGroup := *nextPort-1 == port
-
- if isGroup {
- // Start with a group
- addToCurrentGroup(v)
- } else {
- // Start with single item
- addToPortGroup(v)
- }
-
- continue
- }
-
- // Middle of the slice with len > 0
- if prevPort != nil && nextPort != nil {
- currentIsGroup := *prevPort+1 == port
- nextIsGroup := *nextPort-1 == port
-
- if currentIsGroup {
- // Maybe in the middle of a group
- addToCurrentGroup(v)
-
- if !nextIsGroup {
- // End of a group
- finishCurrentGroup()
- }
- } else if nextIsGroup {
- // Start of a new group
- addToCurrentGroup(v)
- } else {
- // No group at all
- addToPortGroup(v)
- }
-
- continue
- }
-
- // End of the slice with len > 0
- if prevPort != nil && nextPort == nil {
- isGroup := *prevPort+1 == port
-
- if isGroup {
- // End group
- addToCurrentGroup(v)
- finishCurrentGroup()
- } else {
- // End single item
- addToPortGroup(v)
- }
- }
- }
-
- portDisplay := []string{}
- for _, group := range portGroups {
- if len(group) == 0 {
- // Usually should not happen, but better do not crash.
- continue
- }
-
- first := group[0]
-
- hostIP := first.HostIP
+ sb := &strings.Builder{}
+ for _, port := range ports {
+ hostIP := port.HostIP
if hostIP == "" {
hostIP = "0.0.0.0"
}
-
- // Single mappings
- if len(group) == 1 {
- portDisplay = append(portDisplay,
- fmt.Sprintf(
- "%s:%d->%d/%s",
- hostIP, first.HostPort, first.ContainerPort, first.Protocol,
- ),
- )
- continue
- }
-
- // Group mappings
- last := group[len(group)-1]
- portDisplay = append(portDisplay, formatGroup(
- fmt.Sprintf("%s/%s", hostIP, first.Protocol),
- first.HostPort, last.HostPort,
- first.ContainerPort, last.ContainerPort,
- ))
- }
- return strings.Join(portDisplay, ", ")
-}
-
-func comparePorts(i, j types.OCICNIPortMapping) bool {
- if i.ContainerPort != j.ContainerPort {
- return i.ContainerPort < j.ContainerPort
- }
-
- if i.HostIP != j.HostIP {
- return i.HostIP < j.HostIP
- }
-
- if i.HostPort != j.HostPort {
- return i.HostPort < j.HostPort
- }
-
- return i.Protocol < j.Protocol
-}
-
-// formatGroup returns the group in the format:
-// <IP:firstHost:lastHost->firstCtr:lastCtr/Proto>
-// e.g 0.0.0.0:1000-1006->2000-2006/tcp.
-func formatGroup(key string, firstHost, lastHost, firstCtr, lastCtr int32) string {
- parts := strings.Split(key, "/")
- groupType := parts[0]
- var ip string
- if len(parts) > 1 {
- ip = parts[0]
- groupType = parts[1]
- }
-
- group := func(first, last int32) string {
- group := strconv.Itoa(int(first))
- if first != last {
- group = fmt.Sprintf("%s-%d", group, last)
+ protocols := strings.Split(port.Protocol, ",")
+ for _, protocol := range protocols {
+ if port.Range > 1 {
+ fmt.Fprintf(sb, "%s:%d-%d->%d-%d/%s, ",
+ hostIP, port.HostPort, port.HostPort+port.Range-1,
+ port.ContainerPort, port.ContainerPort+port.Range-1, protocol)
+ } else {
+ fmt.Fprintf(sb, "%s:%d->%d/%s, ",
+ hostIP, port.HostPort,
+ port.ContainerPort, protocol)
+ }
}
- return group
}
- hostGroup := group(firstHost, lastHost)
- ctrGroup := group(firstCtr, lastCtr)
-
- return fmt.Sprintf("%s:%s->%s/%s", ip, hostGroup, ctrGroup, groupType)
+ display := sb.String()
+ // make sure to trim the last ", " of the string
+ return display[:len(display)-2]
}
diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go
index 1163b9093..8813fc273 100644
--- a/cmd/podman/containers/start.go
+++ b/cmd/podman/containers/start.go
@@ -87,6 +87,9 @@ func validateStart(cmd *cobra.Command, args []string) error {
if len(args) == 0 && !startOptions.Latest && !startOptions.All {
return errors.New("start requires at least one argument")
}
+ if startOptions.All && startOptions.Latest {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
if len(args) > 0 && startOptions.Latest {
return errors.Errorf("--latest and containers cannot be used together")
}
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 11e8f6870..d21feaabc 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -11,9 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/utils"
"github.com/docker/go-units"
"github.com/pkg/errors"
@@ -113,16 +111,6 @@ func checkStatOptions(cmd *cobra.Command, args []string) error {
}
func stats(cmd *cobra.Command, args []string) error {
- if rootless.IsRootless() {
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return err
- }
- if !unified {
- return errors.New("stats is not supported in rootless mode without cgroups v2")
- }
- }
-
// Convert to the entities options. We should not leak CLI-only
// options into the backend and separate concerns.
opts := entities.ContainerStatsOptions{
diff --git a/cmd/podman/diff/diff.go b/cmd/podman/diff/diff.go
index 81bbb6c43..fba4ea540 100644
--- a/cmd/podman/diff/diff.go
+++ b/cmd/podman/diff/diff.go
@@ -8,7 +8,7 @@ import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/docker/docker/pkg/archive"
+ "github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
diff --git a/cmd/podman/images/buildx.go b/cmd/podman/images/buildx.go
index 5c8e5aaa0..2577a3a74 100644
--- a/cmd/podman/images/buildx.go
+++ b/cmd/podman/images/buildx.go
@@ -14,11 +14,12 @@ var (
// If we are adding new buildx features, we will add them by default
// to podman build.
buildxCmd = &cobra.Command{
- Use: "buildx",
- Short: "Build images",
- Long: "Build images",
- RunE: validate.SubCommandExists,
- Hidden: true,
+ Use: "buildx",
+ Aliases: []string{"builder"},
+ Short: "Build images",
+ Long: "Build images",
+ RunE: validate.SubCommandExists,
+ Hidden: true,
}
)
diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go
index 6c39e5c69..fc7451c41 100644
--- a/cmd/podman/images/prune.go
+++ b/cmd/podman/images/prune.go
@@ -36,6 +36,11 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: pruneCmd,
+ Parent: buildxCmd,
+ })
+
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: pruneCmd,
Parent: imageCmd,
})
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go
index a4e3515db..a990d1626 100644
--- a/cmd/podman/images/pull.go
+++ b/cmd/podman/images/pull.go
@@ -92,7 +92,7 @@ func pullFlags(cmd *cobra.Command) {
_ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS)
variantFlagName := "variant"
- flags.StringVar(&pullOptions.Variant, variantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images")
+ flags.StringVar(&pullOptions.Variant, variantFlagName, "", "Use VARIANT instead of the running architecture variant for choosing images")
_ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone)
platformFlagName := "platform"
diff --git a/cmd/podman/images/scp.go b/cmd/podman/images/scp.go
index 176563440..8402d9a10 100644
--- a/cmd/podman/images/scp.go
+++ b/cmd/podman/images/scp.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/system/connection"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/rootless"
"github.com/docker/distribution/reference"
scpD "github.com/dtylman/scp"
"github.com/pkg/errors"
@@ -125,6 +126,11 @@ func scp(cmd *cobra.Command, args []string) (finalErr error) {
fmt.Println(rep)
// TODO: Add podman remote support
default: // else native load
+ scpOpts.Save.Format = "oci-archive"
+ _, err := os.Open(scpOpts.Save.Output)
+ if err != nil {
+ return err
+ }
if scpOpts.Tag != "" {
return errors.Wrapf(define.ErrInvalidArg, "Renaming of an image is currently not supported")
}
@@ -133,12 +139,20 @@ func scp(cmd *cobra.Command, args []string) (finalErr error) {
if abiErr != nil {
errors.Wrapf(abiErr, "could not save image as specified")
}
- rep, err := abiEng.Load(context.Background(), scpOpts.Load)
- if err != nil {
- return err
+ if !rootless.IsRootless() && scpOpts.Rootless {
+ err := abiEng.Transfer(context.Background(), scpOpts)
+ if err != nil {
+ return err
+ }
+ } else {
+ rep, err := abiEng.Load(context.Background(), scpOpts.Load)
+ if err != nil {
+ return err
+ }
+ fmt.Println("Loaded image(s): " + strings.Join(rep.Names, ","))
}
- fmt.Println("Loaded image(s): " + strings.Join(rep.Names, ","))
}
+
return nil
}
@@ -185,7 +199,7 @@ func saveToRemote(image, localFile string, tag string, uri *urlP.URL, iden strin
return errors.Wrapf(define.ErrInvalidArg, "Renaming of an image is currently not supported")
}
podman := os.Args[0]
- run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in thie case...
+ run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in this case...
_, err = connection.ExecRemoteCommand(dial, run)
if err != nil {
return nil
@@ -271,7 +285,14 @@ func parseArgs(args []string, cfg *config.Config) (map[string]config.Destination
scpOpts.SourceImageName = args[0]
}
case 2:
- if strings.Contains(args[0], "::") {
+ if strings.Contains(args[0], "localhost") || strings.Contains(args[1], "localhost") { // only supporting root to local using sudo at the moment
+ scpOpts.Rootless = true
+ scpOpts.User = strings.Split(args[1], "@")[0]
+ scpOpts.SourceImageName = strings.Split(args[0], "::")[1]
+ if strings.Split(args[0], "@")[0] != "root" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "cannot transfer images from any user besides root using sudo")
+ }
+ } else if strings.Contains(args[0], "::") {
if !(strings.Contains(args[1], "::")) && remoteArgLength(args[0], 1) == 0 { // if an image is specified, this mean we are loading to our client
cliConnections = append(cliConnections, args[0])
scpOpts.ToRemote = true
diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go
index 11e54578a..c9a4793aa 100644
--- a/cmd/podman/images/search.go
+++ b/cmd/podman/images/search.go
@@ -3,6 +3,7 @@ package images
import (
"fmt"
"os"
+ "strings"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
@@ -19,6 +20,7 @@ import (
type searchOptionsWrapper struct {
entities.ImageSearchOptions
// CLI only flags
+ Compatible bool // Docker compat
TLSVerifyCLI bool // Used to convert to an optional bool later
Format string // For go templating
}
@@ -79,7 +81,7 @@ func searchFlags(cmd *cobra.Command) {
filterFlagName := "filter"
flags.StringSliceVarP(&searchOptions.Filters, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])")
- //TODO add custom filter function
+ // TODO add custom filter function
_ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
formatFlagName := "format"
@@ -90,7 +92,8 @@ func searchFlags(cmd *cobra.Command) {
flags.IntVar(&searchOptions.Limit, limitFlagName, 0, "Limit the number of results")
_ = cmd.RegisterFlagCompletionFunc(limitFlagName, completion.AutocompleteNone)
- flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output")
+ flags.Bool("no-trunc", true, "Do not truncate the output. Default: true")
+ flags.BoolVar(&searchOptions.Compatible, "compatible", false, "List stars, official and automated columns (Docker compatibility)")
authfileFlagName := "authfile"
flags.StringVar(&searchOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
@@ -132,11 +135,20 @@ func imageSearch(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
-
if len(searchReport) == 0 {
return nil
}
+ noTrunc, _ := cmd.Flags().GetBool("no-trunc")
+ isJSON := report.IsJSON(searchOptions.Format)
+ for i, element := range searchReport {
+ d := strings.ReplaceAll(element.Description, "\n", " ")
+ if len(d) > 44 && !(noTrunc || isJSON) {
+ d = strings.TrimSpace(d[:44]) + "..."
+ }
+ searchReport[i].Description = d
+ }
+
hdrs := report.Headers(entities.ImageSearchReport{}, nil)
renderHeaders := true
var row string
@@ -145,18 +157,22 @@ func imageSearch(cmd *cobra.Command, args []string) error {
if len(searchOptions.Filters) != 0 {
return errors.Errorf("filters are not applicable to list tags result")
}
- if report.IsJSON(searchOptions.Format) {
+ if isJSON {
listTagsEntries := buildListTagsJSON(searchReport)
return printArbitraryJSON(listTagsEntries)
}
row = "{{.Name}}\t{{.Tag}}\n"
- case report.IsJSON(searchOptions.Format):
+ case isJSON:
return printArbitraryJSON(searchReport)
case cmd.Flags().Changed("format"):
renderHeaders = report.HasTable(searchOptions.Format)
row = report.NormalizeFormat(searchOptions.Format)
default:
- row = "{{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\n"
+ row = "{{.Name}}\t{{.Description}}"
+ if searchOptions.Compatible {
+ row += "\t{{.Stars}}\t{{.Official}}\t{{.Automated}}"
+ }
+ row += "\n"
}
format := report.EnforceRange(row)
@@ -190,7 +206,7 @@ func printArbitraryJSON(v interface{}) error {
}
func buildListTagsJSON(searchReport []entities.ImageSearchReport) []listEntryTag {
- entries := []listEntryTag{}
+ entries := make([]listEntryTag, 0)
ReportLoop:
for _, report := range searchReport {
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index 7e5459e08..d569f4db0 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -48,6 +48,7 @@ type machineReporter struct {
Created string
Running bool
LastUp string
+ Stream string
VMType string
CPUs uint64
Memory string
@@ -153,6 +154,13 @@ func strUint(u uint64) string {
return strconv.FormatUint(u, 10)
}
+func streamName(imageStream string) string {
+ if imageStream == "" {
+ return "default"
+ }
+ return imageStream
+}
+
func toMachineFormat(vms []*machine.ListResponse) ([]*machineReporter, error) {
cfg, err := config.ReadCustomConfig()
if err != nil {
@@ -167,6 +175,7 @@ func toMachineFormat(vms []*machine.ListResponse) ([]*machineReporter, error) {
response.Running = vm.Running
response.LastUp = strTime(vm.LastUp)
response.Created = strTime(vm.CreatedAt)
+ response.Stream = streamName(vm.Stream)
response.VMType = vm.VMType
response.CPUs = vm.CPUs
response.Memory = strUint(vm.Memory * units.MiB)
diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go
index 76ba85601..75666f734 100644
--- a/cmd/podman/machine/stop.go
+++ b/cmd/podman/machine/stop.go
@@ -3,6 +3,8 @@
package machine
import (
+ "fmt"
+
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/machine"
"github.com/containers/podman/v3/pkg/machine/qemu"
@@ -46,5 +48,9 @@ func stop(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- return vm.Stop(vmName, machine.StopOptions{})
+ if err := vm.Stop(vmName, machine.StopOptions{}); err != nil {
+ return err
+ }
+ fmt.Printf("Machine %q stopped successfully\n", vmName)
+ return nil
}
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index e6869efd3..581b29113 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -80,6 +80,14 @@ func init() {
flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, "", "Logging driver for the container")
_ = kubeCmd.RegisterFlagCompletionFunc(logDriverFlagName, common.AutocompleteLogDriver)
+ logOptFlagName := "log-opt"
+ flags.StringSliceVar(
+ &kubeOptions.LogOptions,
+ logOptFlagName, []string{},
+ "Logging driver options",
+ )
+ _ = kubeCmd.RegisterFlagCompletionFunc(logOptFlagName, common.AutocompleteLogOpt)
+
flags.BoolVar(&kubeOptions.NoHosts, "no-hosts", false, "Do not create /etc/hosts within the pod's containers, instead use the version from the image")
flags.BoolVarP(&kubeOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index d5aaf09ce..0a0d43b53 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -132,7 +132,7 @@ func create(cmd *cobra.Command, args []string) error {
}
createOptions.Share = nil
} else {
- // reassign certain optios for lbpod api, these need to be populated in spec
+ // reassign certain options for lbpod api, these need to be populated in spec
flags := cmd.Flags()
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
if err != nil {
@@ -242,16 +242,6 @@ func create(cmd *cobra.Command, args []string) error {
}
if createOptions.Infra {
rawImageName = img
- if !infraOptions.RootFS {
- curr := infraOptions.Quiet
- infraOptions.Quiet = true
- name, err := containers.PullImage(imageName, infraOptions)
- if err != nil {
- fmt.Println(err)
- }
- imageName = name
- infraOptions.Quiet = curr
- }
podSpec.InfraImage = imageName
if infraOptions.Entrypoint != nil {
createOptions.InfraCommand = infraOptions.Entrypoint
diff --git a/cmd/podman/registry/remote.go b/cmd/podman/registry/remote.go
index b5da98bd4..c78930574 100644
--- a/cmd/podman/registry/remote.go
+++ b/cmd/podman/registry/remote.go
@@ -19,11 +19,17 @@ var remoteFromCLI = struct {
// Use in init() functions as an initialization check
func IsRemote() bool {
remoteFromCLI.sync.Do(func() {
+ remote := false
+ if _, ok := os.LookupEnv("CONTAINER_HOST"); ok {
+ remote = true
+ } else if _, ok := os.LookupEnv("CONTAINER_CONNECTION"); ok {
+ remote = true
+ }
fs := pflag.NewFlagSet("remote", pflag.ContinueOnError)
fs.ParseErrorsWhitelist.UnknownFlags = true
fs.Usage = func() {}
fs.SetInterspersed(false)
- fs.BoolVarP(&remoteFromCLI.Value, "remote", "r", false, "")
+ fs.BoolVarP(&remoteFromCLI.Value, "remote", "r", remote, "")
// The shell completion logic will call a command called "__complete" or "__completeNoDesc"
// This command will always be the second argument
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index eb30f1ef6..6da34050e 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -314,7 +314,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
lFlags.StringVar(&opts.Identity, identityFlagName, ident, "path to SSH identity file, (CONTAINER_SSHKEY)")
_ = cmd.RegisterFlagCompletionFunc(identityFlagName, completion.AutocompleteDefault)
- lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)")
+ lFlags.BoolVarP(&opts.Remote, "remote", "r", registry.IsRemote(), "Access remote Podman service")
pFlags := cmd.PersistentFlags()
if registry.IsRemote() {
if err := lFlags.MarkHidden("remote"); err != nil {
diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go
index de85ce3fa..a3290e3d6 100644
--- a/cmd/podman/system/connection/list.go
+++ b/cmd/podman/system/connection/list.go
@@ -44,6 +44,7 @@ func init() {
type namedDestination struct {
Name string
config.Destination
+ Default bool
}
func list(cmd *cobra.Command, _ []string) error {
@@ -60,12 +61,14 @@ func list(cmd *cobra.Command, _ []string) error {
"Identity": "Identity",
"Name": "Name",
"URI": "URI",
+ "Default": "Default",
}}
rows := make([]namedDestination, 0)
for k, v := range cfg.Engine.ServiceDestinations {
+ def := false
if k == cfg.Engine.ActiveService {
- k += "*"
+ def = true
}
r := namedDestination{
@@ -74,6 +77,7 @@ func list(cmd *cobra.Command, _ []string) error {
Identity: v.Identity,
URI: v.URI,
},
+ Default: def,
}
rows = append(rows, r)
}
@@ -82,7 +86,7 @@ func list(cmd *cobra.Command, _ []string) error {
return rows[i].Name < rows[j].Name
})
- format := "{{.Name}}\t{{.Identity}}\t{{.URI}}\n"
+ format := "{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n"
switch {
case report.IsJSON(cmd.Flag("format").Value.String()):
buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ")
diff --git a/cmd/podman/system/connection/remove.go b/cmd/podman/system/connection/remove.go
index 73bae4994..ffbea76c5 100644
--- a/cmd/podman/system/connection/remove.go
+++ b/cmd/podman/system/connection/remove.go
@@ -5,14 +5,14 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/system"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
)
var (
// Skip creating engines since this command will obtain connection information to said engines
rmCmd = &cobra.Command{
- Use: "remove NAME",
- Args: cobra.ExactArgs(1),
+ Use: "remove [options] NAME",
Aliases: []string{"rm"},
Long: `Delete named destination from podman configuration`,
Short: "Delete named destination",
@@ -21,6 +21,10 @@ var (
Example: `podman system connection remove devl
podman system connection rm devl`,
}
+
+ rmOpts = struct {
+ All bool
+ }{}
)
func init() {
@@ -28,14 +32,31 @@ func init() {
Command: rmCmd,
Parent: system.ConnectionCmd,
})
+
+ flags := rmCmd.Flags()
+ flags.BoolVarP(&rmOpts.All, "all", "a", false, "Remove all connections")
}
-func rm(_ *cobra.Command, args []string) error {
+func rm(cmd *cobra.Command, args []string) error {
cfg, err := config.ReadCustomConfig()
if err != nil {
return err
}
+ if rmOpts.All {
+ if cfg.Engine.ServiceDestinations != nil {
+ for k := range cfg.Engine.ServiceDestinations {
+ delete(cfg.Engine.ServiceDestinations, k)
+ }
+ }
+ cfg.Engine.ActiveService = ""
+ return cfg.Write()
+ }
+
+ if len(args) != 1 {
+ return errors.New("accepts 1 arg(s), received 0")
+ }
+
if cfg.Engine.ServiceDestinations != nil {
delete(cfg.Engine.ServiceDestinations, args[0])
}
diff --git a/cmd/podman/system/dial_stdio.go b/cmd/podman/system/dial_stdio.go
new file mode 100644
index 000000000..eae89f38e
--- /dev/null
+++ b/cmd/podman/system/dial_stdio.go
@@ -0,0 +1,145 @@
+package system
+
+import (
+ "context"
+ "io"
+ "os"
+
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/pkg/bindings"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+var (
+ dialStdioCommand = &cobra.Command{
+ Use: "dial-stdio",
+ Short: "Proxy the stdio stream to the daemon connection. Should not be invoked manually.",
+ Args: validate.NoArgs,
+ Hidden: true,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runDialStdio()
+ },
+ Example: "podman system dial-stdio",
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Command: dialStdioCommand,
+ Parent: systemCmd,
+ })
+}
+
+func runDialStdio() error {
+ ctx := registry.Context()
+ cfg := registry.PodmanConfig()
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ bindCtx, err := bindings.NewConnection(ctx, cfg.URI)
+ if err != nil {
+ return errors.Wrap(err, "failed to open connection to podman")
+ }
+ conn, err := bindings.GetClient(bindCtx)
+ if err != nil {
+ return errors.Wrap(err, "failed to get connection after initialization")
+ }
+ netConn, err := conn.GetDialer(bindCtx)
+ if err != nil {
+ return errors.Wrap(err, "failed to open the raw stream connection")
+ }
+ defer netConn.Close()
+
+ var connHalfCloser halfCloser
+ switch t := netConn.(type) {
+ case halfCloser:
+ connHalfCloser = t
+ case halfReadWriteCloser:
+ connHalfCloser = &nopCloseReader{t}
+ default:
+ return errors.New("the raw stream connection does not implement halfCloser")
+ }
+
+ stdin2conn := make(chan error, 1)
+ conn2stdout := make(chan error, 1)
+ go func() {
+ stdin2conn <- copier(connHalfCloser, &halfReadCloserWrapper{os.Stdin}, "stdin to stream")
+ }()
+ go func() {
+ conn2stdout <- copier(&halfWriteCloserWrapper{os.Stdout}, connHalfCloser, "stream to stdout")
+ }()
+ select {
+ case err = <-stdin2conn:
+ if err != nil {
+ return err
+ }
+ // wait for stdout
+ err = <-conn2stdout
+ case err = <-conn2stdout:
+ // return immediately
+ }
+ return err
+}
+
+// Below portion taken from original docker CLI
+// https://github.com/docker/cli/blob/v20.10.9/cli/command/system/dial_stdio.go
+func copier(to halfWriteCloser, from halfReadCloser, debugDescription string) error {
+ defer func() {
+ if err := from.CloseRead(); err != nil {
+ logrus.Errorf("error while CloseRead (%s): %v", debugDescription, err)
+ }
+ if err := to.CloseWrite(); err != nil {
+ logrus.Errorf("error while CloseWrite (%s): %v", debugDescription, err)
+ }
+ }()
+ if _, err := io.Copy(to, from); err != nil {
+ return errors.Wrapf(err, "error while Copy (%s)", debugDescription)
+ }
+ return nil
+}
+
+type halfReadCloser interface {
+ io.Reader
+ CloseRead() error
+}
+
+type halfWriteCloser interface {
+ io.Writer
+ CloseWrite() error
+}
+
+type halfCloser interface {
+ halfReadCloser
+ halfWriteCloser
+}
+
+type halfReadWriteCloser interface {
+ io.Reader
+ halfWriteCloser
+}
+
+type nopCloseReader struct {
+ halfReadWriteCloser
+}
+
+func (x *nopCloseReader) CloseRead() error {
+ return nil
+}
+
+type halfReadCloserWrapper struct {
+ io.ReadCloser
+}
+
+func (x *halfReadCloserWrapper) CloseRead() error {
+ return x.Close()
+}
+
+type halfWriteCloserWrapper struct {
+ io.WriteCloser
+}
+
+func (x *halfWriteCloserWrapper) CloseWrite() error {
+ return x.Close()
+}
diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go
index 0a4be6aea..b9bd7538f 100644
--- a/cmd/podman/system/service_abi.go
+++ b/cmd/podman/system/service_abi.go
@@ -93,7 +93,7 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
return err
}
defer func() {
- if err := server.Shutdown(false); err != nil {
+ if err := server.Shutdown(true); err != nil {
logrus.Warnf("Error when stopping API service: %s", err)
}
}()
diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go
index 50230609e..9b777dd8f 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
)
var (
@@ -34,7 +35,14 @@ func init() {
})
flags := unshareCommand.Flags()
flags.SetInterspersed(false)
- flags.BoolVar(&unshareOptions.RootlessCNI, "rootless-cni", false, "Join the rootless network namespace used for CNI networking")
+ flags.BoolVar(&unshareOptions.RootlessNetNS, "rootless-netns", false, "Join the rootless network namespace used for CNI and netavark networking")
+ // backwards compat still allow --rootless-cni
+ flags.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ if name == "rootless-cni" {
+ name = "rootless-netns"
+ }
+ return pflag.NormalizedName(name)
+ })
}
func unshare(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 4502b156c..3443978d6 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -20,7 +20,7 @@ var (
versionCommand = &cobra.Command{
Use: "version [options]",
Args: validate.NoArgs,
- Short: "Display the Podman Version Information",
+ Short: "Display the Podman version information",
RunE: version,
ValidArgsFunction: completion.AutocompleteNone,
}
@@ -67,7 +67,7 @@ func version(cmd *cobra.Command, args []string) error {
}
if err := tmpl.Execute(w, versions); err != nil {
// On Failure, assume user is using older version of podman version --format and check client
- row = strings.Replace(row, ".Server.", ".", 1)
+ row = strings.ReplaceAll(row, ".Server.", ".")
tmpl, err := report.NewTemplate("version 1.0.0").Parse(row)
if err != nil {
return err