Skip to content

Commit c87c56a

Browse files
authored
Merge pull request #1880 from presztak/use_umoci_package
Use the umoci Go package instead of the command
2 parents b7a69e7 + 175c480 commit c87c56a

File tree

9 files changed

+214
-50
lines changed

9 files changed

+214
-50
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ ifneq "$(INCUS_OFFLINE)" ""
9595
endif
9696
$(GO) get -t -v -u ./...
9797
$(GO) get github.com/go-jose/go-jose/[email protected]
98+
$(GO) get github.com/olekukonko/[email protected]
9899
$(GO) mod tidy --go=1.23.7
99100
$(GO) get toolchain@none
100101

client/oci_images.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,6 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
155155
return nil, fmt.Errorf("OCI image export currently requires root access")
156156
}
157157

158-
_, err = exec.LookPath("umoci")
159-
if err != nil {
160-
return nil, fmt.Errorf("OCI container handling requires \"umoci\" be present on the system")
161-
}
162-
163158
// Get some temporary storage.
164159
ociPath, err := os.MkdirTemp("", "incus-oci-")
165160
if err != nil {
@@ -183,6 +178,8 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
183178
req.ProgressHandler(ioprogress.ProgressData{Text: "Retrieving OCI image from registry"})
184179
}
185180

181+
imageTag := "latest"
182+
186183
stdout, _, err := subprocess.RunCommandSplit(
187184
ctx,
188185
env,
@@ -192,7 +189,7 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
192189
"copy",
193190
"--remove-signatures",
194191
fmt.Sprintf("%s/%s", strings.Replace(r.httpHost, "https://", "docker://", 1), info.Alias),
195-
fmt.Sprintf("oci:%s:latest", filepath.Join(ociPath, "oci")))
192+
fmt.Sprintf("oci:%s:%s", filepath.Join(ociPath, "oci"), imageTag))
196193
if err != nil {
197194
logger.Debug("Error copying remote image to local", logger.Ctx{"image": info.Alias, "stdout": stdout, "stderr": err})
198195
return nil, err
@@ -203,14 +200,9 @@ func (r *ProtocolOCI) GetImageFile(fingerprint string, req ImageFileRequest) (*I
203200
req.ProgressHandler(ioprogress.ProgressData{Text: "Unpacking the OCI image"})
204201
}
205202

206-
stdout, err = subprocess.RunCommand(
207-
"umoci",
208-
"unpack",
209-
"--keep-dirlinks",
210-
"--image", filepath.Join(ociPath, "oci"),
211-
filepath.Join(ociPath, "image"))
203+
err = unpackOCIImage(filepath.Join(ociPath, "oci"), imageTag, filepath.Join(ociPath, "image"))
212204
if err != nil {
213-
logger.Debug("Error unpacking OCI image", logger.Ctx{"image": filepath.Join(ociPath, "oci"), "stdout": stdout, "stderr": err})
205+
logger.Debug("Error unpacking OCI image", logger.Ctx{"image": filepath.Join(ociPath, "oci"), "err": err})
214206
return nil, err
215207
}
216208

client/oci_util.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build !linux
2+
3+
package incus
4+
5+
import (
6+
"fmt"
7+
)
8+
9+
func unpackOCIImage(imagePath string, imageTag string, bundlePath string) error {
10+
return fmt.Errorf("Platform isn't supported")
11+
}

client/oci_util_linux.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//go:build linux
2+
3+
package incus
4+
5+
import (
6+
"fmt"
7+
8+
"github.com/apex/log"
9+
"github.com/opencontainers/umoci"
10+
"github.com/opencontainers/umoci/oci/cas/dir"
11+
"github.com/opencontainers/umoci/oci/casext"
12+
"github.com/opencontainers/umoci/oci/layer"
13+
14+
"github.com/lxc/incus/v6/shared/logger"
15+
)
16+
17+
// Custom handler to intercept logs.
18+
type umociLogHandler struct {
19+
Message string
20+
}
21+
22+
// HandleLog implements a proxy between apex/log and our logger.
23+
func (h *umociLogHandler) HandleLog(e *log.Entry) error {
24+
switch e.Level {
25+
case log.DebugLevel:
26+
logger.Debug(h.Message, logger.Ctx{"log": e.Message})
27+
case log.InfoLevel:
28+
logger.Info(h.Message, logger.Ctx{"log": e.Message})
29+
case log.WarnLevel:
30+
logger.Warn(h.Message, logger.Ctx{"log": e.Message})
31+
case log.ErrorLevel:
32+
logger.Error(h.Message, logger.Ctx{"log": e.Message})
33+
case log.FatalLevel:
34+
logger.Panic(h.Message, logger.Ctx{"log": e.Message})
35+
default:
36+
logger.Error("Unknown umoci log level", logger.Ctx{"log": e.Message})
37+
}
38+
39+
return nil
40+
}
41+
42+
func unpackOCIImage(imagePath string, imageTag string, bundlePath string) error {
43+
// Set the custom handler
44+
log.SetHandler(&umociLogHandler{Message: "Unpacking OCI image"})
45+
defer log.SetHandler(nil)
46+
47+
var unpackOptions layer.UnpackOptions
48+
unpackOptions.KeepDirlinks = true
49+
50+
// Get a reference to the CAS.
51+
engine, err := dir.Open(imagePath)
52+
if err != nil {
53+
return fmt.Errorf("Open CAS: %w", err)
54+
}
55+
56+
engineExt := casext.NewEngine(engine)
57+
defer func() { _ = engine.Close() }()
58+
59+
return umoci.Unpack(engineExt, imageTag, bundlePath, unpackOptions)
60+
}

doc/requirements.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ LXCFS is strongly recommended to properly report resource consumption inside the
3838

3939
## OCI
4040

41-
To run OCI containers, Incus currently rely on both `skopeo` and `umoci`.
42-
Both tools should be available in the user's `PATH`.
41+
To run OCI containers, Incus currently rely on `skopeo`.
42+
`skopeo` should be available in the user's `PATH`.
4343

4444
## QEMU
4545

go.mod

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.23.7
55
require (
66
github.com/LINBIT/golinstor v0.55.0
77
github.com/adhocore/gronx v1.19.6
8+
github.com/apex/log v1.9.0
89
github.com/armon/go-proxyproto v0.1.0
910
github.com/cenkalti/backoff/v4 v4.3.0
1011
github.com/checkpoint-restore/go-criu/v6 v6.3.0
@@ -34,13 +35,14 @@ require (
3435
github.com/mdlayher/ndp v1.1.0
3536
github.com/mdlayher/netx v0.0.0-20230430222610-7e21880baee8
3637
github.com/mdlayher/vsock v1.2.1
37-
github.com/miekg/dns v1.1.65
38-
github.com/minio/minio-go/v7 v7.0.91
38+
github.com/miekg/dns v1.1.66
39+
github.com/minio/minio-go/v7 v7.0.92
3940
github.com/mitchellh/mapstructure v1.5.0
4041
github.com/olekukonko/tablewriter v0.0.5
4142
github.com/opencontainers/runtime-spec v1.2.1
43+
github.com/opencontainers/umoci v0.5.0
4244
github.com/openfga/go-sdk v0.7.1
43-
github.com/osrg/gobgp/v3 v3.36.0
45+
github.com/osrg/gobgp/v3 v3.37.0
4446
github.com/ovn-org/libovsdb v0.7.0
4547
github.com/pierrec/lz4/v4 v4.1.22
4648
github.com/pkg/sftp v1.13.9
@@ -49,7 +51,7 @@ require (
4951
github.com/spf13/cobra v1.9.1
5052
github.com/spf13/pflag v1.0.6
5153
github.com/stretchr/testify v1.10.0
52-
github.com/vishvananda/netlink v1.3.0
54+
github.com/vishvananda/netlink v1.3.1
5355
github.com/zitadel/oidc/v3 v3.38.1
5456
go.starlark.net v0.0.0-20250417143717-f57e51f710eb
5557
golang.org/x/crypto v0.38.0
@@ -66,16 +68,20 @@ require (
6668
)
6769

6870
require (
71+
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
6972
github.com/Rican7/retry v0.3.1 // indirect
7073
github.com/beorn7/perks v1.0.1 // indirect
74+
github.com/blang/semver/v4 v4.0.0 // indirect
7175
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
7276
github.com/cenkalti/hub v1.0.2 // indirect
7377
github.com/cenkalti/rpc2 v1.0.4 // indirect
7478
github.com/cespare/xxhash/v2 v2.3.0 // indirect
7579
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
80+
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
7681
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
7782
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
78-
github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 // indirect
83+
github.com/digitalocean/go-libvirt v0.0.0-20250512231903-57024326652b // indirect
84+
github.com/docker/go-units v0.5.0 // indirect
7985
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 // indirect
8086
github.com/dustin/go-humanize v1.0.1 // indirect
8187
github.com/eapache/channels v1.1.0 // indirect
@@ -94,6 +100,7 @@ require (
94100
github.com/k-sone/critbitgo v1.4.0 // indirect
95101
github.com/klauspost/compress v1.18.0 // indirect
96102
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
103+
github.com/klauspost/pgzip v1.2.6 // indirect
97104
github.com/kr/fs v0.1.0 // indirect
98105
github.com/mattn/go-isatty v0.0.20 // indirect
99106
github.com/mattn/go-runewidth v0.0.16 // indirect
@@ -103,17 +110,23 @@ require (
103110
github.com/minio/crc64nvme v1.0.2 // indirect
104111
github.com/minio/md5-simd v1.1.2 // indirect
105112
github.com/mitchellh/go-homedir v1.1.0 // indirect
113+
github.com/moby/sys/user v0.4.0 // indirect
114+
github.com/moby/sys/userns v0.1.0 // indirect
106115
github.com/muhlemmer/gu v0.3.1 // indirect
107116
github.com/muhlemmer/httpforwarded v0.1.0 // indirect
108117
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
118+
github.com/opencontainers/go-digest v1.0.0 // indirect
119+
github.com/opencontainers/image-spec v1.1.1 // indirect
109120
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
121+
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
110122
github.com/pkg/errors v0.9.1 // indirect
111123
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
112124
github.com/prometheus/client_golang v1.22.0 // indirect
113125
github.com/prometheus/client_model v0.6.2 // indirect
114-
github.com/prometheus/common v0.63.0 // indirect
126+
github.com/prometheus/common v0.64.0 // indirect
115127
github.com/prometheus/procfs v0.16.1 // indirect
116128
github.com/rivo/uniseg v0.4.7 // indirect
129+
github.com/rootless-containers/proto/go-proto v0.0.0-20230421021042-4cd87ebadd67 // indirect
117130
github.com/rs/cors v1.11.1 // indirect
118131
github.com/rs/xid v1.6.0 // indirect
119132
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -123,20 +136,23 @@ require (
123136
github.com/spf13/cast v1.8.0 // indirect
124137
github.com/spf13/viper v1.20.1 // indirect
125138
github.com/subosito/gotenv v1.6.0 // indirect
139+
github.com/tinylib/msgp v1.3.0 // indirect
126140
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
141+
github.com/urfave/cli v1.22.16 // indirect
142+
github.com/vbatts/go-mtree v0.5.4 // indirect
127143
github.com/vishvananda/netns v0.0.5 // indirect
128144
github.com/zitadel/logging v0.6.2 // indirect
129145
github.com/zitadel/schema v1.3.1 // indirect
130146
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
131-
go.opentelemetry.io/otel v1.35.0 // indirect
132-
go.opentelemetry.io/otel/metric v1.35.0 // indirect
133-
go.opentelemetry.io/otel/trace v1.35.0 // indirect
147+
go.opentelemetry.io/otel v1.36.0 // indirect
148+
go.opentelemetry.io/otel/metric v1.36.0 // indirect
149+
go.opentelemetry.io/otel/trace v1.36.0 // indirect
134150
go.uber.org/multierr v1.11.0 // indirect
135151
golang.org/x/mod v0.24.0 // indirect
136152
golang.org/x/net v0.40.0 // indirect
137153
golang.org/x/time v0.11.0 // indirect
138-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
139-
google.golang.org/grpc v1.72.0 // indirect
154+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
155+
google.golang.org/grpc v1.72.1 // indirect
140156
gopkg.in/yaml.v3 v3.0.1 // indirect
141157
moul.io/http2curl/v2 v2.3.0 // indirect
142158
)

0 commit comments

Comments
 (0)