summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--cmd/podman/create.go82
-rw-r--r--cmd/podman/sign.go15
-rw-r--r--libpod/container.go26
-rw-r--r--libpod/container_inspect.go5
-rw-r--r--libpod/container_internal_linux.go8
-rw-r--r--libpod/image/image.go18
-rw-r--r--libpod/image/image_test.go46
-rw-r--r--libpod/runtime.go24
-rw-r--r--pkg/apparmor/apparmor.go7
-rw-r--r--pkg/apparmor/apparmor_linux.go66
-rw-r--r--pkg/apparmor/apparmor_unsupported.go16
-rw-r--r--pkg/spec/createconfig.go4
-rw-r--r--pkg/spec/spec.go1
-rw-r--r--pkg/sysinfo/sysinfo_linux.go~254
-rw-r--r--pkg/varlinkapi/images.go13
16 files changed, 221 insertions, 370 deletions
diff --git a/Makefile b/Makefile
index 3fd9b4ed4..93b9fcd58 100644
--- a/Makefile
+++ b/Makefile
@@ -356,7 +356,10 @@ cmd/podman/varlink/iopodman.go: cmd/podman/varlink/io.podman.varlink
API.md: cmd/podman/varlink/io.podman.varlink
$(GO) generate ./docs/...
-validate: gofmt .gitvalidation
+validate.completions: completions/bash/podman
+ . completions/bash/podman
+
+validate: gofmt .gitvalidation validate.completions
build-all-new-commits:
# Validate that all the commits build on top of $(GIT_BASE_BRANCH)
@@ -366,6 +369,7 @@ build-all-new-commits:
.gopathok \
binaries \
clean \
+ validate.completions \
default \
docs \
gofmt \
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 395a64b3b..d98b78bd4 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -15,13 +15,11 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
- "github.com/containers/libpod/pkg/apparmor"
"github.com/containers/libpod/pkg/inspect"
ns "github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
- libpodVersion "github.com/containers/libpod/version"
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
@@ -162,83 +160,9 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container
return ctr, createConfig, nil
}
-// Checks if a user-specified AppArmor profile is loaded, or loads the default profile if
-// AppArmor is enabled.
-// Any interaction with AppArmor requires root permissions.
-func loadAppArmor(config *cc.CreateConfig) error {
- if rootless.IsRootless() {
- noAAMsg := "AppArmor security is not available in rootless mode"
- switch config.ApparmorProfile {
- case "":
- logrus.Warn(noAAMsg)
- case "unconfined":
- default:
- return fmt.Errorf(noAAMsg)
- }
- return nil
- }
-
- if config.ApparmorProfile == "" && apparmor.IsEnabled() {
- // Unless specified otherwise, make sure that the default AppArmor
- // profile is installed. To avoid redundantly loading the profile
- // on each invocation, check if it's loaded before installing it.
- // Suffix the profile with the current libpod version to allow
- // loading the new, potentially updated profile after an update.
- profile := fmt.Sprintf("%s-%s", apparmor.DefaultLibpodProfile, libpodVersion.Version)
-
- loadProfile := func() error {
- isLoaded, err := apparmor.IsLoaded(profile)
- if err != nil {
- return err
- }
- if !isLoaded {
- err = apparmor.InstallDefault(profile)
- if err != nil {
- return err
- }
-
- }
- return nil
- }
-
- if err := loadProfile(); err != nil {
- switch err {
- case apparmor.ErrApparmorUnsupported:
- // do not set the profile when AppArmor isn't supported
- logrus.Debugf("AppArmor is not supported: setting empty profile")
- default:
- return err
- }
- } else {
- logrus.Infof("Sucessfully loaded AppAmor profile '%s'", profile)
- config.ApparmorProfile = profile
- }
- } else if config.ApparmorProfile != "" && config.ApparmorProfile != "unconfined" {
- if !apparmor.IsEnabled() {
- return fmt.Errorf("Profile specified but AppArmor is disabled on the host")
- }
-
- isLoaded, err := apparmor.IsLoaded(config.ApparmorProfile)
- if err != nil {
- switch err {
- case apparmor.ErrApparmorUnsupported:
- return fmt.Errorf("Profile specified but AppArmor is not supported")
- default:
- return fmt.Errorf("Error checking if AppArmor profile is loaded: %v", err)
- }
- }
- if !isLoaded {
- return fmt.Errorf("The specified AppArmor profile '%s' is not loaded", config.ApparmorProfile)
- }
- }
-
- return nil
-}
-
func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
var (
labelOpts []string
- err error
)
if config.PidMode.IsHost() {
@@ -283,10 +207,6 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
}
}
- if err := loadAppArmor(config); err != nil {
- return err
- }
-
if config.SeccompProfilePath == "" {
if _, err := os.Stat(libpod.SeccompOverridePath); err == nil {
config.SeccompProfilePath = libpod.SeccompOverridePath
@@ -304,7 +224,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
}
}
config.LabelOpts = labelOpts
- return err
+ return nil
}
// isPortInPortBindings determines if an exposed host port is in user
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index aa3e0cab7..e7367a311 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -59,7 +59,7 @@ func signCmd(c *cli.Context) error {
signby := c.String("sign-by")
if signby == "" {
- return errors.Errorf("You must provide an identity")
+ return errors.Errorf("please provide an identity")
}
var sigStoreDir string
@@ -72,11 +72,11 @@ func signCmd(c *cli.Context) error {
mech, err := signature.NewGPGSigningMechanism()
if err != nil {
- return errors.Wrap(err, "Error initializing GPG")
+ return errors.Wrap(err, "error initializing GPG")
}
defer mech.Close()
if err := mech.SupportsSigning(); err != nil {
- return errors.Wrap(err, "Signing is not supported")
+ return errors.Wrap(err, "signing is not supported")
}
systemRegistriesDirPath := trust.RegistriesDirPath(runtime.SystemContext())
@@ -100,7 +100,7 @@ func signCmd(c *cli.Context) error {
}
dockerReference := rawSource.Reference().DockerReference()
if dockerReference == nil {
- return errors.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(rawSource.Reference()))
+ return errors.Errorf("cannot determine canonical Docker reference for destination %s", transports.ImageName(rawSource.Reference()))
}
// create the signstore file
@@ -126,7 +126,10 @@ func signCmd(c *cli.Context) error {
sigStoreDir = SignatureStoreDir
}
- repos := newImage.RepoDigests()
+ repos, err := newImage.RepoDigests()
+ if err != nil {
+ return errors.Wrapf(err, "error calculating repo digests for %s", signimage)
+ }
if len(repos) == 0 {
logrus.Errorf("no repodigests associated with the image %s", signimage)
continue
@@ -187,7 +190,7 @@ func isValidSigStoreDir(sigStoreDir string) (string, error) {
}
_, exists := writeURIs[url.Scheme]
if !exists {
- return sigStoreDir, errors.Errorf("Writing to %s is not supported. Use a supported scheme", sigStoreDir)
+ return sigStoreDir, errors.Errorf("writing to %s is not supported. Use a supported scheme", sigStoreDir)
}
sigStoreDir = url.Path
return sigStoreDir, nil
diff --git a/libpod/container.go b/libpod/container.go
index d0eb6a992..026eb1c4f 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1,7 +1,9 @@
package libpod
import (
+ "encoding/json"
"fmt"
+ "io/ioutil"
"net"
"os"
"path/filepath"
@@ -407,6 +409,30 @@ func (c *Container) Spec() *spec.Spec {
return returnSpec
}
+// specFromState returns the unmarshalled json config of the container. If the
+// config does not exist (e.g., because the container was never started) return
+// the spec from the config.
+func (c *Container) specFromState() (*spec.Spec, error) {
+ spec := c.config.Spec
+
+ if f, err := os.Open(c.state.ConfigPath); err == nil {
+ content, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading container config")
+ }
+ if err := json.Unmarshal([]byte(content), &spec); err != nil {
+ return nil, errors.Wrapf(err, "error unmarshalling container config")
+ }
+ } else {
+ // ignore when the file does not exist
+ if !os.IsNotExist(err) {
+ return nil, errors.Wrapf(err, "error opening container config")
+ }
+ }
+
+ return spec, nil
+}
+
// ID returns the container's ID
func (c *Container) ID() string {
return c.config.ID
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 06a0c9f32..e2730c282 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -12,7 +12,10 @@ import (
func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data) (*inspect.ContainerInspectData, error) {
config := c.config
runtimeInfo := c.state
- spec := c.config.Spec
+ spec, err := c.specFromState()
+ if err != nil {
+ return nil, err
+ }
// Process is allowed to be nil in the spec
args := []string{}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 582a4c3e7..2f03d45ea 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -20,6 +20,7 @@ import (
cnitypes "github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/plugins/pkg/ns"
crioAnnotations "github.com/containers/libpod/pkg/annotations"
+ "github.com/containers/libpod/pkg/apparmor"
"github.com/containers/libpod/pkg/criu"
"github.com/containers/libpod/pkg/lookup"
"github.com/containers/libpod/pkg/resolvconf"
@@ -185,6 +186,13 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
+ // Apply AppArmor checks and load the default profile if needed.
+ updatedProfile, err := apparmor.CheckProfileAndLoadDefault(c.config.Spec.Process.ApparmorProfile)
+ if err != nil {
+ return nil, err
+ }
+ g.SetProcessApparmorProfile(updatedProfile)
+
if err := c.makeBindMounts(); err != nil {
return nil, err
}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 3a6d0e305..2e12adb70 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -305,12 +305,24 @@ func (i *Image) Names() []string {
}
// RepoDigests returns a string array of repodigests associated with the image
-func (i *Image) RepoDigests() []string {
+func (i *Image) RepoDigests() ([]string, error) {
var repoDigests []string
+ digest := i.Digest()
+
for _, name := range i.Names() {
- repoDigests = append(repoDigests, strings.SplitN(name, ":", 2)[0]+"@"+i.Digest().String())
+ named, err := reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, err
+ }
+
+ canonical, err := reference.WithDigest(reference.TrimNamed(named), digest)
+ if err != nil {
+ return nil, err
+ }
+
+ repoDigests = append(repoDigests, canonical.String())
}
- return repoDigests
+ return repoDigests, nil
}
// Created returns the time the image was created
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 91bb2411b..2a68fd273 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/containers/storage"
+ "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
)
@@ -192,6 +193,51 @@ func TestImage_MatchRepoTag(t *testing.T) {
cleanup(workdir, ir)
}
+// TestImage_RepoDigests tests RepoDigest generation.
+func TestImage_RepoDigests(t *testing.T) {
+ dgst, err := digest.Parse("sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, test := range []struct {
+ name string
+ names []string
+ expected []string
+ }{
+ {
+ name: "empty",
+ names: []string{},
+ expected: nil,
+ },
+ {
+ name: "tagged",
+ names: []string{"docker.io/library/busybox:latest"},
+ expected: []string{"docker.io/library/busybox@sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
+ },
+ {
+ name: "digest",
+ names: []string{"docker.io/library/busybox@sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
+ expected: []string{"docker.io/library/busybox@sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc"},
+ },
+ } {
+ t.Run(test.name, func(t *testing.T) {
+ image := &Image{
+ image: &storage.Image{
+ Names: test.names,
+ Digest: dgst,
+ },
+ }
+ actual, err := image.RepoDigests()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Equal(t, test.expected, actual)
+ })
+ }
+}
+
// Test_splitString tests the splitString function in image that
// takes input and splits on / and returns the last array item
func Test_splitString(t *testing.T) {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index ab8d02a4f..c9471247c 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -692,25 +692,19 @@ func makeRuntime(runtime *Runtime) (err error) {
}
}
- // Set up the lock manager
- var manager lock.Manager
lockPath := DefaultSHMLockPath
if rootless.IsRootless() {
lockPath = fmt.Sprintf("%s_%d", DefaultRootlessSHMLockPath, rootless.GetRootlessUID())
}
- if doRefresh {
- // If SHM locks already exist, delete them and reinitialize
- if err := os.Remove(filepath.Join("/dev/shm", lockPath)); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "error deleting existing libpod SHM segment %s", lockPath)
- }
-
- manager, err = lock.NewSHMLockManager(lockPath, runtime.config.NumLocks)
- if err != nil {
- return err
- }
- } else {
- manager, err = lock.OpenSHMLockManager(lockPath, runtime.config.NumLocks)
- if err != nil {
+ // Set up the lock manager
+ manager, err := lock.OpenSHMLockManager(lockPath, runtime.config.NumLocks)
+ if err != nil {
+ if os.IsNotExist(errors.Cause(err)) {
+ manager, err = lock.NewSHMLockManager(lockPath, runtime.config.NumLocks)
+ if err != nil {
+ return err
+ }
+ } else {
return err
}
}
diff --git a/pkg/apparmor/apparmor.go b/pkg/apparmor/apparmor.go
index 8b9f99477..45c029c07 100644
--- a/pkg/apparmor/apparmor.go
+++ b/pkg/apparmor/apparmor.go
@@ -2,11 +2,16 @@ package apparmor
import (
"errors"
+ libpodVersion "github.com/containers/libpod/version"
)
var (
+ // DefaultLipodProfilePrefix is used for version-independent presence checks.
+ DefaultLipodProfilePrefix = "libpod-default" + "-"
// DefaultLibpodProfile is the name of default libpod AppArmor profile.
- DefaultLibpodProfile = "libpod-default"
+ 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")
)
diff --git a/pkg/apparmor/apparmor_linux.go b/pkg/apparmor/apparmor_linux.go
index b0e3ca0fd..0787b3fa5 100644
--- a/pkg/apparmor/apparmor_linux.go
+++ b/pkg/apparmor/apparmor_linux.go
@@ -13,7 +13,10 @@ import (
"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.
@@ -21,6 +24,9 @@ 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()
}
@@ -71,6 +77,10 @@ func macroExists(m string) bool {
// 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,
}
@@ -97,6 +107,10 @@ func InstallDefault(name string) error {
// 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) {
@@ -188,3 +202,55 @@ func parseAAParserVersion(output string) (int, error) {
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
+ }
+
+ if name != "" && rootless.IsRootless() {
+ return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
+ }
+
+ if name != "" && !runcaa.IsEnabled() {
+ 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")
+ }
+ 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
+}
diff --git a/pkg/apparmor/apparmor_unsupported.go b/pkg/apparmor/apparmor_unsupported.go
index df1336b07..b2b4de5f5 100644
--- a/pkg/apparmor/apparmor_unsupported.go
+++ b/pkg/apparmor/apparmor_unsupported.go
@@ -2,19 +2,25 @@
package apparmor
-// IsEnabled returns true if AppArmor is enabled on the host.
+// IsEnabled dummy.
func IsEnabled() bool {
return false
}
-// InstallDefault generates a default profile in a temp directory determined by
-// os.TempDir(), then loads the profile into the kernel using 'apparmor_parser'.
+// InstallDefault dummy.
func InstallDefault(name string) error {
return ErrApparmorUnsupported
}
-// IsLoaded checks if a profile with the given name has been loaded into the
-// kernel.
+// 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
+}
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index ffc98e307..87fce7e2e 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -518,7 +518,9 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
if c.CgroupParent != "" {
options = append(options, libpod.WithCgroupParent(c.CgroupParent))
}
- if c.Detach {
+ // For a rootless container always cleanup the storage/network as they
+ // run in a different namespace thus not reusable when we restart.
+ if c.Detach || rootless.IsRootless() {
options = append(options, libpod.WithExitCommand(c.createExitCommand()))
}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index ffa999730..9ef0223f2 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -252,6 +252,7 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
}
// SECURITY OPTS
g.SetProcessNoNewPrivileges(config.NoNewPrivs)
+
g.SetProcessApparmorProfile(config.ApparmorProfile)
blockAccessToKernelFilesystems(config, &g)
diff --git a/pkg/sysinfo/sysinfo_linux.go~ b/pkg/sysinfo/sysinfo_linux.go~
deleted file mode 100644
index 471f786a7..000000000
--- a/pkg/sysinfo/sysinfo_linux.go~
+++ /dev/null
@@ -1,254 +0,0 @@
-package sysinfo
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "strings"
-
- "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 {
- _, 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"
-}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 5e4cb4ccb..8f8934025 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -41,13 +41,18 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
for _, image := range images {
labels, _ := image.Labels(getContext())
containers, _ := image.Containers()
+ repoDigests, err := image.RepoDigests()
+ if err != nil {
+ return err
+ }
+
size, _ := image.Size(getContext())
i := iopodman.ImageInList{
Id: image.ID(),
ParentId: image.Parent,
RepoTags: image.Names(),
- RepoDigests: image.RepoDigests(),
+ RepoDigests: repoDigests,
Created: image.Created().String(),
Size: int64(*size),
VirtualSize: image.VirtualSize,
@@ -73,6 +78,10 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
if err != nil {
return err
}
+ repoDigests, err := newImage.RepoDigests()
+ if err != nil {
+ return err
+ }
size, err := newImage.Size(getContext())
if err != nil {
return err
@@ -82,7 +91,7 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
Id: newImage.ID(),
ParentId: newImage.Parent,
RepoTags: newImage.Names(),
- RepoDigests: newImage.RepoDigests(),
+ RepoDigests: repoDigests,
Created: newImage.Created().String(),
Size: int64(*size),
VirtualSize: newImage.VirtualSize,