diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_internal_linux.go | 11 | ||||
-rw-r--r-- | libpod/image/image.go | 20 | ||||
-rw-r--r-- | libpod/image/prune.go | 79 | ||||
-rw-r--r-- | libpod/networking_linux.go | 34 | ||||
-rw-r--r-- | libpod/options.go | 8 |
5 files changed, 134 insertions, 18 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 26d6771b0..f051f40e9 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -676,6 +676,10 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO return errors.Wrapf(define.ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State) } + if c.AutoRemove() && options.TargetFile == "" { + return errors.Errorf("Cannot checkpoint containers that have been started with '--rm' unless '--export' is used") + } + if err := c.checkpointRestoreLabelLog("dump.log"); err != nil { return err } @@ -884,7 +888,12 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti // We want to have the same network namespace as before. if c.config.CreateNetNS { - if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), c.state.NetNS.Path()); err != nil { + netNSPath := "" + if !c.config.PostConfigureNetNS { + netNSPath = c.state.NetNS.Path() + } + + if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), netNSPath); err != nil { return err } } diff --git a/libpod/image/image.go b/libpod/image/image.go index 75ac85311..129ccd376 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -74,6 +74,11 @@ type InfoImage struct { Layers []LayerInfo } +// ImageFilter is a function to determine whether a image is included +// in command output. Images to be outputted are tested using the function. +// A true return will include the image, a false return will exclude it. +type ImageFilter func(*Image) bool //nolint + // ErrRepoTagNotFound is the error returned when the image id given doesn't match a rep tag in store var ErrRepoTagNotFound = stderrors.New("unable to match user input to any specific repotag") @@ -330,6 +335,21 @@ func (i *Image) Names() []string { return i.image.Names } +// NamesHistory returns a string array of names previously associated with the +// image, which may be a mixture of tags and digests +func (i *Image) NamesHistory() []string { + if len(i.image.Names) > 0 && len(i.image.NamesHistory) > 0 && + // We compare the latest (time-referenced) tags for equality and skip + // it in the history if they match to not display them twice. We have + // to compare like this, because `i.image.Names` (latest last) gets + // appended on retag, whereas `i.image.NamesHistory` gets prepended + // (latest first) + i.image.Names[len(i.image.Names)-1] == i.image.NamesHistory[0] { + return i.image.NamesHistory[1:] + } + return i.image.NamesHistory +} + // RepoTags returns a string array of repotags associated with the image func (i *Image) RepoTags() ([]string, error) { var repoTags []string diff --git a/libpod/image/prune.go b/libpod/image/prune.go index 006cbdf22..f5be8ed50 100644 --- a/libpod/image/prune.go +++ b/libpod/image/prune.go @@ -2,23 +2,78 @@ package image import ( "context" + "strings" + "time" "github.com/containers/libpod/libpod/events" + "github.com/containers/libpod/pkg/timetype" "github.com/containers/storage" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) +func generatePruneFilterFuncs(filter, filterValue string) (ImageFilter, error) { + switch filter { + case "label": + var filterArray = strings.SplitN(filterValue, "=", 2) + var filterKey = filterArray[0] + if len(filterArray) > 1 { + filterValue = filterArray[1] + } else { + filterValue = "" + } + return func(i *Image) bool { + labels, err := i.Labels(context.Background()) + if err != nil { + return false + } + for labelKey, labelValue := range labels { + if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { + return true + } + } + return false + }, nil + + case "until": + ts, err := timetype.GetTimestamp(filterValue, time.Now()) + if err != nil { + return nil, err + } + seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) + if err != nil { + return nil, err + } + until := time.Unix(seconds, nanoseconds) + return func(i *Image) bool { + if !until.IsZero() && i.Created().After((until)) { + return true + } + return false + }, nil + + } + return nil, nil +} + // GetPruneImages returns a slice of images that have no names/unused -func (ir *Runtime) GetPruneImages(all bool) ([]*Image, error) { +func (ir *Runtime) GetPruneImages(all bool, filterFuncs []ImageFilter) ([]*Image, error) { var ( pruneImages []*Image ) + allImages, err := ir.GetRWImages() if err != nil { return nil, err } for _, i := range allImages { + // filter the images based on this. + for _, filterFunc := range filterFuncs { + if !filterFunc(i) { + continue + } + } + if len(i.Names()) == 0 { pruneImages = append(pruneImages, i) continue @@ -38,9 +93,25 @@ func (ir *Runtime) GetPruneImages(all bool) ([]*Image, error) { // PruneImages prunes dangling and optionally all unused images from the local // image store -func (ir *Runtime) PruneImages(ctx context.Context, all bool) ([]string, error) { - var prunedCids []string - pruneImages, err := ir.GetPruneImages(all) +func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) { + var ( + prunedCids []string + filterFuncs []ImageFilter + ) + for _, f := range filter { + filterSplit := strings.SplitN(f, "=", 2) + if len(filterSplit) < 2 { + return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) + } + + generatedFunc, err := generatePruneFilterFuncs(filterSplit[0], filterSplit[1]) + if err != nil { + return nil, errors.Wrapf(err, "invalid filter") + } + filterFuncs = append(filterFuncs, generatedFunc) + } + + pruneImages, err := ir.GetPruneImages(all, filterFuncs) if err != nil { return nil, errors.Wrap(err, "unable to get images to prune") } diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index cba7b636a..a68338dbb 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -29,19 +29,40 @@ import ( // Get an OCICNI network config func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP, staticMAC net.HardwareAddr) ocicni.PodNetwork { - defaultNetwork := r.netPlugin.GetDefaultNetworkName() + var networkKey string + if len(networks) > 0 { + // This is inconsistent for >1 network, but it's probably the + // best we can do. + networkKey = networks[0] + } else { + networkKey = r.netPlugin.GetDefaultNetworkName() + } network := ocicni.PodNetwork{ Name: name, Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces ID: id, NetNS: nsPath, RuntimeConfig: map[string]ocicni.RuntimeConfig{ - defaultNetwork: {PortMappings: ports}, + networkKey: {PortMappings: ports}, }, } + // If we have extra networks, add them + if len(networks) > 0 { + network.Networks = make([]ocicni.NetAttachment, len(networks)) + for i, netName := range networks { + network.Networks[i].Name = netName + } + } + if staticIP != nil || staticMAC != nil { - network.Networks = []ocicni.NetAttachment{{Name: defaultNetwork}} + // For static IP or MAC, we need to populate networks even if + // it's just the default. + if len(networks) == 0 { + // If len(networks) == 0 this is guaranteed to be the + // default network. + network.Networks = []ocicni.NetAttachment{{Name: networkKey}} + } var rt ocicni.RuntimeConfig = ocicni.RuntimeConfig{PortMappings: ports} if staticIP != nil { rt.IP = staticIP.String() @@ -50,12 +71,7 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port rt.MAC = staticMAC.String() } network.RuntimeConfig = map[string]ocicni.RuntimeConfig{ - defaultNetwork: rt, - } - } else { - network.Networks = make([]ocicni.NetAttachment, len(networks)) - for i, netName := range networks { - network.Networks[i].Name = netName + networkKey: rt, } } diff --git a/libpod/options.go b/libpod/options.go index bfbbb9e2d..f7f14eb26 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1041,8 +1041,8 @@ func WithStaticIP(ip net.IP) CtrCreateOption { return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if the container is not creating a network namespace") } - if len(ctr.config.Networks) != 0 { - return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining additional CNI networks") + if len(ctr.config.Networks) > 1 { + return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network") } ctr.config.StaticIP = ip @@ -1066,8 +1066,8 @@ func WithStaticMAC(mac net.HardwareAddr) CtrCreateOption { return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if the container is not creating a network namespace") } - if len(ctr.config.Networks) != 0 { - return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining additional CNI networks") + if len(ctr.config.Networks) > 1 { + return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network") } ctr.config.StaticMAC = mac |