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(
|
createFlags.StringVar(
|
||||||
&cf.CGroupsNS,
|
&cf.CGroupsNS,
|
||||||
"cgroupns", getDefaultCgroupNS(),
|
"cgroupns", containerConfig.CgroupNS(),
|
||||||
"cgroup namespace to use",
|
"cgroup namespace to use",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.CGroups,
|
&cf.CGroups,
|
||||||
"cgroups", "enabled",
|
"cgroups", containerConfig.Cgroups(),
|
||||||
`control container cgroup configuration ("enabled"|"disabled"|"no-conmon")`,
|
`control container cgroup configuration ("enabled"|"disabled"|"no-conmon")`,
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
@ -121,12 +121,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.DetachKeys,
|
&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 `_`",
|
"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(
|
createFlags.StringSliceVar(
|
||||||
&cf.Device,
|
&cf.Device,
|
||||||
"device", getDefaultDevices(),
|
"device", containerConfig.Devices(),
|
||||||
fmt.Sprintf("Add a host device to the container"),
|
fmt.Sprintf("Add a host device to the container"),
|
||||||
)
|
)
|
||||||
createFlags.StringSliceVar(
|
createFlags.StringSliceVar(
|
||||||
@ -161,7 +161,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringArrayVarP(
|
createFlags.StringArrayVarP(
|
||||||
&cf.env,
|
&cf.env,
|
||||||
"env", "e", getDefaultEnv(),
|
"env", "e", containerConfig.Env(),
|
||||||
"Set environment variables in container",
|
"Set environment variables in container",
|
||||||
)
|
)
|
||||||
createFlags.BoolVar(
|
createFlags.BoolVar(
|
||||||
@ -238,7 +238,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.InitPath,
|
&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)
|
// 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"),
|
fmt.Sprintf("Path to the container-init binary"),
|
||||||
)
|
)
|
||||||
@ -249,7 +249,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.IPC,
|
&cf.IPC,
|
||||||
"ipc", getDefaultIPCNS(),
|
"ipc", containerConfig.IPCNS(),
|
||||||
"IPC namespace to use",
|
"IPC namespace to use",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
@ -331,13 +331,13 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
// markFlagHidden(createFlags, "override-os")
|
// markFlagHidden(createFlags, "override-os")
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.PID,
|
&cf.PID,
|
||||||
"pid", getDefaultPidNS(),
|
"pid", containerConfig.PidNS(),
|
||||||
"PID namespace to use",
|
"PID namespace to use",
|
||||||
)
|
)
|
||||||
createFlags.Int64Var(
|
createFlags.Int64Var(
|
||||||
&cf.PIDsLimit,
|
&cf.PIDsLimit,
|
||||||
"pids-limit", getDefaultPidsLimit(),
|
"pids-limit", containerConfig.PidsLimit(),
|
||||||
getDefaultPidsDescription(),
|
"Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.Pod,
|
&cf.Pod,
|
||||||
@ -391,12 +391,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringArrayVar(
|
createFlags.StringArrayVar(
|
||||||
&cf.SecurityOpt,
|
&cf.SecurityOpt,
|
||||||
"security-opt", getDefaultSecurityOptions(),
|
"security-opt", containerConfig.SecurityOptions(),
|
||||||
"Security Options",
|
"Security Options",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.ShmSize,
|
&cf.ShmSize,
|
||||||
"shm-size", getDefaultShmSize(),
|
"shm-size", containerConfig.ShmSize(),
|
||||||
"Size of /dev/shm "+sizeWithUnitFormat,
|
"Size of /dev/shm "+sizeWithUnitFormat,
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
@ -427,7 +427,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
|
|
||||||
createFlags.StringSliceVar(
|
createFlags.StringSliceVar(
|
||||||
&cf.Sysctl,
|
&cf.Sysctl,
|
||||||
"sysctl", getDefaultSysctls(),
|
"sysctl", containerConfig.Sysctls(),
|
||||||
"Sysctl options",
|
"Sysctl options",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
@ -452,7 +452,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringSliceVar(
|
createFlags.StringSliceVar(
|
||||||
&cf.Ulimit,
|
&cf.Ulimit,
|
||||||
"ulimit", getDefaultUlimits(),
|
"ulimit", containerConfig.Ulimits(),
|
||||||
"Ulimit options",
|
"Ulimit options",
|
||||||
)
|
)
|
||||||
createFlags.StringVarP(
|
createFlags.StringVarP(
|
||||||
@ -462,12 +462,12 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.UserNS,
|
&cf.UserNS,
|
||||||
"userns", getDefaultUserNS(),
|
"userns", containerConfig.Containers.UserNS,
|
||||||
"User namespace to use",
|
"User namespace to use",
|
||||||
)
|
)
|
||||||
createFlags.StringVar(
|
createFlags.StringVar(
|
||||||
&cf.UTS,
|
&cf.UTS,
|
||||||
"uts", getDefaultUTSNS(),
|
"uts", containerConfig.Containers.UTSNS,
|
||||||
"UTS namespace to use",
|
"UTS namespace to use",
|
||||||
)
|
)
|
||||||
createFlags.StringArrayVar(
|
createFlags.StringArrayVar(
|
||||||
@ -477,7 +477,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
)
|
)
|
||||||
createFlags.StringArrayVarP(
|
createFlags.StringArrayVarP(
|
||||||
&cf.Volume,
|
&cf.Volume,
|
||||||
"volume", "v", getDefaultVolumes(),
|
"volume", "v", containerConfig.Volumes(),
|
||||||
"Bind mount a volume into the container",
|
"Bind mount a volume into the container",
|
||||||
)
|
)
|
||||||
createFlags.StringSliceVar(
|
createFlags.StringSliceVar(
|
||||||
|
@ -1,18 +1,5 @@
|
|||||||
package common
|
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 (
|
var (
|
||||||
// DefaultHealthCheckInterval default value
|
// DefaultHealthCheckInterval default value
|
||||||
DefaultHealthCheckInterval = "30s"
|
DefaultHealthCheckInterval = "30s"
|
||||||
@ -25,111 +12,3 @@ var (
|
|||||||
// DefaultImageVolume default value
|
// DefaultImageVolume default value
|
||||||
DefaultImageVolume = "bind"
|
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 [])",
|
"Add a custom host-to-IP mapping (host:ip) (default [])",
|
||||||
)
|
)
|
||||||
netFlags.StringSlice(
|
netFlags.StringSlice(
|
||||||
"dns", getDefaultDNSServers(),
|
"dns", containerConfig.DNSServers(),
|
||||||
"Set custom DNS servers",
|
"Set custom DNS servers",
|
||||||
)
|
)
|
||||||
netFlags.StringSlice(
|
netFlags.StringSlice(
|
||||||
"dns-opt", getDefaultDNSOptions(),
|
"dns-opt", containerConfig.DNSOptions(),
|
||||||
"Set custom DNS options",
|
"Set custom DNS options",
|
||||||
)
|
)
|
||||||
netFlags.StringSlice(
|
netFlags.StringSlice(
|
||||||
"dns-search", getDefaultDNSSearches(),
|
"dns-search", containerConfig.DNSSearches(),
|
||||||
"Set custom DNS search domains",
|
"Set custom DNS search domains",
|
||||||
)
|
)
|
||||||
netFlags.String(
|
netFlags.String(
|
||||||
@ -35,7 +35,7 @@ func GetNetFlags() *pflag.FlagSet {
|
|||||||
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
|
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
|
||||||
)
|
)
|
||||||
netFlags.String(
|
netFlags.String(
|
||||||
"network", getDefaultNetNS(),
|
"network", containerConfig.NetNS(),
|
||||||
"Connect a container to a network",
|
"Connect a container to a network",
|
||||||
)
|
)
|
||||||
netFlags.StringSliceP(
|
netFlags.StringSliceP(
|
||||||
|
@ -3,7 +3,6 @@ package containers
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/common"
|
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -39,7 +38,7 @@ func init() {
|
|||||||
Command: attachCommand,
|
Command: attachCommand,
|
||||||
})
|
})
|
||||||
flags := attachCommand.Flags()
|
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.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.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")
|
flags.BoolVarP(&attachOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package containers
|
package containers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,7 +17,7 @@ var (
|
|||||||
RunE: registry.SubCommandExists,
|
RunE: registry.SubCommandExists,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultContainerConfig = getDefaultContainerConfig()
|
containerConfig = util.DefaultContainerConfig()
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -29,12 +26,3 @@ func init() {
|
|||||||
Command: containerCmd,
|
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"
|
"bufio"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/common"
|
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
envLib "github.com/containers/libpod/pkg/env"
|
envLib "github.com/containers/libpod/pkg/env"
|
||||||
@ -38,7 +37,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
flags := execCommand.Flags()
|
flags := execCommand.Flags()
|
||||||
flags.SetInterspersed(false)
|
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.StringArrayVarP(&envInput, "env", "e", []string{}, "Set environment variables")
|
||||||
flags.StringSliceVar(&envFile, "env-file", []string{}, "Read in a file of 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")
|
flags.BoolVarP(&execOpts.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
restartDescription = fmt.Sprintf(`Restarts one or more running containers. The container ID or name can be used.
|
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{
|
restartCommand = &cobra.Command{
|
||||||
Use: "restart [flags] CONTAINER [CONTAINER...]",
|
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.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.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.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() {
|
if registry.IsRemote() {
|
||||||
_ = flags.MarkHidden("latest")
|
_ = flags.MarkHidden("latest")
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/common"
|
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
"github.com/containers/libpod/cmd/podman/utils"
|
"github.com/containers/libpod/cmd/podman/utils"
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
@ -38,7 +37,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
flags := startCommand.Flags()
|
flags := startCommand.Flags()
|
||||||
flags.BoolVarP(&startOptions.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR")
|
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.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.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)")
|
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 (
|
var (
|
||||||
stopDescription = fmt.Sprintf(`Stops one or more running containers. The container name or ID can be used.
|
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{
|
stopCommand = &cobra.Command{
|
||||||
Use: "stop [flags] CONTAINER [CONTAINER...]",
|
Use: "stop [flags] CONTAINER [CONTAINER...]",
|
||||||
Short: "Stop one or more containers",
|
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.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.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.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() {
|
if registry.IsRemote() {
|
||||||
_ = flags.MarkHidden("latest")
|
_ = flags.MarkHidden("latest")
|
||||||
@ -58,7 +58,7 @@ func stop(cmd *cobra.Command, args []string) error {
|
|||||||
var (
|
var (
|
||||||
errs utils.OutputErrors
|
errs utils.OutputErrors
|
||||||
)
|
)
|
||||||
stopOptions.Timeout = defaultContainerConfig.Engine.StopTimeout
|
stopOptions.Timeout = containerConfig.Engine.StopTimeout
|
||||||
if cmd.Flag("time").Changed {
|
if cmd.Flag("time").Changed {
|
||||||
stopOptions.Timeout = stopTimeout
|
stopOptions.Timeout = stopTimeout
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/containers/libpod/cmd/podman/common"
|
"github.com/containers/libpod/cmd/podman/common"
|
||||||
"github.com/containers/libpod/cmd/podman/parse"
|
"github.com/containers/libpod/cmd/podman/parse"
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"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/domain/entities"
|
||||||
"github.com/containers/libpod/pkg/errorhandling"
|
"github.com/containers/libpod/pkg/errorhandling"
|
||||||
"github.com/containers/libpod/pkg/specgen"
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
@ -50,8 +49,8 @@ func init() {
|
|||||||
flags.AddFlagSet(common.GetNetFlags())
|
flags.AddFlagSet(common.GetNetFlags())
|
||||||
flags.StringVar(&createOptions.CGroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
|
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.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.InfraImage, "infra-image", containerConfig.Engine.InfraImage, "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.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.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.StringSliceVarP(&labels, "label", "l", []string{}, "Set metadata on pod (default [])")
|
||||||
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
|
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
|
||||||
|
@ -3,6 +3,7 @@ package pods
|
|||||||
import (
|
import (
|
||||||
"github.com/containers/libpod/cmd/podman/registry"
|
"github.com/containers/libpod/cmd/podman/registry"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ var (
|
|||||||
TraverseChildren: true,
|
TraverseChildren: true,
|
||||||
RunE: registry.SubCommandExists,
|
RunE: registry.SubCommandExists,
|
||||||
}
|
}
|
||||||
|
containerConfig = util.DefaultContainerConfig()
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -47,11 +47,10 @@ func init() {
|
|||||||
flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running pods")
|
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.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.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() {
|
if registry.IsRemote() {
|
||||||
_ = flags.MarkHidden("latest")
|
_ = flags.MarkHidden("latest")
|
||||||
_ = flags.MarkHidden("ignore")
|
_ = flags.MarkHidden("ignore")
|
||||||
|
|
||||||
}
|
}
|
||||||
flags.SetNormalizeFunc(utils.AliasFlags)
|
flags.SetNormalizeFunc(utils.AliasFlags)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func init() {
|
|||||||
Parent: volumeCmd,
|
Parent: volumeCmd,
|
||||||
})
|
})
|
||||||
flags := createCommand.Flags()
|
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.StringSliceVarP(&opts.Label, "label", "l", []string{}, "Set metadata for a volume (default [])")
|
||||||
flags.StringArrayVarP(&opts.Opts, "opt", "o", []string{}, "Set driver specific options (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"
|
cnitypes "github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containers/buildah/pkg/secrets"
|
"github.com/containers/buildah/pkg/secrets"
|
||||||
|
"github.com/containers/common/pkg/apparmor"
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/libpod/events"
|
"github.com/containers/libpod/libpod/events"
|
||||||
"github.com/containers/libpod/pkg/annotations"
|
"github.com/containers/libpod/pkg/annotations"
|
||||||
"github.com/containers/libpod/pkg/apparmor"
|
|
||||||
"github.com/containers/libpod/pkg/cgroups"
|
"github.com/containers/libpod/pkg/cgroups"
|
||||||
"github.com/containers/libpod/pkg/criu"
|
"github.com/containers/libpod/pkg/criu"
|
||||||
"github.com/containers/libpod/pkg/lookup"
|
"github.com/containers/libpod/pkg/lookup"
|
||||||
|
@ -6,10 +6,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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 is the default path for SHM locks
|
||||||
DefaultSHMLockPath = "/libpod_lock"
|
DefaultSHMLockPath = "/libpod_lock"
|
||||||
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
|
// 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()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defaultContainerConfig, err := runtime.GetConfig()
|
containerConfig, err := runtime.GetConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "GetConfig()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "GetConfig()"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cc, err := makeCreateConfig(defaultContainerConfig, input, newImage)
|
cc, err := makeCreateConfig(containerConfig, input, newImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()"))
|
||||||
return
|
return
|
||||||
@ -60,7 +60,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
utils.CreateContainer(r.Context(), w, runtime, &cc)
|
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 (
|
var (
|
||||||
err error
|
err error
|
||||||
init bool
|
init bool
|
||||||
@ -81,7 +81,7 @@ func makeCreateConfig(defaultContainerConfig *config.Config, input handlers.Crea
|
|||||||
workDir = input.WorkingDir
|
workDir = input.WorkingDir
|
||||||
}
|
}
|
||||||
|
|
||||||
stopTimeout := defaultContainerConfig.Engine.StopTimeout
|
stopTimeout := containerConfig.Engine.StopTimeout
|
||||||
if input.StopTimeout != nil {
|
if input.StopTimeout != nil {
|
||||||
stopTimeout = uint(*input.StopTimeout)
|
stopTimeout = uint(*input.StopTimeout)
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/pkg/api/handlers"
|
"github.com/containers/libpod/pkg/api/handlers"
|
||||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/libpod/pkg/sysinfo"
|
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/google/uuid"
|
"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"
|
"github.com/containers/common/pkg/capabilities"
|
||||||
cconfig "github.com/containers/common/pkg/config"
|
cconfig "github.com/containers/common/pkg/config"
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/pkg/cgroups"
|
"github.com/containers/libpod/pkg/cgroups"
|
||||||
"github.com/containers/libpod/pkg/env"
|
"github.com/containers/libpod/pkg/env"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/libpod/pkg/sysinfo"
|
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/opencontainers/runc/libcontainer/user"
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
|
@ -4,9 +4,9 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/libpod/pkg/cgroups"
|
"github.com/containers/libpod/pkg/cgroups"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/libpod/pkg/sysinfo"
|
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package specgen
|
package specgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/containers/libpod/libpod/define"
|
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrInvalidPodSpecConfig describes an error given when the podspecgenerator is invalid
|
// ErrInvalidPodSpecConfig describes an error given when the podspecgenerator is invalid
|
||||||
ErrInvalidPodSpecConfig error = errors.New("invalid pod spec")
|
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 {
|
func exclusivePodOptions(opt1, opt2 string) error {
|
||||||
@ -96,10 +98,10 @@ func (p *PodSpecGenerator) Validate() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(p.InfraImage) < 1 {
|
if len(p.InfraImage) < 1 {
|
||||||
p.InfraImage = define.DefaultInfraImage
|
p.InfraImage = containerConfig.Engine.InfraImage
|
||||||
}
|
}
|
||||||
if len(p.InfraCommand) < 1 {
|
if len(p.InfraCommand) < 1 {
|
||||||
p.InfraCommand = []string{define.DefaultInfraCommand}
|
p.InfraCommand = []string{containerConfig.Engine.InfraCommand}
|
||||||
}
|
}
|
||||||
return nil
|
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"
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/libpod/pkg/errorhandling"
|
"github.com/containers/libpod/pkg/errorhandling"
|
||||||
"github.com/containers/libpod/pkg/namespaces"
|
"github.com/containers/libpod/pkg/namespaces"
|
||||||
@ -27,6 +28,17 @@ import (
|
|||||||
"golang.org/x/crypto/ssh/terminal"
|
"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
|
// Helper function to determine the username/password passed
|
||||||
// in the creds string. It could be either or both.
|
// in the creds string. It could be either or both.
|
||||||
func parseCreds(creds string) (string, string) {
|
func parseCreds(creds string) (string, string) {
|
||||||
@ -669,3 +681,7 @@ func swapSELinuxLabel(cLabel, processLabel string) (string, error) {
|
|||||||
dcon["type"] = scon["type"]
|
dcon["type"] = scon["type"]
|
||||||
return dcon.Get(), nil
|
return dcon.Get(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DefaultContainerConfig() *config.Config {
|
||||||
|
return containerConfig
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/sysinfo"
|
||||||
"github.com/containers/image/v5/manifest"
|
"github.com/containers/image/v5/manifest"
|
||||||
"github.com/containers/libpod/cmd/podman/parse"
|
"github.com/containers/libpod/cmd/podman/parse"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
@ -28,7 +29,6 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/containers/libpod/pkg/seccomp"
|
"github.com/containers/libpod/pkg/seccomp"
|
||||||
cc "github.com/containers/libpod/pkg/spec"
|
cc "github.com/containers/libpod/pkg/spec"
|
||||||
"github.com/containers/libpod/pkg/sysinfo"
|
|
||||||
systemdGen "github.com/containers/libpod/pkg/systemd/generate"
|
systemdGen "github.com/containers/libpod/pkg/systemd/generate"
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
@ -331,7 +331,7 @@ func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt {
|
|||||||
// structure.
|
// structure.
|
||||||
func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
|
func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
|
||||||
// FIXME this will need to be fixed!!!!! With containers conf
|
// FIXME this will need to be fixed!!!!! With containers conf
|
||||||
//defaultContainerConfig := cliconfig.GetDefaultConfig()
|
//containerConfig := cliconfig.GetDefaultConfig()
|
||||||
// TODO | WARN
|
// TODO | WARN
|
||||||
// We do not get a default network over varlink. Unlike the other default values for some cli
|
// 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.
|
// elements, it seems it gets set to the default anyway.
|
||||||
|
Reference in New Issue
Block a user