1
0
mirror of https://github.com/lxc/incus.git synced 2026-02-05 09:46:19 +01:00

client: Use the umoci Go package instead of the command

Signed-off-by: Piotr Resztak <piotr.resztak@futurfusion.io>
This commit is contained in:
Piotr Resztak
2025-04-02 19:09:04 +02:00
committed by Stéphane Graber
parent 341d4252f4
commit 727041a1c2
3 changed files with 76 additions and 13 deletions

View File

@@ -155,11 +155,6 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
return nil, fmt.Errorf("OCI image export currently requires root access") return nil, fmt.Errorf("OCI image export currently requires root access")
} }
_, err = exec.LookPath("umoci")
if err != nil {
return nil, fmt.Errorf("OCI container handling requires \"umoci\" be present on the system")
}
// Get some temporary storage. // Get some temporary storage.
ociPath, err := os.MkdirTemp("", "incus-oci-") ociPath, err := os.MkdirTemp("", "incus-oci-")
if err != nil { if err != nil {
@@ -183,6 +178,8 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
req.ProgressHandler(ioprogress.ProgressData{Text: "Retrieving OCI image from registry"}) req.ProgressHandler(ioprogress.ProgressData{Text: "Retrieving OCI image from registry"})
} }
imageTag := "latest"
stdout, _, err := subprocess.RunCommandSplit( stdout, _, err := subprocess.RunCommandSplit(
ctx, ctx,
env, env,
@@ -192,7 +189,7 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
"copy", "copy",
"--remove-signatures", "--remove-signatures",
fmt.Sprintf("%s/%s", strings.Replace(r.httpHost, "https://", "docker://", 1), info.Alias), fmt.Sprintf("%s/%s", strings.Replace(r.httpHost, "https://", "docker://", 1), info.Alias),
fmt.Sprintf("oci:%s:latest", filepath.Join(ociPath, "oci"))) fmt.Sprintf("oci:%s:%s", filepath.Join(ociPath, "oci"), imageTag))
if err != nil { if err != nil {
logger.Debug("Error copying remote image to local", logger.Ctx{"image": info.Alias, "stdout": stdout, "stderr": err}) logger.Debug("Error copying remote image to local", logger.Ctx{"image": info.Alias, "stdout": stdout, "stderr": err})
return nil, err return nil, err
@@ -203,14 +200,9 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
req.ProgressHandler(ioprogress.ProgressData{Text: "Unpacking the OCI image"}) req.ProgressHandler(ioprogress.ProgressData{Text: "Unpacking the OCI image"})
} }
stdout, err = subprocess.RunCommand( err = unpackOCIImage(filepath.Join(ociPath, "oci"), imageTag, filepath.Join(ociPath, "image"))
"umoci",
"unpack",
"--keep-dirlinks",
"--image", filepath.Join(ociPath, "oci"),
filepath.Join(ociPath, "image"))
if err != nil { if err != nil {
logger.Debug("Error unpacking OCI image", logger.Ctx{"image": filepath.Join(ociPath, "oci"), "stdout": stdout, "stderr": err}) logger.Debug("Error unpacking OCI image", logger.Ctx{"image": filepath.Join(ociPath, "oci"), "err": err})
return nil, err return nil, err
} }

11
client/oci_util.go Normal file
View File

@@ -0,0 +1,11 @@
//go:build !linux
package incus
import (
"fmt"
)
func unpackOCIImage(imagePath string, imageTag string, bundlePath string) error {
return fmt.Errorf("Platform isn't supported")
}

60
client/oci_util_linux.go Normal file
View File

@@ -0,0 +1,60 @@
//go:build linux
package incus
import (
"fmt"
"github.com/apex/log"
"github.com/opencontainers/umoci"
"github.com/opencontainers/umoci/oci/cas/dir"
"github.com/opencontainers/umoci/oci/casext"
"github.com/opencontainers/umoci/oci/layer"
"github.com/lxc/incus/v6/shared/logger"
)
// Custom handler to intercept logs.
type umociLogHandler struct {
Message string
}
// HandleLog implements a proxy between apex/log and our logger.
func (h *umociLogHandler) HandleLog(e *log.Entry) error {
switch e.Level {
case log.DebugLevel:
logger.Debug(h.Message, logger.Ctx{"log": e.Message})
case log.InfoLevel:
logger.Info(h.Message, logger.Ctx{"log": e.Message})
case log.WarnLevel:
logger.Warn(h.Message, logger.Ctx{"log": e.Message})
case log.ErrorLevel:
logger.Error(h.Message, logger.Ctx{"log": e.Message})
case log.FatalLevel:
logger.Panic(h.Message, logger.Ctx{"log": e.Message})
default:
logger.Error("Unknown umoci log level", logger.Ctx{"log": e.Message})
}
return nil
}
func unpackOCIImage(imagePath string, imageTag string, bundlePath string) error {
// Set the custom handler
log.SetHandler(&umociLogHandler{Message: "Unpacking OCI image"})
defer log.SetHandler(nil)
var unpackOptions layer.UnpackOptions
unpackOptions.KeepDirlinks = true
// Get a reference to the CAS.
engine, err := dir.Open(imagePath)
if err != nil {
return fmt.Errorf("Open CAS: %w", err)
}
engineExt := casext.NewEngine(engine)
defer func() { _ = engine.Close() }()
return umoci.Unpack(engineExt, imageTag, bundlePath, unpackOptions)
}