@@ -54,6 +54,7 @@ type ArchiveOptions struct {
54
54
FirmwareLibrary string
55
55
Logger * logrus.Logger
56
56
GraphOptions []string // passed in from a storage Store, probably
57
+ ExtraImageContent map [string ]string
57
58
}
58
59
59
60
type chainRetrievalError struct {
@@ -70,17 +71,15 @@ func (c chainRetrievalError) Error() string {
70
71
71
72
// Archive generates a WorkloadConfig for a specified directory and produces a
72
73
// tar archive of a container image's rootfs with the expected contents.
73
- // The input directory will have a ".krun_config.json" file added to it while
74
- // this function is running, but it will be removed on completion.
75
- func Archive (path string , ociConfig * v1.Image , options ArchiveOptions ) (io.ReadCloser , WorkloadConfig , error ) {
74
+ func Archive (rootfsPath string , ociConfig * v1.Image , options ArchiveOptions ) (io.ReadCloser , WorkloadConfig , error ) {
76
75
const (
77
76
teeDefaultCPUs = 2
78
77
teeDefaultMemory = 512
79
78
teeDefaultFilesystem = "ext4"
80
79
teeDefaultTeeType = SNP
81
80
)
82
81
83
- if path == "" {
82
+ if rootfsPath == "" {
84
83
return nil , WorkloadConfig {}, fmt .Errorf ("required path not specified" )
85
84
}
86
85
logger := options .Logger
@@ -103,7 +102,7 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
103
102
filesystem := teeDefaultFilesystem
104
103
workloadID := options .WorkloadID
105
104
if workloadID == "" {
106
- digestInput := path + filesystem + time .Now ().String ()
105
+ digestInput := rootfsPath + filesystem + time .Now ().String ()
107
106
workloadID = digest .Canonical .FromString (digestInput ).Encoded ()
108
107
}
109
108
workloadConfig := WorkloadConfig {
@@ -176,7 +175,7 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
176
175
177
176
// We're going to want to add some content to the rootfs, so set up an
178
177
// overlay that uses it as a lower layer so that we can write to it.
179
- st , err := system .Stat (path )
178
+ st , err := system .Stat (rootfsPath )
180
179
if err != nil {
181
180
return nil , WorkloadConfig {}, fmt .Errorf ("reading information about the container root filesystem: %w" , err )
182
181
}
@@ -220,7 +219,7 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
220
219
}
221
220
}()
222
221
// Create a mount point using that working state.
223
- rootfsMount , err := overlay .Mount (overlayTempDir , path , rootfsDir , 0 , 0 , options .GraphOptions )
222
+ rootfsMount , err := overlay .Mount (overlayTempDir , rootfsPath , rootfsDir , 0 , 0 , options .GraphOptions )
224
223
if err != nil {
225
224
return nil , WorkloadConfig {}, fmt .Errorf ("setting up support for overlay of container root filesystem: %w" , err )
226
225
}
@@ -243,14 +242,46 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
243
242
}
244
243
}()
245
244
// Pretend that we didn't have to do any of the preceding.
246
- path = rootfsDir
245
+ rootfsPath = rootfsDir
246
+
247
+ // Write extra content to the rootfs, creating intermediate directories if necessary.
248
+ for location , content := range options .ExtraImageContent {
249
+ err := func () error {
250
+ if err := idtools .MkdirAllAndChownNew (filepath .Dir (filepath .Join (rootfsPath , location )), 0o755 , idtools.IDPair {UID : int (st .UID ()), GID : int (st .GID ())}); err != nil {
251
+ return fmt .Errorf ("ensuring %q is present in container root filesystem: %w" , filepath .Dir (location ), err )
252
+ }
253
+ output , err := os .OpenFile (filepath .Join (rootfsPath , location ), os .O_CREATE | os .O_WRONLY | os .O_TRUNC , 0o644 )
254
+ if err != nil {
255
+ return fmt .Errorf ("preparing to write %q to container root filesystem: %w" , location , err )
256
+ }
257
+ defer output .Close ()
258
+ input , err := os .Open (content )
259
+ if err != nil {
260
+ return err
261
+ }
262
+ defer input .Close ()
263
+ if _ , err := io .Copy (output , input ); err != nil {
264
+ return fmt .Errorf ("copying contents of %q to %q in container root filesystem: %w" , content , location , err )
265
+ }
266
+ if err := output .Chown (int (st .UID ()), int (st .GID ())); err != nil {
267
+ return fmt .Errorf ("setting owner of %q in the container root filesystem: %w" , location , err )
268
+ }
269
+ if err := output .Chmod (0o644 ); err != nil {
270
+ return fmt .Errorf ("setting permissions on %q in the container root filesystem: %w" , location , err )
271
+ }
272
+ return nil
273
+ }()
274
+ if err != nil {
275
+ return nil , WorkloadConfig {}, err
276
+ }
277
+ }
247
278
248
279
// Write part of the config blob where the krun init process will be
249
280
// looking for it. The oci2cw tool used `buildah inspect` output, but
250
281
// init is just looking for fields that have the right names in any
251
282
// object, and the image's config will have that, so let's try encoding
252
283
// it directly.
253
- krunConfigPath := filepath .Join (path , ".krun_config.json" )
284
+ krunConfigPath := filepath .Join (rootfsPath , ".krun_config.json" )
254
285
krunConfigBytes , err := json .Marshal (ociConfig )
255
286
if err != nil {
256
287
return nil , WorkloadConfig {}, fmt .Errorf ("creating .krun_config from image configuration: %w" , err )
@@ -288,7 +319,7 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
288
319
imageSize := slop (options .ImageSize , options .Slop )
289
320
if imageSize == 0 {
290
321
var sourceSize int64
291
- if err := filepath .WalkDir (path , func (path string , d fs.DirEntry , err error ) error {
322
+ if err := filepath .WalkDir (rootfsPath , func (path string , d fs.DirEntry , err error ) error {
292
323
if err != nil && ! errors .Is (err , os .ErrNotExist ) && ! errors .Is (err , os .ErrPermission ) {
293
324
return err
294
325
}
@@ -336,7 +367,7 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
336
367
}
337
368
338
369
// Format the disk image with the filesystem contents.
339
- if _ , stderr , err := MakeFS (path , plain .Name (), filesystem ); err != nil {
370
+ if _ , stderr , err := MakeFS (rootfsPath , plain .Name (), filesystem ); err != nil {
340
371
if strings .TrimSpace (stderr ) != "" {
341
372
return nil , WorkloadConfig {}, fmt .Errorf ("%s: %w" , strings .TrimSpace (stderr ), err )
342
373
}
@@ -456,8 +487,8 @@ func Archive(path string, ociConfig *v1.Image, options ArchiveOptions) (io.ReadC
456
487
tmpHeader .Name = "tmp/"
457
488
tmpHeader .Typeflag = tar .TypeDir
458
489
tmpHeader .Mode = 0o1777
459
- tmpHeader .Uname , workloadConfigHeader .Gname = "" , ""
460
- tmpHeader .Uid , workloadConfigHeader .Gid = 0 , 0
490
+ tmpHeader .Uname , tmpHeader .Gname = "" , ""
491
+ tmpHeader .Uid , tmpHeader .Gid = 0 , 0
461
492
tmpHeader .Size = 0
462
493
if err = tw .WriteHeader (tmpHeader ); err != nil {
463
494
logrus .Errorf ("writing header for %q: %v" , tmpHeader .Name , err )
0 commit comments