mirror of
https://github.com/containers/podman.git
synced 2025-05-25 19:16:59 +08:00
Update podman to use containers.conf
Add more default options parsing Switch to using --time as opposed to --timeout to better match Docker. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -51,12 +51,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.CGroupsNS,
|
||||
"cgroupns", getDefaultCgroupNS(),
|
||||
"cgroupns", containerConfig.CgroupNS(),
|
||||
"cgroup namespace to use",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.CGroups,
|
||||
"cgroups", "enabled",
|
||||
"cgroups", containerConfig.Cgroups(),
|
||||
`control container cgroup configuration ("enabled"|"disabled"|"no-conmon")`,
|
||||
)
|
||||
createFlags.StringVar(
|
||||
@ -121,12 +121,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.DetachKeys,
|
||||
"detach-keys", GetDefaultDetachKeys(),
|
||||
"detach-keys", containerConfig.DetachKeys(),
|
||||
"Override 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-cf`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`",
|
||||
)
|
||||
createFlags.StringSliceVar(
|
||||
&cf.Device,
|
||||
"device", getDefaultDevices(),
|
||||
"device", containerConfig.Devices(),
|
||||
fmt.Sprintf("Add a host device to the container"),
|
||||
)
|
||||
createFlags.StringSliceVar(
|
||||
@ -161,7 +161,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringArrayVarP(
|
||||
&cf.env,
|
||||
"env", "e", getDefaultEnv(),
|
||||
"env", "e", containerConfig.Env(),
|
||||
"Set environment variables in container",
|
||||
)
|
||||
createFlags.BoolVar(
|
||||
@ -238,7 +238,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.InitPath,
|
||||
"init-path", getDefaultInitPath(),
|
||||
"init-path", containerConfig.InitPath(),
|
||||
// Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
|
||||
fmt.Sprintf("Path to the container-init binary"),
|
||||
)
|
||||
@ -249,7 +249,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.IPC,
|
||||
"ipc", getDefaultIPCNS(),
|
||||
"ipc", containerConfig.IPCNS(),
|
||||
"IPC namespace to use",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
@ -331,13 +331,13 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
// markFlagHidden(createFlags, "override-os")
|
||||
createFlags.StringVar(
|
||||
&cf.PID,
|
||||
"pid", getDefaultPidNS(),
|
||||
"pid", containerConfig.PidNS(),
|
||||
"PID namespace to use",
|
||||
)
|
||||
createFlags.Int64Var(
|
||||
&cf.PIDsLimit,
|
||||
"pids-limit", getDefaultPidsLimit(),
|
||||
getDefaultPidsDescription(),
|
||||
"pids-limit", containerConfig.PidsLimit(),
|
||||
"Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.Pod,
|
||||
@ -391,12 +391,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringArrayVar(
|
||||
&cf.SecurityOpt,
|
||||
"security-opt", getDefaultSecurityOptions(),
|
||||
"security-opt", containerConfig.SecurityOptions(),
|
||||
"Security Options",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.ShmSize,
|
||||
"shm-size", getDefaultShmSize(),
|
||||
"shm-size", containerConfig.ShmSize(),
|
||||
"Size of /dev/shm "+sizeWithUnitFormat,
|
||||
)
|
||||
createFlags.StringVar(
|
||||
@ -427,7 +427,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
|
||||
createFlags.StringSliceVar(
|
||||
&cf.Sysctl,
|
||||
"sysctl", getDefaultSysctls(),
|
||||
"sysctl", containerConfig.Sysctls(),
|
||||
"Sysctl options",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
@ -452,7 +452,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringSliceVar(
|
||||
&cf.Ulimit,
|
||||
"ulimit", getDefaultUlimits(),
|
||||
"ulimit", containerConfig.Ulimits(),
|
||||
"Ulimit options",
|
||||
)
|
||||
createFlags.StringVarP(
|
||||
@ -462,12 +462,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.UserNS,
|
||||
"userns", getDefaultUserNS(),
|
||||
"userns", containerConfig.Containers.UserNS,
|
||||
"User namespace to use",
|
||||
)
|
||||
createFlags.StringVar(
|
||||
&cf.UTS,
|
||||
"uts", getDefaultUTSNS(),
|
||||
"uts", containerConfig.Containers.UTSNS,
|
||||
"UTS namespace to use",
|
||||
)
|
||||
createFlags.StringArrayVar(
|
||||
@ -477,7 +477,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||
)
|
||||
createFlags.StringArrayVarP(
|
||||
&cf.Volume,
|
||||
"volume", "v", getDefaultVolumes(),
|
||||
"volume", "v", containerConfig.Volumes(),
|
||||
"Bind mount a volume into the container",
|
||||
)
|
||||
createFlags.StringSliceVar(
|
||||
|
@ -1,18 +1,5 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/buildah/pkg/parse"
|
||||
"github.com/containers/libpod/pkg/apparmor"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/specgen"
|
||||
"github.com/containers/libpod/pkg/sysinfo"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultHealthCheckInterval default value
|
||||
DefaultHealthCheckInterval = "30s"
|
||||
@ -25,111 +12,3 @@ var (
|
||||
// DefaultImageVolume default value
|
||||
DefaultImageVolume = "bind"
|
||||
)
|
||||
|
||||
// TODO these options are directly embedded into many of the CLI cobra values, as such
|
||||
// this approach will not work in a remote client. so we will need to likely do something like a
|
||||
// supported and unsupported approach here and backload these options into the specgen
|
||||
// once we are "on" the host system.
|
||||
func getDefaultSecurityOptions() []string {
|
||||
securityOpts := []string{}
|
||||
if containerConfig.Containers.SeccompProfile != "" && containerConfig.Containers.SeccompProfile != parse.SeccompDefaultPath {
|
||||
securityOpts = append(securityOpts, fmt.Sprintf("seccomp=%s", containerConfig.Containers.SeccompProfile))
|
||||
}
|
||||
if apparmor.IsEnabled() && containerConfig.Containers.ApparmorProfile != "" {
|
||||
securityOpts = append(securityOpts, fmt.Sprintf("apparmor=%s", containerConfig.Containers.ApparmorProfile))
|
||||
}
|
||||
if selinux.GetEnabled() && !containerConfig.Containers.EnableLabeling {
|
||||
securityOpts = append(securityOpts, fmt.Sprintf("label=%s", selinux.DisableSecOpt()[0]))
|
||||
}
|
||||
return securityOpts
|
||||
}
|
||||
|
||||
// getDefaultSysctls
|
||||
func getDefaultSysctls() []string {
|
||||
return containerConfig.Containers.DefaultSysctls
|
||||
}
|
||||
|
||||
func getDefaultVolumes() []string {
|
||||
return containerConfig.Containers.Volumes
|
||||
}
|
||||
|
||||
func getDefaultDevices() []string {
|
||||
return containerConfig.Containers.Devices
|
||||
}
|
||||
|
||||
func getDefaultDNSServers() []string { //nolint
|
||||
return containerConfig.Containers.DNSServers
|
||||
}
|
||||
|
||||
func getDefaultDNSSearches() []string { //nolint
|
||||
return containerConfig.Containers.DNSSearches
|
||||
}
|
||||
|
||||
func getDefaultDNSOptions() []string { //nolint
|
||||
return containerConfig.Containers.DNSOptions
|
||||
}
|
||||
|
||||
func getDefaultEnv() []string {
|
||||
return containerConfig.Containers.Env
|
||||
}
|
||||
|
||||
func getDefaultInitPath() string {
|
||||
return containerConfig.Containers.InitPath
|
||||
}
|
||||
|
||||
func getDefaultIPCNS() string {
|
||||
return containerConfig.Containers.IPCNS
|
||||
}
|
||||
|
||||
func getDefaultPidNS() string {
|
||||
return containerConfig.Containers.PidNS
|
||||
}
|
||||
|
||||
func getDefaultNetNS() string { //nolint
|
||||
if containerConfig.Containers.NetNS == string(specgen.Private) && rootless.IsRootless() {
|
||||
return string(specgen.Slirp)
|
||||
}
|
||||
return containerConfig.Containers.NetNS
|
||||
}
|
||||
|
||||
func getDefaultCgroupNS() string {
|
||||
return containerConfig.Containers.CgroupNS
|
||||
}
|
||||
|
||||
func getDefaultUTSNS() string {
|
||||
return containerConfig.Containers.UTSNS
|
||||
}
|
||||
|
||||
func getDefaultShmSize() string {
|
||||
return containerConfig.Containers.ShmSize
|
||||
}
|
||||
|
||||
func getDefaultUlimits() []string {
|
||||
return containerConfig.Containers.DefaultUlimits
|
||||
}
|
||||
|
||||
func getDefaultUserNS() string {
|
||||
userns := os.Getenv("PODMAN_USERNS")
|
||||
if userns != "" {
|
||||
return userns
|
||||
}
|
||||
return containerConfig.Containers.UserNS
|
||||
}
|
||||
|
||||
func getDefaultPidsLimit() int64 {
|
||||
if rootless.IsRootless() {
|
||||
cgroup2, _ := cgroups.IsCgroup2UnifiedMode()
|
||||
if cgroup2 {
|
||||
return containerConfig.Containers.PidsLimit
|
||||
}
|
||||
}
|
||||
return sysinfo.GetDefaultPidsLimit()
|
||||
}
|
||||
|
||||
func getDefaultPidsDescription() string {
|
||||
return "Tune container pids limit (set 0 for unlimited)"
|
||||
}
|
||||
|
||||
func GetDefaultDetachKeys() string {
|
||||
return containerConfig.Engine.DetachKeys
|
||||
}
|
||||
|
@ -15,15 +15,15 @@ func GetNetFlags() *pflag.FlagSet {
|
||||
"Add a custom host-to-IP mapping (host:ip) (default [])",
|
||||
)
|
||||
netFlags.StringSlice(
|
||||
"dns", getDefaultDNSServers(),
|
||||
"dns", containerConfig.DNSServers(),
|
||||
"Set custom DNS servers",
|
||||
)
|
||||
netFlags.StringSlice(
|
||||
"dns-opt", getDefaultDNSOptions(),
|
||||
"dns-opt", containerConfig.DNSOptions(),
|
||||
"Set custom DNS options",
|
||||
)
|
||||
netFlags.StringSlice(
|
||||
"dns-search", getDefaultDNSSearches(),
|
||||
"dns-search", containerConfig.DNSSearches(),
|
||||
"Set custom DNS search domains",
|
||||
)
|
||||
netFlags.String(
|
||||
@ -35,7 +35,7 @@ func GetNetFlags() *pflag.FlagSet {
|
||||
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
|
||||
)
|
||||
netFlags.String(
|
||||
"network", getDefaultNetNS(),
|
||||
"network", containerConfig.NetNS(),
|
||||
"Connect a container to a network",
|
||||
)
|
||||
netFlags.StringSliceP(
|
||||
|
@ -3,7 +3,6 @@ package containers
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/common"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
@ -39,7 +38,7 @@ func init() {
|
||||
Command: attachCommand,
|
||||
})
|
||||
flags := attachCommand.Flags()
|
||||
flags.StringVar(&attachOpts.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "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.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")
|
||||
flags.BoolVar(&attachOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
|
||||
flags.BoolVarP(&attachOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||
|
@ -1,12 +1,9 @@
|
||||
package containers
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -20,7 +17,7 @@ var (
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
|
||||
defaultContainerConfig = getDefaultContainerConfig()
|
||||
containerConfig = util.DefaultContainerConfig()
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -29,12 +26,3 @@ func init() {
|
||||
Command: containerCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func getDefaultContainerConfig() *config.Config {
|
||||
defaultContainerConfig, err := config.Default()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return defaultContainerConfig
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"os"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/common"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
envLib "github.com/containers/libpod/pkg/env"
|
||||
@ -38,7 +37,7 @@ func init() {
|
||||
})
|
||||
flags := execCommand.Flags()
|
||||
flags.SetInterspersed(false)
|
||||
flags.StringVar(&execOpts.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
|
||||
flags.StringVar(&execOpts.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
|
||||
flags.StringArrayVarP(&envInput, "env", "e", []string{}, "Set environment variables")
|
||||
flags.StringSliceVar(&envFile, "env-file", []string{}, "Read in a file of environment variables")
|
||||
flags.BoolVarP(&execOpts.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
var (
|
||||
restartDescription = fmt.Sprintf(`Restarts one or more running containers. The container ID or name can be used.
|
||||
|
||||
A timeout before forcibly stopping can be set, but defaults to %d seconds.`, defaultContainerConfig.Engine.StopTimeout)
|
||||
A timeout before forcibly stopping can be set, but defaults to %d seconds.`, containerConfig.Engine.StopTimeout)
|
||||
|
||||
restartCommand = &cobra.Command{
|
||||
Use: "restart [flags] CONTAINER [CONTAINER...]",
|
||||
@ -46,7 +46,7 @@ func init() {
|
||||
flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all non-running containers")
|
||||
flags.BoolVarP(&restartOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||
flags.BoolVar(&restartOptions.Running, "running", false, "Restart only running containers when --all is used")
|
||||
flags.UintVarP(&restartTimeout, "time", "t", defaultContainerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
||||
flags.UintVarP(&restartTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
||||
if registry.IsRemote() {
|
||||
_ = flags.MarkHidden("latest")
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/common"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/cmd/podman/utils"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
@ -38,7 +37,7 @@ func init() {
|
||||
})
|
||||
flags := startCommand.Flags()
|
||||
flags.BoolVarP(&startOptions.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
|
||||
flags.StringVar(&startOptions.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "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.StringVar(&startOptions.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.BoolVarP(&startOptions.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
|
||||
flags.BoolVarP(&startOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||
flags.BoolVar(&startOptions.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
var (
|
||||
stopDescription = fmt.Sprintf(`Stops one or more running containers. The container name or ID can be used.
|
||||
|
||||
A timeout to forcibly stop the container can also be set but defaults to %d seconds otherwise.`, defaultContainerConfig.Engine.StopTimeout)
|
||||
A timeout to forcibly stop the container can also be set but defaults to %d seconds otherwise.`, containerConfig.Engine.StopTimeout)
|
||||
stopCommand = &cobra.Command{
|
||||
Use: "stop [flags] CONTAINER [CONTAINER...]",
|
||||
Short: "Stop one or more containers",
|
||||
@ -44,7 +44,7 @@ func init() {
|
||||
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
|
||||
flags.StringArrayVarP(&stopOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
|
||||
flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||
flags.UintVarP(&stopTimeout, "time", "t", defaultContainerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
||||
flags.UintVarP(&stopTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
||||
|
||||
if registry.IsRemote() {
|
||||
_ = flags.MarkHidden("latest")
|
||||
@ -58,7 +58,7 @@ func stop(cmd *cobra.Command, args []string) error {
|
||||
var (
|
||||
errs utils.OutputErrors
|
||||
)
|
||||
stopOptions.Timeout = defaultContainerConfig.Engine.StopTimeout
|
||||
stopOptions.Timeout = containerConfig.Engine.StopTimeout
|
||||
if cmd.Flag("time").Changed {
|
||||
stopOptions.Timeout = stopTimeout
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"github.com/containers/libpod/cmd/podman/common"
|
||||
"github.com/containers/libpod/cmd/podman/parse"
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/errorhandling"
|
||||
"github.com/containers/libpod/pkg/specgen"
|
||||
@ -50,8 +49,8 @@ func init() {
|
||||
flags.AddFlagSet(common.GetNetFlags())
|
||||
flags.StringVar(&createOptions.CGroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
|
||||
flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
|
||||
flags.StringVar(&createOptions.InfraImage, "infra-image", define.DefaultInfraImage, "The image of the infra container to associate with the pod")
|
||||
flags.StringVar(&createOptions.InfraCommand, "infra-command", define.DefaultInfraCommand, "The command to run on the infra container when the pod is started")
|
||||
flags.StringVar(&createOptions.InfraImage, "infra-image", containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
|
||||
flags.StringVar(&createOptions.InfraCommand, "infra-command", containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
|
||||
flags.StringSliceVar(&labelFile, "label-file", []string{}, "Read in a line delimited file of labels")
|
||||
flags.StringSliceVarP(&labels, "label", "l", []string{}, "Set metadata on pod (default [])")
|
||||
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
|
||||
|
@ -3,6 +3,7 @@ package pods
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podman/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -15,6 +16,7 @@ var (
|
||||
TraverseChildren: true,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
containerConfig = util.DefaultContainerConfig()
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -47,11 +47,10 @@ func init() {
|
||||
flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running pods")
|
||||
flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified pod is missing")
|
||||
flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Stop the latest pod podman is aware of")
|
||||
flags.UintVarP(&timeout, "time", "t", 0, "Seconds to wait for pod stop before killing the container")
|
||||
flags.UintVarP(&timeout, "time", "t", containerConfig.Engine.StopTimeout, "Seconds to wait for pod stop before killing the container")
|
||||
if registry.IsRemote() {
|
||||
_ = flags.MarkHidden("latest")
|
||||
_ = flags.MarkHidden("ignore")
|
||||
|
||||
}
|
||||
flags.SetNormalizeFunc(utils.AliasFlags)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func init() {
|
||||
Parent: volumeCmd,
|
||||
})
|
||||
flags := createCommand.Flags()
|
||||
flags.StringVar(&createOpts.Driver, "driver", "", "Specify volume driver name (default local)")
|
||||
flags.StringVar(&createOpts.Driver, "driver", "local", "Specify volume driver name")
|
||||
flags.StringSliceVarP(&opts.Label, "label", "l", []string{}, "Set metadata for a volume (default [])")
|
||||
flags.StringArrayVarP(&opts.Opts, "opt", "o", []string{}, "Set driver specific options (default [])")
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ import (
|
||||
cnitypes "github.com/containernetworking/cni/pkg/types/current"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containers/buildah/pkg/secrets"
|
||||
"github.com/containers/common/pkg/apparmor"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/libpod/events"
|
||||
"github.com/containers/libpod/pkg/annotations"
|
||||
"github.com/containers/libpod/pkg/apparmor"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/criu"
|
||||
"github.com/containers/libpod/pkg/lookup"
|
||||
|
@ -6,10 +6,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultInfraImage to use for infra container
|
||||
DefaultInfraImage = "k8s.gcr.io/pause:3.2"
|
||||
// DefaultInfraCommand to be run in an infra container
|
||||
DefaultInfraCommand = "/pause"
|
||||
// DefaultSHMLockPath is the default path for SHM locks
|
||||
DefaultSHMLockPath = "/libpod_lock"
|
||||
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
|
||||
|
@ -46,12 +46,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
|
||||
return
|
||||
}
|
||||
defaultContainerConfig, err := runtime.GetConfig()
|
||||
containerConfig, err := runtime.GetConfig()
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "GetConfig()"))
|
||||
return
|
||||
}
|
||||
cc, err := makeCreateConfig(defaultContainerConfig, input, newImage)
|
||||
cc, err := makeCreateConfig(containerConfig, input, newImage)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()"))
|
||||
return
|
||||
@ -60,7 +60,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
utils.CreateContainer(r.Context(), w, runtime, &cc)
|
||||
}
|
||||
|
||||
func makeCreateConfig(defaultContainerConfig *config.Config, input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
|
||||
func makeCreateConfig(containerConfig *config.Config, input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
|
||||
var (
|
||||
err error
|
||||
init bool
|
||||
@ -81,7 +81,7 @@ func makeCreateConfig(defaultContainerConfig *config.Config, input handlers.Crea
|
||||
workDir = input.WorkingDir
|
||||
}
|
||||
|
||||
stopTimeout := defaultContainerConfig.Engine.StopTimeout
|
||||
stopTimeout := containerConfig.Engine.StopTimeout
|
||||
if input.StopTimeout != nil {
|
||||
stopTimeout = uint(*input.StopTimeout)
|
||||
}
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/common/pkg/sysinfo"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/pkg/api/handlers"
|
||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/sysinfo"
|
||||
docker "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/google/uuid"
|
||||
|
@ -1,19 +0,0 @@
|
||||
package apparmor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
libpodVersion "github.com/containers/libpod/version"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultLipodProfilePrefix is used for version-independent presence checks.
|
||||
DefaultLipodProfilePrefix = config.DefaultApparmorProfile
|
||||
// DefaultLibpodProfile is the name of default libpod AppArmor profile.
|
||||
DefaultLibpodProfile = DefaultLipodProfilePrefix + "-" + libpodVersion.Version
|
||||
// ErrApparmorUnsupported indicates that AppArmor support is not supported.
|
||||
ErrApparmorUnsupported = errors.New("AppArmor is not supported")
|
||||
// ErrApparmorRootless indicates that AppArmor support is not supported in rootless mode.
|
||||
ErrApparmorRootless = errors.New("AppArmor is not supported in rootless mode")
|
||||
)
|
@ -1,289 +0,0 @@
|
||||
// +build linux,apparmor
|
||||
|
||||
package apparmor
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// profileDirectory is the file store for apparmor profiles and macros.
|
||||
var profileDirectory = "/etc/apparmor.d"
|
||||
|
||||
// IsEnabled returns true if AppArmor is enabled on the host.
|
||||
func IsEnabled() bool {
|
||||
if rootless.IsRootless() {
|
||||
return false
|
||||
}
|
||||
return runcaa.IsEnabled()
|
||||
}
|
||||
|
||||
// profileData holds information about the given profile for generation.
|
||||
type profileData struct {
|
||||
// Name is profile name.
|
||||
Name string
|
||||
// Imports defines the apparmor functions to import, before defining the profile.
|
||||
Imports []string
|
||||
// InnerImports defines the apparmor functions to import in the profile.
|
||||
InnerImports []string
|
||||
// Version is the {major, minor, patch} version of apparmor_parser as a single number.
|
||||
Version int
|
||||
}
|
||||
|
||||
// generateDefault creates an apparmor profile from ProfileData.
|
||||
func (p *profileData) generateDefault(out io.Writer) error {
|
||||
compiled, err := template.New("apparmor_profile").Parse(libpodProfileTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if macroExists("tunables/global") {
|
||||
p.Imports = append(p.Imports, "#include <tunables/global>")
|
||||
} else {
|
||||
p.Imports = append(p.Imports, "@{PROC}=/proc/")
|
||||
}
|
||||
|
||||
if macroExists("abstractions/base") {
|
||||
p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
|
||||
}
|
||||
|
||||
ver, err := getAAParserVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Version = ver
|
||||
|
||||
return compiled.Execute(out, p)
|
||||
}
|
||||
|
||||
// macrosExists checks if the passed macro exists.
|
||||
func macroExists(m string) bool {
|
||||
_, err := os.Stat(path.Join(profileDirectory, m))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// InstallDefault generates a default profile and loads it into the kernel
|
||||
// using 'apparmor_parser'.
|
||||
func InstallDefault(name string) error {
|
||||
if rootless.IsRootless() {
|
||||
return ErrApparmorRootless
|
||||
}
|
||||
|
||||
p := profileData{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
cmd := exec.Command("apparmor_parser", "-Kr")
|
||||
pipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
if pipeErr := pipe.Close(); pipeErr != nil {
|
||||
logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := p.generateDefault(pipe); err != nil {
|
||||
if pipeErr := pipe.Close(); pipeErr != nil {
|
||||
logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
|
||||
}
|
||||
if cmdErr := cmd.Wait(); cmdErr != nil {
|
||||
logrus.Errorf("unable to wait for apparmor command: %q", cmdErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if pipeErr := pipe.Close(); pipeErr != nil {
|
||||
logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
|
||||
}
|
||||
return cmd.Wait()
|
||||
}
|
||||
|
||||
// DefaultContent returns the default profile content as byte slice. The
|
||||
// profile is named as the provided `name`. The function errors if the profile
|
||||
// generation fails.
|
||||
func DefaultContent(name string) ([]byte, error) {
|
||||
p := profileData{Name: name}
|
||||
var bytes bytes.Buffer
|
||||
if err := p.generateDefault(&bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.Bytes(), nil
|
||||
}
|
||||
|
||||
// IsLoaded checks if a profile with the given name has been loaded into the
|
||||
// kernel.
|
||||
func IsLoaded(name string) (bool, error) {
|
||||
if name != "" && rootless.IsRootless() {
|
||||
return false, errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
|
||||
}
|
||||
|
||||
file, err := os.Open("/sys/kernel/security/apparmor/profiles")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
r := bufio.NewReader(file)
|
||||
for {
|
||||
p, err := r.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.HasPrefix(p, name+" ") {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// execAAParser runs `apparmor_parser` with the passed arguments.
|
||||
func execAAParser(dir string, args ...string) (string, error) {
|
||||
c := exec.Command("apparmor_parser", args...)
|
||||
c.Dir = dir
|
||||
|
||||
output, err := c.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("running `%s %s` failed with output: %s\nerror: %v", c.Path, strings.Join(c.Args, " "), output, err)
|
||||
}
|
||||
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// getAAParserVersion returns the major and minor version of apparmor_parser.
|
||||
func getAAParserVersion() (int, error) {
|
||||
output, err := execAAParser("", "--version")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return parseAAParserVersion(output)
|
||||
}
|
||||
|
||||
// parseAAParserVersion parses the given `apparmor_parser --version` output and
|
||||
// returns the major and minor version number as an integer.
|
||||
func parseAAParserVersion(output string) (int, error) {
|
||||
// output is in the form of the following:
|
||||
// AppArmor parser version 2.9.1
|
||||
// Copyright (C) 1999-2008 Novell Inc.
|
||||
// Copyright 2009-2012 Canonical Ltd.
|
||||
lines := strings.SplitN(output, "\n", 2)
|
||||
words := strings.Split(lines[0], " ")
|
||||
version := words[len(words)-1]
|
||||
|
||||
// split by major minor version
|
||||
v := strings.Split(version, ".")
|
||||
if len(v) == 0 || len(v) > 3 {
|
||||
return -1, fmt.Errorf("parsing version failed for output: `%s`", output)
|
||||
}
|
||||
|
||||
// Default the versions to 0.
|
||||
var majorVersion, minorVersion, patchLevel int
|
||||
|
||||
majorVersion, err := strconv.Atoi(v[0])
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if len(v) > 1 {
|
||||
minorVersion, err = strconv.Atoi(v[1])
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
if len(v) > 2 {
|
||||
patchLevel, err = strconv.Atoi(v[2])
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
// major*10^5 + minor*10^3 + patch*10^0
|
||||
numericVersion := majorVersion*1e5 + minorVersion*1e3 + patchLevel
|
||||
return numericVersion, nil
|
||||
|
||||
}
|
||||
|
||||
// CheckProfileAndLoadDefault checks if the specified profile is loaded and
|
||||
// loads the DefaultLibpodProfile if the specified on is prefixed by
|
||||
// DefaultLipodProfilePrefix. This allows to always load and apply the latest
|
||||
// default AppArmor profile. Note that AppArmor requires root. If it's a
|
||||
// default profile, return DefaultLipodProfilePrefix, otherwise the specified
|
||||
// one.
|
||||
func CheckProfileAndLoadDefault(name string) (string, error) {
|
||||
if name == "unconfined" {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// AppArmor is not supported in rootless mode as it requires root
|
||||
// privileges. Return an error in case a specific profile is specified.
|
||||
if rootless.IsRootless() {
|
||||
if name != "" {
|
||||
return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
|
||||
} else {
|
||||
logrus.Debug("skipping loading default AppArmor profile (rootless mode)")
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
// Check if AppArmor is disabled and error out if a profile is to be set.
|
||||
if !runcaa.IsEnabled() {
|
||||
if name == "" {
|
||||
return "", nil
|
||||
} else {
|
||||
return "", fmt.Errorf("profile %q specified but AppArmor is disabled on the host", name)
|
||||
}
|
||||
}
|
||||
|
||||
// If the specified name is not empty or is not a default libpod one,
|
||||
// ignore it and return the name.
|
||||
if name != "" && !strings.HasPrefix(name, DefaultLipodProfilePrefix) {
|
||||
isLoaded, err := IsLoaded(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !isLoaded {
|
||||
return "", fmt.Errorf("AppArmor profile %q specified but not loaded", name)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
name = DefaultLibpodProfile
|
||||
// To avoid expensive redundant loads on each invocation, check
|
||||
// if it's loaded before installing it.
|
||||
isLoaded, err := IsLoaded(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !isLoaded {
|
||||
err = InstallDefault(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
logrus.Infof("successfully loaded AppAmor profile %q", name)
|
||||
} else {
|
||||
logrus.Infof("AppAmor profile %q is already loaded", name)
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// +build linux,apparmor
|
||||
|
||||
package apparmor
|
||||
|
||||
const libpodProfileTemplate = `
|
||||
{{range $value := .Imports}}
|
||||
{{$value}}
|
||||
{{end}}
|
||||
|
||||
profile {{.Name}} flags=(attach_disconnected,mediate_deleted) {
|
||||
{{range $value := .InnerImports}}
|
||||
{{$value}}
|
||||
{{end}}
|
||||
|
||||
network,
|
||||
capability,
|
||||
file,
|
||||
umount,
|
||||
|
||||
{{if ge .Version 208096}}
|
||||
# Allow signals from privileged profiles and from within the same profile
|
||||
signal (receive) peer=unconfined,
|
||||
signal (send,receive) peer={{.Name}},
|
||||
{{end}}
|
||||
|
||||
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
|
||||
# deny write to files not in /proc/<number>/** or /proc/sys/**
|
||||
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
|
||||
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
|
||||
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
|
||||
deny @{PROC}/sysrq-trigger rwklx,
|
||||
deny @{PROC}/kcore rwklx,
|
||||
|
||||
deny mount,
|
||||
|
||||
deny /sys/[^f]*/** wklx,
|
||||
deny /sys/f[^s]*/** wklx,
|
||||
deny /sys/fs/[^c]*/** wklx,
|
||||
deny /sys/fs/c[^g]*/** wklx,
|
||||
deny /sys/fs/cg[^r]*/** wklx,
|
||||
deny /sys/firmware/** rwklx,
|
||||
deny /sys/kernel/security/** rwklx,
|
||||
|
||||
{{if ge .Version 208095}}
|
||||
# suppress ptrace denials when using using 'ps' inside a container
|
||||
ptrace (trace,read) peer={{.Name}},
|
||||
{{end}}
|
||||
}
|
||||
`
|
@ -1,140 +0,0 @@
|
||||
// +build linux,apparmor
|
||||
|
||||
package apparmor
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type versionExpected struct {
|
||||
output string
|
||||
version int
|
||||
}
|
||||
|
||||
func TestParseAAParserVersion(t *testing.T) {
|
||||
if !IsEnabled() {
|
||||
t.Skip("AppArmor disabled: skipping tests")
|
||||
}
|
||||
versions := []versionExpected{
|
||||
{
|
||||
output: `AppArmor parser version 2.10
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 210000,
|
||||
},
|
||||
{
|
||||
output: `AppArmor parser version 2.8
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 208000,
|
||||
},
|
||||
{
|
||||
output: `AppArmor parser version 2.20
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 220000,
|
||||
},
|
||||
{
|
||||
output: `AppArmor parser version 2.05
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 205000,
|
||||
},
|
||||
{
|
||||
output: `AppArmor parser version 2.9.95
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 209095,
|
||||
},
|
||||
{
|
||||
output: `AppArmor parser version 3.14.159
|
||||
Copyright (C) 1999-2008 Novell Inc.
|
||||
Copyright 2009-2012 Canonical Ltd.
|
||||
|
||||
`,
|
||||
version: 314159,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
version, err := parseAAParserVersion(v.output)
|
||||
if err != nil {
|
||||
t.Fatalf("expected error to be nil for %#v, got: %v", v, err)
|
||||
}
|
||||
if version != v.version {
|
||||
t.Fatalf("expected version to be %d, was %d, for: %#v\n", v.version, version, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
aapath = "/sys/kernel/security/apparmor/"
|
||||
profile = "libpod-default-testing"
|
||||
)
|
||||
|
||||
func TestInstallDefault(t *testing.T) {
|
||||
if _, err := os.Stat(aapath); err != nil {
|
||||
t.Skip("AppArmor isn't available in this environment")
|
||||
}
|
||||
|
||||
// removes `profile`
|
||||
removeProfile := func() error {
|
||||
path := aapath + ".remove"
|
||||
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(profile)
|
||||
return err
|
||||
}
|
||||
|
||||
// makes sure `profile` is loaded according to `state`
|
||||
checkLoaded := func(state bool) {
|
||||
loaded, err := IsLoaded(profile)
|
||||
if err != nil {
|
||||
t.Fatalf("Error searching AppArmor profile '%s': %v", profile, err)
|
||||
}
|
||||
if state != loaded {
|
||||
if state {
|
||||
t.Fatalf("AppArmor profile '%s' isn't loaded but should", profile)
|
||||
} else {
|
||||
t.Fatalf("AppArmor profile '%s' is loaded but shouldn't", profile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test installing the profile
|
||||
if err := InstallDefault(profile); err != nil {
|
||||
t.Fatalf("Couldn't install AppArmor profile '%s': %v", profile, err)
|
||||
}
|
||||
checkLoaded(true)
|
||||
|
||||
// remove the profile and check again
|
||||
if err := removeProfile(); err != nil {
|
||||
t.Fatalf("Couldn't remove AppArmor profile '%s': %v", profile, err)
|
||||
}
|
||||
checkLoaded(false)
|
||||
}
|
||||
|
||||
func TestDefaultContent(t *testing.T) {
|
||||
if _, err := os.Stat(aapath); err != nil {
|
||||
t.Skip("AppArmor isn't available in this environment")
|
||||
}
|
||||
if _, err := DefaultContent(profile); err != nil {
|
||||
t.Fatalf("Couldn't retrieve default AppArmor profile content '%s': %v", profile, err)
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// +build !linux !apparmor
|
||||
|
||||
package apparmor
|
||||
|
||||
// IsEnabled dummy.
|
||||
func IsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// InstallDefault dummy.
|
||||
func InstallDefault(name string) error {
|
||||
return ErrApparmorUnsupported
|
||||
}
|
||||
|
||||
// IsLoaded dummy.
|
||||
func IsLoaded(name string) (bool, error) {
|
||||
return false, ErrApparmorUnsupported
|
||||
}
|
||||
|
||||
// CheckProfileAndLoadDefault dummy.
|
||||
func CheckProfileAndLoadDefault(name string) (string, error) {
|
||||
if name == "" {
|
||||
return "", nil
|
||||
}
|
||||
return "", ErrApparmorUnsupported
|
||||
}
|
||||
|
||||
// DefaultContent dummy.
|
||||
func DefaultContent(name string) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
@ -5,11 +5,11 @@ import (
|
||||
|
||||
"github.com/containers/common/pkg/capabilities"
|
||||
cconfig "github.com/containers/common/pkg/config"
|
||||
"github.com/containers/common/pkg/sysinfo"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/env"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/sysinfo"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/common/pkg/sysinfo"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/sysinfo"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/docker/go-units"
|
||||
|
@ -1,14 +1,16 @@
|
||||
package specgen
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidPodSpecConfig describes an error given when the podspecgenerator is invalid
|
||||
ErrInvalidPodSpecConfig error = errors.New("invalid pod spec")
|
||||
// containerConfig has the default configurations defined in containers.conf
|
||||
containerConfig = util.DefaultContainerConfig()
|
||||
)
|
||||
|
||||
func exclusivePodOptions(opt1, opt2 string) error {
|
||||
@ -96,10 +98,10 @@ func (p *PodSpecGenerator) Validate() error {
|
||||
}
|
||||
}
|
||||
if len(p.InfraImage) < 1 {
|
||||
p.InfraImage = define.DefaultInfraImage
|
||||
p.InfraImage = containerConfig.Engine.InfraImage
|
||||
}
|
||||
if len(p.InfraCommand) < 1 {
|
||||
p.InfraCommand = []string{define.DefaultInfraCommand}
|
||||
p.InfraCommand = []string{containerConfig.Engine.InfraCommand}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
SysInfo stores information about which features a kernel supports.
|
@ -1,12 +0,0 @@
|
||||
// +build !linux,!windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// NumCPU returns the number of CPUs
|
||||
func NumCPU() int {
|
||||
return runtime.NumCPU()
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// numCPU queries the system for the count of threads available
|
||||
// for use to this process.
|
||||
//
|
||||
// Issues two syscalls.
|
||||
// Returns 0 on errors. Use |runtime.NumCPU| in that case.
|
||||
func numCPU() int {
|
||||
// Gets the affinity mask for a process: The very one invoking this function.
|
||||
pid, _, _ := unix.RawSyscall(unix.SYS_GETPID, 0, 0, 0)
|
||||
|
||||
var mask [1024 / 64]uintptr
|
||||
_, _, err := unix.RawSyscall(unix.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0])))
|
||||
if err != 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// For every available thread a bit is set in the mask.
|
||||
ncpu := 0
|
||||
for _, e := range mask {
|
||||
if e == 0 {
|
||||
continue
|
||||
}
|
||||
ncpu += int(popcnt(uint64(e)))
|
||||
}
|
||||
return ncpu
|
||||
}
|
||||
|
||||
// NumCPU returns the number of CPUs which are currently online
|
||||
func NumCPU() int {
|
||||
if ncpu := numCPU(); ncpu > 0 {
|
||||
return ncpu
|
||||
}
|
||||
return runtime.NumCPU()
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
getCurrentProcess = kernel32.NewProc("GetCurrentProcess")
|
||||
getProcessAffinityMask = kernel32.NewProc("GetProcessAffinityMask")
|
||||
)
|
||||
|
||||
func numCPU() int {
|
||||
// Gets the affinity mask for a process
|
||||
var mask, sysmask uintptr
|
||||
currentProcess, _, _ := getCurrentProcess.Call()
|
||||
ret, _, _ := getProcessAffinityMask.Call(currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
|
||||
if ret == 0 {
|
||||
return 0
|
||||
}
|
||||
// For every available thread a bit is set in the mask.
|
||||
ncpu := int(popcnt(uint64(mask)))
|
||||
return ncpu
|
||||
}
|
||||
|
||||
// NumCPU returns the number of CPUs which are currently online
|
||||
func NumCPU() int {
|
||||
if ncpu := numCPU(); ncpu > 0 {
|
||||
return ncpu
|
||||
}
|
||||
return runtime.NumCPU()
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import "github.com/docker/docker/pkg/parsers"
|
||||
|
||||
// SysInfo stores information about which features a kernel supports.
|
||||
// TODO Windows: Factor out platform specific capabilities.
|
||||
type SysInfo struct {
|
||||
// Whether the kernel supports AppArmor or not
|
||||
AppArmor bool
|
||||
// Whether the kernel supports Seccomp or not
|
||||
Seccomp bool
|
||||
|
||||
cgroupMemInfo
|
||||
cgroupCPUInfo
|
||||
cgroupBlkioInfo
|
||||
cgroupCpusetInfo
|
||||
cgroupPids
|
||||
|
||||
// Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work
|
||||
IPv4ForwardingDisabled bool
|
||||
|
||||
// Whether bridge-nf-call-iptables is supported or not
|
||||
BridgeNFCallIPTablesDisabled bool
|
||||
|
||||
// Whether bridge-nf-call-ip6tables is supported or not
|
||||
BridgeNFCallIP6TablesDisabled bool
|
||||
|
||||
// Whether the cgroup has the mountpoint of "devices" or not
|
||||
CgroupDevicesEnabled bool
|
||||
}
|
||||
|
||||
type cgroupMemInfo struct {
|
||||
// Whether memory limit is supported or not
|
||||
MemoryLimit bool
|
||||
|
||||
// Whether swap limit is supported or not
|
||||
SwapLimit bool
|
||||
|
||||
// Whether soft limit is supported or not
|
||||
MemoryReservation bool
|
||||
|
||||
// Whether OOM killer disable is supported or not
|
||||
OomKillDisable bool
|
||||
|
||||
// Whether memory swappiness is supported or not
|
||||
MemorySwappiness bool
|
||||
|
||||
// Whether kernel memory limit is supported or not
|
||||
KernelMemory bool
|
||||
}
|
||||
|
||||
type cgroupCPUInfo struct {
|
||||
// Whether CPU shares is supported or not
|
||||
CPUShares bool
|
||||
|
||||
// Whether CPU CFS(Completely Fair Scheduler) period is supported or not
|
||||
CPUCfsPeriod bool
|
||||
|
||||
// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
|
||||
CPUCfsQuota bool
|
||||
|
||||
// Whether CPU real-time period is supported or not
|
||||
CPURealtimePeriod bool
|
||||
|
||||
// Whether CPU real-time runtime is supported or not
|
||||
CPURealtimeRuntime bool
|
||||
}
|
||||
|
||||
type cgroupBlkioInfo struct {
|
||||
// Whether Block IO weight is supported or not
|
||||
BlkioWeight bool
|
||||
|
||||
// Whether Block IO weight_device is supported or not
|
||||
BlkioWeightDevice bool
|
||||
|
||||
// Whether Block IO read limit in bytes per second is supported or not
|
||||
BlkioReadBpsDevice bool
|
||||
|
||||
// Whether Block IO write limit in bytes per second is supported or not
|
||||
BlkioWriteBpsDevice bool
|
||||
|
||||
// Whether Block IO read limit in IO per second is supported or not
|
||||
BlkioReadIOpsDevice bool
|
||||
|
||||
// Whether Block IO write limit in IO per second is supported or not
|
||||
BlkioWriteIOpsDevice bool
|
||||
}
|
||||
|
||||
type cgroupCpusetInfo struct {
|
||||
// Whether Cpuset is supported or not
|
||||
Cpuset bool
|
||||
|
||||
// Available Cpuset's cpus
|
||||
Cpus string
|
||||
|
||||
// Available Cpuset's memory nodes
|
||||
Mems string
|
||||
}
|
||||
|
||||
type cgroupPids struct {
|
||||
// Whether Pids Limit is supported or not
|
||||
PidsLimit bool
|
||||
}
|
||||
|
||||
// IsCpusetCpusAvailable returns `true` if the provided string set is contained
|
||||
// in cgroup's cpuset.cpus set, `false` otherwise.
|
||||
// If error is not nil a parsing error occurred.
|
||||
func (c cgroupCpusetInfo) IsCpusetCpusAvailable(provided string) (bool, error) {
|
||||
return isCpusetListAvailable(provided, c.Cpus)
|
||||
}
|
||||
|
||||
// IsCpusetMemsAvailable returns `true` if the provided string set is contained
|
||||
// in cgroup's cpuset.mems set, `false` otherwise.
|
||||
// If error is not nil a parsing error occurred.
|
||||
func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
|
||||
return isCpusetListAvailable(provided, c.Mems)
|
||||
}
|
||||
|
||||
func isCpusetListAvailable(provided, available string) (bool, error) {
|
||||
parsedProvided, err := parsers.ParseUintList(provided)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
parsedAvailable, err := parsers.ParseUintList(available)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for k := range parsedProvided {
|
||||
if !parsedAvailable[k] {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Returns bit count of 1, used by NumCPU
|
||||
func popcnt(x uint64) (n byte) {
|
||||
x -= (x >> 1) & 0x5555555555555555
|
||||
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
|
||||
x += x >> 4
|
||||
x &= 0x0f0f0f0f0f0f0f0f
|
||||
x *= 0x0101010101010101
|
||||
return byte(x >> 56)
|
||||
}
|
||||
|
||||
// GetDefaultPidsLimit returns the default pids limit to run containers with
|
||||
func GetDefaultPidsLimit() int64 {
|
||||
sysInfo := New(true)
|
||||
if !sysInfo.PidsLimit {
|
||||
return 0
|
||||
}
|
||||
return 4096
|
||||
}
|
@ -1,261 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
cg "github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func findCgroupMountpoints() (map[string]string, error) {
|
||||
cgMounts, err := cgroups.GetCgroupMounts(false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse cgroup information: %v", err)
|
||||
}
|
||||
mps := make(map[string]string)
|
||||
for _, m := range cgMounts {
|
||||
for _, ss := range m.Subsystems {
|
||||
mps[ss] = m.Mountpoint
|
||||
}
|
||||
}
|
||||
return mps, nil
|
||||
}
|
||||
|
||||
// New returns a new SysInfo, using the filesystem to detect which features
|
||||
// the kernel supports. If `quiet` is `false` warnings are printed in logs
|
||||
// whenever an error occurs or misconfigurations are present.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
cgMounts, err := findCgroupMountpoints()
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to parse cgroup information: %v", err)
|
||||
} else {
|
||||
sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
|
||||
sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
|
||||
sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
|
||||
sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
|
||||
sysInfo.cgroupPids = checkCgroupPids(quiet)
|
||||
}
|
||||
|
||||
_, ok := cgMounts["devices"]
|
||||
sysInfo.CgroupDevicesEnabled = ok
|
||||
|
||||
sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
|
||||
sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
|
||||
sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
|
||||
|
||||
// Check if AppArmor is supported.
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
|
||||
sysInfo.AppArmor = true
|
||||
}
|
||||
|
||||
// Check if Seccomp is supported, via CONFIG_SECCOMP.
|
||||
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
|
||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
|
||||
sysInfo.Seccomp = true
|
||||
}
|
||||
}
|
||||
|
||||
return sysInfo
|
||||
}
|
||||
|
||||
// checkCgroupMem reads the memory information from the memory cgroup mount point.
|
||||
func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
|
||||
mountPoint, ok := cgMounts["memory"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Your kernel does not support cgroup memory limit")
|
||||
}
|
||||
return cgroupMemInfo{}
|
||||
}
|
||||
|
||||
swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
|
||||
if !quiet && !swapLimit {
|
||||
logrus.Warn("Your kernel does not support swap memory limit")
|
||||
}
|
||||
memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
|
||||
if !quiet && !memoryReservation {
|
||||
logrus.Warn("Your kernel does not support memory reservation")
|
||||
}
|
||||
oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
|
||||
if !quiet && !oomKillDisable {
|
||||
logrus.Warn("Your kernel does not support oom control")
|
||||
}
|
||||
memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
|
||||
if !quiet && !memorySwappiness {
|
||||
logrus.Warn("Your kernel does not support memory swappiness")
|
||||
}
|
||||
kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
|
||||
if !quiet && !kernelMemory {
|
||||
logrus.Warn("Your kernel does not support kernel memory limit")
|
||||
}
|
||||
|
||||
return cgroupMemInfo{
|
||||
MemoryLimit: true,
|
||||
SwapLimit: swapLimit,
|
||||
MemoryReservation: memoryReservation,
|
||||
OomKillDisable: oomKillDisable,
|
||||
MemorySwappiness: memorySwappiness,
|
||||
KernelMemory: kernelMemory,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
|
||||
func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
|
||||
mountPoint, ok := cgMounts["cpu"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find cpu cgroup in mounts")
|
||||
}
|
||||
return cgroupCPUInfo{}
|
||||
}
|
||||
|
||||
cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
|
||||
if !quiet && !cpuShares {
|
||||
logrus.Warn("Your kernel does not support cgroup cpu shares")
|
||||
}
|
||||
|
||||
cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
|
||||
if !quiet && !cpuCfsPeriod {
|
||||
logrus.Warn("Your kernel does not support cgroup cfs period")
|
||||
}
|
||||
|
||||
cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
|
||||
if !quiet && !cpuCfsQuota {
|
||||
logrus.Warn("Your kernel does not support cgroup cfs quotas")
|
||||
}
|
||||
|
||||
cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
|
||||
if !quiet && !cpuRealtimePeriod {
|
||||
logrus.Warn("Your kernel does not support cgroup rt period")
|
||||
}
|
||||
|
||||
cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
|
||||
if !quiet && !cpuRealtimeRuntime {
|
||||
logrus.Warn("Your kernel does not support cgroup rt runtime")
|
||||
}
|
||||
|
||||
return cgroupCPUInfo{
|
||||
CPUShares: cpuShares,
|
||||
CPUCfsPeriod: cpuCfsPeriod,
|
||||
CPUCfsQuota: cpuCfsQuota,
|
||||
CPURealtimePeriod: cpuRealtimePeriod,
|
||||
CPURealtimeRuntime: cpuRealtimeRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
|
||||
func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
|
||||
mountPoint, ok := cgMounts["blkio"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find blkio cgroup in mounts")
|
||||
}
|
||||
return cgroupBlkioInfo{}
|
||||
}
|
||||
|
||||
weight := cgroupEnabled(mountPoint, "blkio.weight")
|
||||
if !quiet && !weight {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio weight")
|
||||
}
|
||||
|
||||
weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
|
||||
if !quiet && !weightDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio weight_device")
|
||||
}
|
||||
|
||||
readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
|
||||
if !quiet && !readBpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
|
||||
}
|
||||
|
||||
writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
|
||||
if !quiet && !writeBpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
|
||||
}
|
||||
readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
|
||||
if !quiet && !readIOpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
|
||||
}
|
||||
|
||||
writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
|
||||
if !quiet && !writeIOpsDevice {
|
||||
logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
|
||||
}
|
||||
return cgroupBlkioInfo{
|
||||
BlkioWeight: weight,
|
||||
BlkioWeightDevice: weightDevice,
|
||||
BlkioReadBpsDevice: readBpsDevice,
|
||||
BlkioWriteBpsDevice: writeBpsDevice,
|
||||
BlkioReadIOpsDevice: readIOpsDevice,
|
||||
BlkioWriteIOpsDevice: writeIOpsDevice,
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
|
||||
func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
|
||||
mountPoint, ok := cgMounts["cpuset"]
|
||||
if !ok {
|
||||
if !quiet {
|
||||
logrus.Warn("Unable to find cpuset cgroup in mounts")
|
||||
}
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
|
||||
if err != nil {
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
|
||||
if err != nil {
|
||||
return cgroupCpusetInfo{}
|
||||
}
|
||||
|
||||
return cgroupCpusetInfo{
|
||||
Cpuset: true,
|
||||
Cpus: strings.TrimSpace(string(cpus)),
|
||||
Mems: strings.TrimSpace(string(mems)),
|
||||
}
|
||||
}
|
||||
|
||||
// checkCgroupPids reads the pids information from the pids cgroup mount point.
|
||||
func checkCgroupPids(quiet bool) cgroupPids {
|
||||
cgroup2, err := cg.IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to check cgroups version: %v", err)
|
||||
}
|
||||
if !cgroup2 {
|
||||
_, err := cgroups.FindCgroupMountpoint("", "pids")
|
||||
if err != nil {
|
||||
if !quiet {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
return cgroupPids{}
|
||||
}
|
||||
}
|
||||
|
||||
return cgroupPids{
|
||||
PidsLimit: true,
|
||||
}
|
||||
}
|
||||
|
||||
func cgroupEnabled(mountPoint, name string) bool {
|
||||
_, err := os.Stat(path.Join(mountPoint, name))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func readProcBool(path string) bool {
|
||||
val, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(val)) == "1"
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestReadProcBool(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "test-sysinfo-proc")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
procFile := filepath.Join(tmpDir, "read-proc-bool")
|
||||
err = ioutil.WriteFile(procFile, []byte("1"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
if !readProcBool(procFile) {
|
||||
t.Fatal("expected proc bool to be true, got false")
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(procFile, []byte("0"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if readProcBool(procFile) {
|
||||
t.Fatal("expected proc bool to be false, got true")
|
||||
}
|
||||
|
||||
if readProcBool(path.Join(tmpDir, "no-exist")) {
|
||||
t.Fatal("should be false for non-existent entry")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCgroupEnabled(t *testing.T) {
|
||||
cgroupDir, err := ioutil.TempDir("", "cgroup-test")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(cgroupDir)
|
||||
|
||||
if cgroupEnabled(cgroupDir, "test") {
|
||||
t.Fatal("cgroupEnabled should be false")
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path.Join(cgroupDir, "test"), []byte{}, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
if !cgroupEnabled(cgroupDir, "test") {
|
||||
t.Fatal("cgroupEnabled should be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
sysInfo := New(false)
|
||||
require.NotNil(t, sysInfo)
|
||||
checkSysInfo(t, sysInfo)
|
||||
|
||||
sysInfo = New(true)
|
||||
require.NotNil(t, sysInfo)
|
||||
checkSysInfo(t, sysInfo)
|
||||
}
|
||||
|
||||
func checkSysInfo(t *testing.T, sysInfo *SysInfo) {
|
||||
// Check if Seccomp is supported, via CONFIG_SECCOMP.then sysInfo.Seccomp must be TRUE , else FALSE
|
||||
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
|
||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
|
||||
require.True(t, sysInfo.Seccomp)
|
||||
}
|
||||
} else {
|
||||
require.False(t, sysInfo.Seccomp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAppArmorEnabled(t *testing.T) {
|
||||
// Check if AppArmor is supported. then it must be TRUE , else FALSE
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err != nil {
|
||||
t.Skip("App Armor Must be Enabled")
|
||||
}
|
||||
|
||||
sysInfo := New(true)
|
||||
require.True(t, sysInfo.AppArmor)
|
||||
}
|
||||
|
||||
func TestNewAppArmorDisabled(t *testing.T) {
|
||||
// Check if AppArmor is supported. then it must be TRUE , else FALSE
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
|
||||
t.Skip("App Armor Must be Disabled")
|
||||
}
|
||||
|
||||
sysInfo := New(true)
|
||||
require.False(t, sysInfo.AppArmor)
|
||||
}
|
||||
|
||||
func TestNumCPU(t *testing.T) {
|
||||
cpuNumbers := NumCPU()
|
||||
if cpuNumbers <= 0 {
|
||||
t.Fatal("CPU returned must be greater than zero")
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
// +build solaris,cgo
|
||||
|
||||
package sysinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -llgrp
|
||||
#cgo CFLAGS: -Wall -Werror
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/lgrp_user.h>
|
||||
int getLgrpCount() {
|
||||
lgrp_cookie_t lgrpcookie = LGRP_COOKIE_NONE;
|
||||
uint_t nlgrps;
|
||||
|
||||
if ((lgrpcookie = lgrp_init(LGRP_VIEW_OS)) == LGRP_COOKIE_NONE) {
|
||||
return -1;
|
||||
}
|
||||
nlgrps = lgrp_nlgrps(lgrpcookie);
|
||||
return nlgrps;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// IsCPUSharesAvailable returns whether CPUShares setting is supported.
|
||||
// We need FSS to be set as default scheduling class to support CPU Shares
|
||||
func IsCPUSharesAvailable() bool {
|
||||
cmd := exec.Command("/usr/sbin/dispadmin", "-d")
|
||||
outBuf := new(bytes.Buffer)
|
||||
errBuf := new(bytes.Buffer)
|
||||
cmd.Stderr = errBuf
|
||||
cmd.Stdout = outBuf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return (strings.Contains(outBuf.String(), "FSS"))
|
||||
}
|
||||
|
||||
// New returns a new SysInfo, using the filesystem to detect which features
|
||||
// the kernel supports.
|
||||
//NOTE Solaris: If we change the below capabilities be sure
|
||||
// to update verifyPlatformContainerSettings() in daemon_solaris.go
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
sysInfo.cgroupMemInfo = setCgroupMem(quiet)
|
||||
sysInfo.cgroupCPUInfo = setCgroupCPU(quiet)
|
||||
sysInfo.cgroupBlkioInfo = setCgroupBlkioInfo(quiet)
|
||||
sysInfo.cgroupCpusetInfo = setCgroupCPUsetInfo(quiet)
|
||||
|
||||
sysInfo.IPv4ForwardingDisabled = false
|
||||
|
||||
sysInfo.AppArmor = false
|
||||
|
||||
return sysInfo
|
||||
}
|
||||
|
||||
// setCgroupMem reads the memory information for Solaris.
|
||||
func setCgroupMem(quiet bool) cgroupMemInfo {
|
||||
|
||||
return cgroupMemInfo{
|
||||
MemoryLimit: true,
|
||||
SwapLimit: true,
|
||||
MemoryReservation: false,
|
||||
OomKillDisable: false,
|
||||
MemorySwappiness: false,
|
||||
KernelMemory: false,
|
||||
}
|
||||
}
|
||||
|
||||
// setCgroupCPU reads the cpu information for Solaris.
|
||||
func setCgroupCPU(quiet bool) cgroupCPUInfo {
|
||||
|
||||
return cgroupCPUInfo{
|
||||
CPUShares: true,
|
||||
CPUCfsPeriod: false,
|
||||
CPUCfsQuota: true,
|
||||
CPURealtimePeriod: false,
|
||||
CPURealtimeRuntime: false,
|
||||
}
|
||||
}
|
||||
|
||||
// blkio switches are not supported in Solaris.
|
||||
func setCgroupBlkioInfo(quiet bool) cgroupBlkioInfo {
|
||||
|
||||
return cgroupBlkioInfo{
|
||||
BlkioWeight: false,
|
||||
BlkioWeightDevice: false,
|
||||
}
|
||||
}
|
||||
|
||||
// setCgroupCPUsetInfo reads the cpuset information for Solaris.
|
||||
func setCgroupCPUsetInfo(quiet bool) cgroupCpusetInfo {
|
||||
|
||||
return cgroupCpusetInfo{
|
||||
Cpuset: true,
|
||||
Cpus: getCPUCount(),
|
||||
Mems: getLgrpCount(),
|
||||
}
|
||||
}
|
||||
|
||||
func getCPUCount() string {
|
||||
ncpus := C.sysconf(C._SC_NPROCESSORS_ONLN)
|
||||
if ncpus <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(int64(ncpus), 16)
|
||||
}
|
||||
|
||||
func getLgrpCount() string {
|
||||
nlgrps := C.getLgrpCount()
|
||||
if nlgrps <= 0 {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(int64(nlgrps), 16)
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package sysinfo
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIsCpusetListAvailable(t *testing.T) {
|
||||
cases := []struct {
|
||||
provided string
|
||||
available string
|
||||
res bool
|
||||
err bool
|
||||
}{
|
||||
{"1", "0-4", true, false},
|
||||
{"01,3", "0-4", true, false},
|
||||
{"", "0-7", true, false},
|
||||
{"1--42", "0-7", false, true},
|
||||
{"1-42", "00-1,8,,9", false, true},
|
||||
{"1,41-42", "43,45", false, false},
|
||||
{"0-3", "", false, false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
r, err := isCpusetListAvailable(c.provided, c.available)
|
||||
if (c.err && err == nil) && r != c.res {
|
||||
t.Fatalf("Expected pair: %v, %v for %s, %s. Got %v, %v instead", c.res, c.err, c.provided, c.available, c.err && err == nil, r)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// +build !linux,!solaris,!windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
// New returns an empty SysInfo for non linux nor solaris for now.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
return sysInfo
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package sysinfo
|
||||
|
||||
// New returns an empty SysInfo for windows for now.
|
||||
func New(quiet bool) *SysInfo {
|
||||
sysInfo := &SysInfo{}
|
||||
return sysInfo
|
||||
}
|
@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/libpod/pkg/errorhandling"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
@ -27,6 +28,17 @@ import (
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var containerConfig *config.Config
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
containerConfig, err = config.Default()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to determine the username/password passed
|
||||
// in the creds string. It could be either or both.
|
||||
func parseCreds(creds string) (string, string) {
|
||||
@ -669,3 +681,7 @@ func swapSELinuxLabel(cLabel, processLabel string) (string, error) {
|
||||
dcon["type"] = scon["type"]
|
||||
return dcon.Get(), nil
|
||||
}
|
||||
|
||||
func DefaultContainerConfig() *config.Config {
|
||||
return containerConfig
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/sysinfo"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/libpod/cmd/podman/parse"
|
||||
"github.com/containers/libpod/libpod"
|
||||
@ -28,7 +29,6 @@ import (
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/seccomp"
|
||||
cc "github.com/containers/libpod/pkg/spec"
|
||||
"github.com/containers/libpod/pkg/sysinfo"
|
||||
systemdGen "github.com/containers/libpod/pkg/systemd/generate"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/docker/go-connections/nat"
|
||||
|
@ -331,7 +331,7 @@ func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt {
|
||||
// structure.
|
||||
func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
|
||||
// FIXME this will need to be fixed!!!!! With containers conf
|
||||
//defaultContainerConfig := cliconfig.GetDefaultConfig()
|
||||
//containerConfig := cliconfig.GetDefaultConfig()
|
||||
// TODO | WARN
|
||||
// We do not get a default network over varlink. Unlike the other default values for some cli
|
||||
// elements, it seems it gets set to the default anyway.
|
||||
|
Reference in New Issue
Block a user