diff options
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/common/netflags.go | 11 | ||||
-rw-r--r-- | cmd/podman/common/specgen.go | 272 | ||||
-rw-r--r-- | cmd/podman/containers/attach.go | 17 | ||||
-rw-r--r-- | cmd/podman/containers/commit.go | 2 | ||||
-rw-r--r-- | cmd/podman/containers/cp.go | 55 | ||||
-rw-r--r-- | cmd/podman/containers/run.go | 4 | ||||
-rw-r--r-- | cmd/podman/containers/start.go | 2 | ||||
-rw-r--r-- | cmd/podman/login.go | 68 | ||||
-rw-r--r-- | cmd/podman/logout.go | 57 |
9 files changed, 360 insertions, 128 deletions
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go index 1a47733e7..a439eb792 100644 --- a/cmd/podman/common/netflags.go +++ b/cmd/podman/common/netflags.go @@ -5,6 +5,7 @@ import ( "github.com/containers/libpod/cmd/podman/parse" "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/specgen" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -159,9 +160,13 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) { return nil, err } - return nil, errors.Errorf("network %s is not yet supported", network) - // TODO How do I convert a string network to a Specgen.Namespace? - // opts.Network = specgen.Namespace{NSMode: network} + ns, cniNets, err := specgen.ParseNetworkNamespace(network) + if err != nil { + return nil, err + } + + opts.Network = ns + opts.CNINetworks = cniNets } return &opts, err diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 43325ef8c..fc0167461 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -22,49 +22,135 @@ import ( "github.com/pkg/errors" ) -func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error { - var ( - err error - //namespaces map[string]string - ) +func getCPULimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) (*specs.LinuxCPU, error) { + cpu := &specs.LinuxCPU{} + hasLimits := false - // validate flags as needed - if err := c.validate(); err != nil { - return nil + if c.CPUShares > 0 { + cpu.Shares = &c.CPUShares + hasLimits = true + } + if c.CPUPeriod > 0 { + cpu.Period = &c.CPUPeriod + hasLimits = true + } + if c.CPUSetCPUs != "" { + cpu.Cpus = c.CPUSetCPUs + hasLimits = true + } + if c.CPUSetMems != "" { + cpu.Mems = c.CPUSetMems + hasLimits = true + } + if c.CPUQuota > 0 { + cpu.Quota = &c.CPUQuota + hasLimits = true + } + if c.CPURTPeriod > 0 { + cpu.RealtimePeriod = &c.CPURTPeriod + hasLimits = true + } + if c.CPURTRuntime > 0 { + cpu.RealtimeRuntime = &c.CPURTRuntime + hasLimits = true } - s.User = c.User - inputCommand := args[1:] - if len(c.HealthCmd) > 0 { - s.HealthConfig, err = makeHealthCheckFromCli(c.HealthCmd, c.HealthInterval, c.HealthRetries, c.HealthTimeout, c.HealthStartPeriod) + if !hasLimits { + return nil, nil + } + return cpu, nil +} + +func getIOLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) (*specs.LinuxBlockIO, error) { + var err error + io := &specs.LinuxBlockIO{} + hasLimits := false + if b := c.BlkIOWeight; len(b) > 0 { + u, err := strconv.ParseUint(b, 10, 16) if err != nil { - return err + return nil, errors.Wrapf(err, "invalid value for blkio-weight") } + nu := uint16(u) + io.Weight = &nu + hasLimits = true } - s.IDMappings, err = util.ParseIDMapping(ns.UsernsMode(c.UserNS), c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) - if err != nil { - return err + if len(c.BlkIOWeightDevice) > 0 { + if err := parseWeightDevices(c.BlkIOWeightDevice, s); err != nil { + return nil, err + } + hasLimits = true } - if s.ResourceLimits == nil { - s.ResourceLimits = &specs.LinuxResources{} + + if bps := c.DeviceReadBPs; len(bps) > 0 { + if s.ThrottleReadBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { + return nil, err + } + hasLimits = true + } + + if bps := c.DeviceWriteBPs; len(bps) > 0 { + if s.ThrottleWriteBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { + return nil, err + } + hasLimits = true + } + + if iops := c.DeviceReadIOPs; len(iops) > 0 { + if s.ThrottleReadIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { + return nil, err + } + hasLimits = true + } + + if iops := c.DeviceWriteIOPs; len(iops) > 0 { + if s.ThrottleWriteIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { + return nil, err + } + hasLimits = true + } + + if !hasLimits { + return nil, nil + } + return io, nil +} + +func getPidsLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) (*specs.LinuxPids, error) { + pids := &specs.LinuxPids{} + hasLimits := false + if c.PIDsLimit > 0 { + pids.Limit = c.PIDsLimit + hasLimits = true + } + if c.CGroups == "disabled" && c.PIDsLimit > 0 { + s.ResourceLimits.Pids.Limit = -1 } - if s.ResourceLimits.Memory == nil { - s.ResourceLimits.Memory = &specs.LinuxMemory{} + if !hasLimits { + return nil, nil } + return pids, nil +} + +func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) (*specs.LinuxMemory, error) { + var err error + memory := &specs.LinuxMemory{} + hasLimits := false if m := c.Memory; len(m) > 0 { ml, err := units.RAMInBytes(m) if err != nil { - return errors.Wrapf(err, "invalid value for memory") + return nil, errors.Wrapf(err, "invalid value for memory") } - s.ResourceLimits.Memory.Limit = &ml + memory.Limit = &ml + hasLimits = true } if m := c.MemoryReservation; len(m) > 0 { mr, err := units.RAMInBytes(m) if err != nil { - return errors.Wrapf(err, "invalid value for memory") + return nil, errors.Wrapf(err, "invalid value for memory") } - s.ResourceLimits.Memory.Reservation = &mr + memory.Reservation = &mr + hasLimits = true } if m := c.MemorySwap; len(m) > 0 { var ms int64 @@ -74,28 +160,58 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string } else { ms, err = units.RAMInBytes(m) if err != nil { - return errors.Wrapf(err, "invalid value for memory") + return nil, errors.Wrapf(err, "invalid value for memory") } } - s.ResourceLimits.Memory.Swap = &ms + memory.Swap = &ms + hasLimits = true } if m := c.KernelMemory; len(m) > 0 { mk, err := units.RAMInBytes(m) if err != nil { - return errors.Wrapf(err, "invalid value for kernel-memory") + return nil, errors.Wrapf(err, "invalid value for kernel-memory") } - s.ResourceLimits.Memory.Kernel = &mk + memory.Kernel = &mk + hasLimits = true } - if s.ResourceLimits.BlockIO == nil { - s.ResourceLimits.BlockIO = &specs.LinuxBlockIO{} + if c.MemorySwappiness >= 0 { + swappiness := uint64(c.MemorySwappiness) + memory.Swappiness = &swappiness + hasLimits = true } - if b := c.BlkIOWeight; len(b) > 0 { - u, err := strconv.ParseUint(b, 10, 16) + if c.OOMKillDisable { + memory.DisableOOMKiller = &c.OOMKillDisable + hasLimits = true + } + if !hasLimits { + return nil, nil + } + return memory, nil +} + +func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error { + var ( + err error + //namespaces map[string]string + ) + + // validate flags as needed + if err := c.validate(); err != nil { + return nil + } + + s.User = c.User + inputCommand := args[1:] + if len(c.HealthCmd) > 0 { + s.HealthConfig, err = makeHealthCheckFromCli(c.HealthCmd, c.HealthInterval, c.HealthRetries, c.HealthTimeout, c.HealthStartPeriod) if err != nil { - return errors.Wrapf(err, "invalid value for blkio-weight") + return err } - nu := uint16(u) - s.ResourceLimits.BlockIO.Weight = &nu + } + + s.IDMappings, err = util.ParseIDMapping(ns.UsernsMode(c.UserNS), c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) + if err != nil { + return err } s.Terminal = c.TTY @@ -329,12 +445,24 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string if s.ResourceLimits == nil { s.ResourceLimits = &specs.LinuxResources{} } - if s.ResourceLimits.Memory == nil { - s.ResourceLimits.Memory = &specs.LinuxMemory{} + s.ResourceLimits.Memory, err = getMemoryLimits(s, c, args) + if err != nil { + return err } - if c.MemorySwappiness >= 0 { - swappiness := uint64(c.MemorySwappiness) - s.ResourceLimits.Memory.Swappiness = &swappiness + s.ResourceLimits.BlockIO, err = getIOLimits(s, c, args) + if err != nil { + return err + } + s.ResourceLimits.Pids, err = getPidsLimits(s, c, args) + if err != nil { + return err + } + s.ResourceLimits.CPU, err = getCPULimits(s, c, args) + if err != nil { + return err + } + if s.ResourceLimits.CPU == nil && s.ResourceLimits.Pids == nil && s.ResourceLimits.BlockIO == nil && s.ResourceLimits.Memory == nil { + s.ResourceLimits = nil } if s.LogConfiguration == nil { @@ -344,15 +472,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string if ld := c.LogDriver; len(ld) > 0 { s.LogConfiguration.Driver = ld } - if s.ResourceLimits.Pids == nil { - s.ResourceLimits.Pids = &specs.LinuxPids{} - } - if c.PIDsLimit > 0 { - s.ResourceLimits.Pids.Limit = c.PIDsLimit - } - if c.CGroups == "disabled" && c.PIDsLimit > 0 { - s.ResourceLimits.Pids.Limit = -1 - } // TODO WTF //cgroup := &cc.CgroupConfig{ // Cgroups: c.String("cgroups"), @@ -458,32 +577,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string // quiet //DeviceCgroupRules: c.StringSlice("device-cgroup-rule"), - if bps := c.DeviceReadBPs; len(bps) > 0 { - if s.ThrottleReadBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { - return err - } - } - - if bps := c.DeviceWriteBPs; len(bps) > 0 { - if s.ThrottleWriteBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { - return err - } - } - - if iops := c.DeviceReadIOPs; len(iops) > 0 { - if s.ThrottleReadIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { - return err - } - } - - if iops := c.DeviceWriteIOPs; len(iops) > 0 { - if s.ThrottleWriteIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { - return err - } - } - - s.ResourceLimits.Memory.DisableOOMKiller = &c.OOMKillDisable - // Rlimits/Ulimits for _, u := range c.Ulimit { if u == "host" { @@ -518,35 +611,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.LogConfiguration.Options = logOpts s.Name = c.Name - if err := parseWeightDevices(c.BlkIOWeightDevice, s); err != nil { - return err - } - - if s.ResourceLimits.CPU == nil { - s.ResourceLimits.CPU = &specs.LinuxCPU{} - } - if c.CPUShares > 0 { - s.ResourceLimits.CPU.Shares = &c.CPUShares - } - if c.CPUPeriod > 0 { - s.ResourceLimits.CPU.Period = &c.CPUPeriod - } - - if c.CPUSetCPUs != "" { - s.ResourceLimits.CPU.Cpus = c.CPUSetCPUs - } - if c.CPUSetMems != "" { - s.ResourceLimits.CPU.Mems = c.CPUSetMems - } - if c.CPUQuota > 0 { - s.ResourceLimits.CPU.Quota = &c.CPUQuota - } - if c.CPURTPeriod > 0 { - s.ResourceLimits.CPU.RealtimePeriod = &c.CPURTPeriod - } - if c.CPURTRuntime > 0 { - s.ResourceLimits.CPU.RealtimeRuntime = &c.CPURTRuntime - } s.OOMScoreAdj = &c.OOMScoreAdj s.RestartPolicy = c.Restart s.Remove = c.Rm diff --git a/cmd/podman/containers/attach.go b/cmd/podman/containers/attach.go index b87fab5ef..78b52ad1b 100644 --- a/cmd/podman/containers/attach.go +++ b/cmd/podman/containers/attach.go @@ -43,23 +43,6 @@ var ( attachOpts entities.AttachOptions ) -func init() { - registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode}, - Command: attachCommand, - }) - flags := attachCommand.Flags() - attachFlags(flags) - - registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode}, - Command: containerAttachCommand, - Parent: containerCmd, - }) - containerAttachFlags := containerAttachCommand.Flags() - attachFlags(containerAttachFlags) -} - func attachFlags(flags *pflag.FlagSet) { flags.StringVar(&attachOpts.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`") flags.BoolVar(&attachOpts.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false") diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go index 69e343f59..137e486eb 100644 --- a/cmd/podman/containers/commit.go +++ b/cmd/podman/containers/commit.go @@ -72,7 +72,7 @@ func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, - Command: containerAttachCommand, + Command: containerCommitCommand, Parent: containerCmd, }) containerCommitFlags := containerCommitCommand.Flags() diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go new file mode 100644 index 000000000..f0f9a158d --- /dev/null +++ b/cmd/podman/containers/cp.go @@ -0,0 +1,55 @@ +package containers + +import ( + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/rootless" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + cpDescription = `Command copies the contents of SRC_PATH to the DEST_PATH. + + You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container. If "-" is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT. The CONTAINER can be a running or stopped container. The SRC_PATH or DEST_PATH can be a file or directory. +` + cpCommand = &cobra.Command{ + Use: "cp [flags] SRC_PATH DEST_PATH", + Short: "Copy files/folders between a container and the local filesystem", + Long: cpDescription, + Args: cobra.ExactArgs(2), + RunE: cp, + Example: "podman cp [CONTAINER:]SRC_PATH [CONTAINER:]DEST_PATH", + } +) + +var ( + cpOpts entities.ContainerCpOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: cpCommand, + }) + flags := cpCommand.Flags() + flags.BoolVar(&cpOpts.Extract, "extract", false, "Extract the tar file into the destination directory.") + flags.BoolVar(&cpOpts.Pause, "pause", copyPause(), "Pause the container while copying") +} + +func cp(cmd *cobra.Command, args []string) error { + _, err := registry.ContainerEngine().ContainerCp(registry.GetContext(), args[0], args[1], cpOpts) + return err +} + +func copyPause() bool { + if rootless.IsRootless() { + cgroupv2, _ := cgroups.IsCgroup2UnifiedMode() + if !cgroupv2 { + logrus.Debugf("defaulting to pause==false on rootless cp in cgroupv1 systems") + return false + } + } + return true +} diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index ffad26fe9..06b89b0fc 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -34,8 +34,8 @@ var ( Long: runCommand.Long, RunE: runCommand.RunE, Example: `podman container run imageID ls -alF /etc - podman container run --network=host imageID dnf -y install java - podman container run --volume /var/hostdir:/var/ctrdir -i -t fedora /bin/bash`, + podman container run --network=host imageID dnf -y install java + podman container run --volume /var/hostdir:/var/ctrdir -i -t fedora /bin/bash`, } ) diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go index a321b130e..73f37e51f 100644 --- a/cmd/podman/containers/start.go +++ b/cmd/podman/containers/start.go @@ -66,7 +66,7 @@ func init() { Parent: containerCmd, }) - containerStartFlags := containerRunCommand.Flags() + containerStartFlags := containerStartCommand.Flags() startFlags(containerStartFlags) } diff --git a/cmd/podman/login.go b/cmd/podman/login.go new file mode 100644 index 000000000..1843a764d --- /dev/null +++ b/cmd/podman/login.go @@ -0,0 +1,68 @@ +package main + +import ( + "context" + "os" + + "github.com/containers/common/pkg/auth" + "github.com/containers/image/v5/types" + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/spf13/cobra" +) + +type loginOptionsWrapper struct { + auth.LoginOptions + tlsVerify bool +} + +var ( + loginOptions = loginOptionsWrapper{} + loginCommand = &cobra.Command{ + Use: "login [flags] REGISTRY", + Short: "Login to a container registry", + Long: "Login to a container registry on a specified server.", + RunE: login, + Args: cobra.ExactArgs(1), + Example: `podman login quay.io + podman login --username ... --password ... quay.io + podman login --authfile dir/auth.json quay.io`, + } +) + +func init() { + // Note that the local and the remote client behave the same: both + // store credentials locally while the remote client will pass them + // over the wire to the endpoint. + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: loginCommand, + }) + flags := loginCommand.Flags() + + // Flags from the auth package. + flags.AddFlagSet(auth.GetLoginFlags(&loginOptions.LoginOptions)) + + // Podman flags. + flags.BoolVarP(&loginOptions.tlsVerify, "tls-verify", "", false, "Require HTTPS and verify certificates when contacting registries") + flags.BoolVarP(&loginOptions.GetLoginSet, "get-login", "", false, "Return the current login user for the registry") + loginOptions.Stdin = os.Stdin + loginOptions.Stdout = os.Stdout +} + +// Implementation of podman-login. +func login(cmd *cobra.Command, args []string) error { + var skipTLS types.OptionalBool + + if cmd.Flags().Changed("tls-verify") { + skipTLS = types.NewOptionalBool(!loginOptions.tlsVerify) + } + + sysCtx := types.SystemContext{ + AuthFilePath: loginOptions.AuthFile, + DockerCertPath: loginOptions.CertDir, + DockerInsecureSkipTLSVerify: skipTLS, + } + + return auth.Login(context.Background(), &sysCtx, &loginOptions.LoginOptions, args[0]) +} diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go new file mode 100644 index 000000000..77bdc92b4 --- /dev/null +++ b/cmd/podman/logout.go @@ -0,0 +1,57 @@ +package main + +import ( + "os" + + "github.com/containers/common/pkg/auth" + "github.com/containers/image/v5/types" + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + logoutOptions = auth.LogoutOptions{} + logoutCommand = &cobra.Command{ + Use: "logout [flags] REGISTRY", + Short: "Logout of a container registry", + Long: "Remove the cached username and password for the registry.", + RunE: logout, + Args: cobra.MaximumNArgs(1), + Example: `podman logout quay.io + podman logout --authfile dir/auth.json quay.io + podman logout --all`, + } +) + +func init() { + // Note that the local and the remote client behave the same: both + // store credentials locally while the remote client will pass them + // over the wire to the endpoint. + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: logoutCommand, + }) + flags := logoutCommand.Flags() + + // Flags from the auth package. + flags.AddFlagSet(auth.GetLogoutFlags(&logoutOptions)) + logoutOptions.Stdin = os.Stdin + logoutOptions.Stdout = os.Stdout +} + +// Implementation of podman-logout. +func logout(cmd *cobra.Command, args []string) error { + sysCtx := types.SystemContext{AuthFilePath: logoutOptions.AuthFile} + + registry := "" + if len(args) > 0 { + if logoutOptions.All { + return errors.New("--all takes no arguments") + } + registry = args[0] + } + + return auth.Logout(&sysCtx, &logoutOptions, registry) +} |