Re-add resource limit warnings to Specgen

These were part of Podman v1.9, but were lost in the transition
to using Specgen to create containers. Most resource limits are
checked via the sysinfo package to ensure they are safe to use
(the cgroup is mounted, kernel support is present, etc) and
removed if not safe. Further, bounds checks are performed to
ensure that values are valid.

Ensure these warnings are printed client-side when they occur.
This part is a little bit gross, as it happens in pkg/infra and
not cmd/podman, which is largely down to how we implemented
`podman run` - all the work is done in pkg/infra and it returns
only once the container has exited, and we need warnings to print
*before* the container runs. The solution here, while inelegant,
avoid the need to extensively refactor our handling of run.

Should fix blkio-limit warnings that were identified by the FCOS
test suite.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon
2020-06-16 17:32:01 -04:00
parent d6965da26d
commit c51c593ff6
7 changed files with 270 additions and 79 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
envLib "github.com/containers/libpod/pkg/env"
"github.com/containers/libpod/pkg/signal"
@ -13,91 +14,103 @@ import (
"golang.org/x/sys/unix"
)
func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) error {
// If a rootfs is used, then there is no image data
if s.ContainerStorageConfig.Rootfs != "" {
return nil
}
// Fill any missing parts of the spec generator (e.g. from the image).
// Returns a set of warnings or any fatal error that occurred.
func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) ([]string, error) {
var (
newImage *image.Image
err error
)
newImage, err := r.ImageRuntime().NewFromLocal(s.Image)
if err != nil {
return err
}
_, mediaType, err := newImage.Manifest(ctx)
if err != nil {
return err
}
if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
s.HealthConfig, err = newImage.GetHealthCheck(ctx)
// Only add image configuration if we have an image
if s.Image != "" {
newImage, err = r.ImageRuntime().NewFromLocal(s.Image)
if err != nil {
return err
return nil, err
}
}
// Image stop signal
if s.StopSignal == nil {
stopSignal, err := newImage.StopSignal(ctx)
_, mediaType, err := newImage.Manifest(ctx)
if err != nil {
return err
return nil, err
}
if stopSignal != "" {
sig, err := signal.ParseSignalNameOrNumber(stopSignal)
if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
s.HealthConfig, err = newImage.GetHealthCheck(ctx)
if err != nil {
return err
return nil, err
}
}
// Image stop signal
if s.StopSignal == nil {
stopSignal, err := newImage.StopSignal(ctx)
if err != nil {
return nil, err
}
if stopSignal != "" {
sig, err := signal.ParseSignalNameOrNumber(stopSignal)
if err != nil {
return nil, err
}
s.StopSignal = &sig
}
s.StopSignal = &sig
}
}
rtc, err := r.GetConfig()
if err != nil {
return err
return nil, err
}
// Get Default Environment
defaultEnvs, err := envLib.ParseSlice(rtc.Containers.Env)
if err != nil {
return errors.Wrap(err, "Env fields in containers.conf failed to parse")
return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse")
}
// Image envs from the image if they don't exist
// already, overriding the default environments
imageEnvs, err := newImage.Env(ctx)
if err != nil {
return err
}
var envs map[string]string
envs, err := envLib.ParseSlice(imageEnvs)
if err != nil {
return errors.Wrap(err, "Env fields from image failed to parse")
}
s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env)
if newImage != nil {
// Image envs from the image if they don't exist
// already, overriding the default environments
imageEnvs, err := newImage.Env(ctx)
if err != nil {
return nil, err
}
labels, err := newImage.Labels(ctx)
if err != nil {
return err
}
// labels from the image that dont exist already
if len(labels) > 0 && s.Labels == nil {
s.Labels = make(map[string]string)
}
for k, v := range labels {
if _, exists := s.Labels[k]; !exists {
s.Labels[k] = v
envs, err = envLib.ParseSlice(imageEnvs)
if err != nil {
return nil, errors.Wrap(err, "Env fields from image failed to parse")
}
}
// annotations
s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env)
// Add annotations from the image
annotations, err := newImage.Annotations(ctx)
if err != nil {
return err
}
for k, v := range annotations {
annotations[k] = v
// Labels and Annotations
annotations := make(map[string]string)
if newImage != nil {
labels, err := newImage.Labels(ctx)
if err != nil {
return nil, err
}
// labels from the image that dont exist already
if len(labels) > 0 && s.Labels == nil {
s.Labels = make(map[string]string)
}
for k, v := range labels {
if _, exists := s.Labels[k]; !exists {
s.Labels[k] = v
}
}
// Add annotations from the image
imgAnnotations, err := newImage.Annotations(ctx)
if err != nil {
return nil, err
}
for k, v := range imgAnnotations {
annotations[k] = v
}
}
// in the event this container is in a pod, and the pod has an infra container
@ -121,40 +134,42 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
s.Annotations = annotations
// workdir
workingDir, err := newImage.WorkingDir(ctx)
if err != nil {
return err
}
if len(s.WorkDir) < 1 && len(workingDir) > 1 {
s.WorkDir = workingDir
if newImage != nil {
workingDir, err := newImage.WorkingDir(ctx)
if err != nil {
return nil, err
}
if len(s.WorkDir) < 1 && len(workingDir) > 1 {
s.WorkDir = workingDir
}
}
if len(s.SeccompProfilePath) < 1 {
p, err := libpod.DefaultSeccompPath()
if err != nil {
return err
return nil, err
}
s.SeccompProfilePath = p
}
if len(s.User) == 0 {
if len(s.User) == 0 && newImage != nil {
s.User, err = newImage.User(ctx)
if err != nil {
return err
return nil, err
}
}
if err := finishThrottleDevices(s); err != nil {
return err
return nil, err
}
// Unless already set via the CLI, check if we need to disable process
// labels or set the defaults.
if len(s.SelinuxOpts) == 0 {
if err := setLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil {
return err
return nil, err
}
}
return nil
return verifyContainerResources(s)
}
// finishThrottleDevices takes the temporary representation of the throttle