mirror of
https://github.com/mudler/luet.git
synced 2025-08-21 08:43:11 +00:00
* Reduce possibility of circular dependency Just by adding an import for bus to anything in the helper dir, we would run into a circular dependency due to how things are structured. That means that we cannot set any events for unpacking or docker helper pulling an image. This commit tries to work around this by doing several things. - Remove full imports of the helper module by segmentating some modules into their own submodule, like docker or match so just using a small match function doesnt bring the whole module - Removing a simple function to check if a dir exists from importing the full helper module and instead write the function (5 lines) - Using logrus in the bus module instead of logger, which avoids a circular dependency Signed-off-by: Itxaka <igarcia@suse.com> * Add two new events for unpacking an image Both pre and post unpacking an image Signed-off-by: Itxaka <igarcia@suse.com>
94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
package imgworker
|
|
|
|
// FROM Slightly adapted from genuinetools/img worker
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/mudler/luet/pkg/bus"
|
|
"os"
|
|
|
|
"github.com/containerd/containerd/content"
|
|
"github.com/containerd/containerd/images"
|
|
"github.com/containerd/containerd/platforms"
|
|
"github.com/docker/distribution/reference"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// TODO: this requires root permissions to mount/unmount layers, althrought it shouldn't be required.
|
|
// See how backends are unpacking images without asking for root permissions.
|
|
|
|
// UnpackEventData is the data structure to pass for the bus events
|
|
type UnpackEventData struct {
|
|
Image string
|
|
Dest string
|
|
}
|
|
|
|
// Unpack exports an image to a rootfs destination directory.
|
|
func (c *Client) Unpack(image, dest string) error {
|
|
|
|
ctx := c.ctx
|
|
if len(dest) < 1 {
|
|
return errors.New("destination directory for rootfs cannot be empty")
|
|
}
|
|
|
|
if _, err := os.Stat(dest); err == nil {
|
|
return fmt.Errorf("destination directory already exists: %s", dest)
|
|
}
|
|
|
|
// Parse the image name and tag.
|
|
named, err := reference.ParseNormalizedNamed(image)
|
|
if err != nil {
|
|
return fmt.Errorf("parsing image name %q failed: %v", image, err)
|
|
}
|
|
// Add the latest lag if they did not provide one.
|
|
named = reference.TagNameOnly(named)
|
|
image = named.String()
|
|
|
|
// Create the worker opts.
|
|
opt, err := c.createWorkerOpt()
|
|
if err != nil {
|
|
return fmt.Errorf("creating worker opt failed: %v", err)
|
|
}
|
|
|
|
if opt.ImageStore == nil {
|
|
return errors.New("image store is nil")
|
|
}
|
|
|
|
img, err := opt.ImageStore.Get(ctx, image)
|
|
if err != nil {
|
|
return fmt.Errorf("getting image %s from image store failed: %v", image, err)
|
|
}
|
|
|
|
manifest, err := images.Manifest(ctx, opt.ContentStore, img.Target, platforms.Default())
|
|
if err != nil {
|
|
return fmt.Errorf("getting image manifest failed: %v", err)
|
|
}
|
|
|
|
_,_ = bus.Manager.Publish(bus.EventImagePreUnPack, UnpackEventData{Image: image, Dest: dest})
|
|
|
|
for _, desc := range manifest.Layers {
|
|
logrus.Debugf("Unpacking layer %s", desc.Digest.String())
|
|
|
|
// Read the blob from the content store.
|
|
layer, err := opt.ContentStore.ReaderAt(ctx, desc)
|
|
if err != nil {
|
|
return fmt.Errorf("getting reader for digest %s failed: %v", desc.Digest.String(), err)
|
|
}
|
|
|
|
// Unpack the tarfile to the rootfs path.
|
|
// FROM: https://godoc.org/github.com/moby/moby/pkg/archive#TarOptions
|
|
if err := archive.Untar(content.NewReader(layer), dest, &archive.TarOptions{
|
|
NoLchown: false,
|
|
ExcludePatterns: []string{"dev/"}, // prevent 'operation not permitted'
|
|
}); err != nil {
|
|
return fmt.Errorf("extracting tar for %s to directory %s failed: %v", desc.Digest.String(), dest, err)
|
|
}
|
|
}
|
|
|
|
_, _ = bus.Manager.Publish(bus.EventImagePostUnPack, UnpackEventData{Image: image, Dest: dest})
|
|
|
|
return nil
|
|
}
|