@@ -13,12 +13,11 @@ import (
13
13
"syscall"
14
14
"time"
15
15
16
- "gitlab.com/bootc-org/podman-bootc/pkg/config"
16
+ "gitlab.com/bootc-org/podman-bootc/pkg/cache"
17
+ "gitlab.com/bootc-org/podman-bootc/pkg/container"
17
18
"gitlab.com/bootc-org/podman-bootc/pkg/user"
18
- "gitlab.com/bootc-org/podman-bootc/pkg/utils"
19
19
20
20
"github.com/containers/podman/v5/pkg/bindings/containers"
21
- "github.com/containers/podman/v5/pkg/bindings/images"
22
21
"github.com/containers/podman/v5/pkg/domain/entities/types"
23
22
"github.com/containers/podman/v5/pkg/specgen"
24
23
"github.com/docker/go-units"
@@ -62,14 +61,11 @@ type diskFromContainerMeta struct {
62
61
}
63
62
64
63
type BootcDisk struct {
65
- ImageNameOrId string
64
+ ContainerImage container.ContainerImage
65
+ Cache cache.Cache
66
66
User user.User
67
67
Ctx context.Context
68
- ImageId string
69
- imageData * types.ImageInspectReport
70
- RepoTag string
71
68
CreatedAt time.Time
72
- Directory string
73
69
file * os.File
74
70
bootcInstallContainerId string
75
71
}
@@ -80,40 +76,34 @@ var (
80
76
instanceOnce sync.Once
81
77
)
82
78
83
- func NewBootcDisk (imageNameOrId string , ctx context.Context , user user.User ) * BootcDisk {
79
+ // NewBootcDisk creates a new BootcDisk instance
80
+ //
81
+ // Parameters:
82
+ // - imageNameOrId: the name or id of the container image
83
+ // - ctx: context for the podman machine connection
84
+ // - user: the user who is running the command, determines where the disk image is stored
85
+ func NewBootcDisk (containerImage container.ContainerImage , ctx context.Context , user user.User , cache cache.Cache ) * BootcDisk {
84
86
instanceOnce .Do (func () {
85
87
instance = & BootcDisk {
86
- ImageNameOrId : imageNameOrId ,
87
- Ctx : ctx ,
88
- User : user ,
88
+ ContainerImage : containerImage ,
89
+ Ctx : ctx ,
90
+ User : user ,
91
+ Cache : cache ,
89
92
}
90
93
})
91
94
return instance
92
95
}
93
96
94
- func (p * BootcDisk ) GetDirectory () string {
95
- return p .Directory
96
- }
97
-
98
- func (p * BootcDisk ) GetImageId () string {
99
- return p .ImageId
100
- }
101
-
102
97
// GetSize returns the virtual size of the disk in bytes;
103
98
// this may be larger than the actual disk usage
104
99
func (p * BootcDisk ) GetSize () (int64 , error ) {
105
- st , err := os .Stat (filepath . Join ( p . Directory , config . DiskImage ))
100
+ st , err := os .Stat (p . Cache . GetDiskPath ( ))
106
101
if err != nil {
107
102
return 0 , err
108
103
}
109
104
return st .Size (), nil
110
105
}
111
106
112
- // GetRepoTag returns the repository of the container image
113
- func (p * BootcDisk ) GetRepoTag () string {
114
- return p .RepoTag
115
- }
116
-
117
107
// GetCreatedAt returns the creation time of the disk image
118
108
func (p * BootcDisk ) GetCreatedAt () time.Time {
119
109
return p .CreatedAt
@@ -122,32 +112,6 @@ func (p *BootcDisk) GetCreatedAt() time.Time {
122
112
func (p * BootcDisk ) Install (quiet bool , config DiskImageConfig ) (err error ) {
123
113
p .CreatedAt = time .Now ()
124
114
125
- err = p .pullImage ()
126
- if err != nil {
127
- return
128
- }
129
-
130
- // Create VM cache dir; one per oci bootc image
131
- p .Directory = filepath .Join (p .User .CacheDir (), p .ImageId )
132
- lock := utils .NewCacheLock (p .User .RunDir (), p .Directory )
133
- locked , err := lock .TryLock (utils .Exclusive )
134
- if err != nil {
135
- return fmt .Errorf ("error locking the VM cache path: %w" , err )
136
- }
137
- if ! locked {
138
- return fmt .Errorf ("unable to lock the VM cache path" )
139
- }
140
-
141
- defer func () {
142
- if err := lock .Unlock (); err != nil {
143
- logrus .Errorf ("unable to unlock VM %s: %v" , p .ImageId , err )
144
- }
145
- }()
146
-
147
- if err := os .MkdirAll (p .Directory , os .ModePerm ); err != nil {
148
- return fmt .Errorf ("error while making bootc disk directory: %w" , err )
149
- }
150
-
151
115
err = p .getOrInstallImageToDisk (quiet , config )
152
116
if err != nil {
153
117
return
@@ -173,7 +137,7 @@ func (p *BootcDisk) Cleanup() (err error) {
173
137
174
138
// getOrInstallImageToDisk checks if the disk is present and if not, installs the image to a new disk
175
139
func (p * BootcDisk ) getOrInstallImageToDisk (quiet bool , diskConfig DiskImageConfig ) error {
176
- diskPath := filepath . Join ( p . Directory , config . DiskImage )
140
+ diskPath := p . Cache . GetDiskPath ( )
177
141
f , err := os .Open (diskPath )
178
142
if err != nil {
179
143
if ! errors .Is (err , os .ErrNotExist ) {
@@ -199,8 +163,8 @@ func (p *BootcDisk) getOrInstallImageToDisk(quiet bool, diskConfig DiskImageConf
199
163
return p .bootcInstallImageToDisk (quiet , diskConfig )
200
164
}
201
165
202
- logrus .Debugf ("previous disk digest: %s current digest: %s" , serializedMeta .ImageDigest , p .ImageId )
203
- if serializedMeta .ImageDigest == p .ImageId {
166
+ logrus .Debugf ("previous disk digest: %s current digest: %s" , serializedMeta .ImageDigest , p .ContainerImage . GetId () )
167
+ if serializedMeta .ImageDigest == p .ContainerImage . GetId () {
204
168
return nil
205
169
}
206
170
@@ -217,12 +181,12 @@ func align(size int64, align int64) int64 {
217
181
218
182
// bootcInstallImageToDisk creates a disk image from a bootc container
219
183
func (p * BootcDisk ) bootcInstallImageToDisk (quiet bool , diskConfig DiskImageConfig ) (err error ) {
220
- fmt .Printf ("Executing `bootc install to-disk` from container image %s to create disk image\n " , p .RepoTag )
221
- p .file , err = os .CreateTemp (p .Directory , "podman-bootc-tempdisk" )
184
+ fmt .Printf ("Executing `bootc install to-disk` from container image %s to create disk image\n " , p .ContainerImage . GetRepoTag () )
185
+ p .file , err = os .CreateTemp (p .Cache . GetDirectory () , "podman-bootc-tempdisk" )
222
186
if err != nil {
223
187
return err
224
188
}
225
- size := p .imageData . Size * containerSizeToDiskSizeMultiplier
189
+ size := p .ContainerImage . GetSize () * containerSizeToDiskSizeMultiplier
226
190
if size < diskSizeMinimum {
227
191
size = diskSizeMinimum
228
192
}
@@ -237,7 +201,7 @@ func (p *BootcDisk) bootcInstallImageToDisk(quiet bool, diskConfig DiskImageConf
237
201
}
238
202
// Round up to 4k; loopback wants at least 512b alignment
239
203
size = align (size , 4096 )
240
- humanContainerSize := units .HumanSize (float64 (p .imageData . Size ))
204
+ humanContainerSize := units .HumanSize (float64 (p .ContainerImage . GetSize () ))
241
205
humanSize := units .HumanSize (float64 (size ))
242
206
logrus .Infof ("container size: %s, disk size: %s" , humanContainerSize , humanSize )
243
207
@@ -257,7 +221,7 @@ func (p *BootcDisk) bootcInstallImageToDisk(quiet bool, diskConfig DiskImageConf
257
221
return fmt .Errorf ("failed to create disk image: %w" , err )
258
222
}
259
223
serializedMeta := diskFromContainerMeta {
260
- ImageDigest : p .ImageId ,
224
+ ImageDigest : p .ContainerImage . GetId () ,
261
225
}
262
226
buf , err := json .Marshal (serializedMeta )
263
227
if err != nil {
@@ -266,8 +230,8 @@ func (p *BootcDisk) bootcInstallImageToDisk(quiet bool, diskConfig DiskImageConf
266
230
if err := unix .Fsetxattr (int (p .file .Fd ()), imageMetaXattr , buf , 0 ); err != nil {
267
231
return fmt .Errorf ("failed to set xattr: %w" , err )
268
232
}
269
- diskPath := filepath .Join (p .Directory , config .DiskImage )
270
233
234
+ diskPath := p .Cache .GetDiskPath ()
271
235
if err := os .Rename (p .file .Name (), diskPath ); err != nil {
272
236
return fmt .Errorf ("failed to rename to %s: %w" , diskPath , err )
273
237
}
@@ -276,39 +240,10 @@ func (p *BootcDisk) bootcInstallImageToDisk(quiet bool, diskConfig DiskImageConf
276
240
return nil
277
241
}
278
242
279
- // pullImage fetches the container image if not present
280
- func (p * BootcDisk ) pullImage () (err error ) {
281
- pullPolicy := "missing"
282
- ids , err := images .Pull (p .Ctx , p .ImageNameOrId , & images.PullOptions {Policy : & pullPolicy })
283
- if err != nil {
284
- return fmt .Errorf ("failed to pull image: %w" , err )
285
- }
286
-
287
- if len (ids ) == 0 {
288
- return fmt .Errorf ("no ids returned from image pull" )
289
- }
290
-
291
- if len (ids ) > 1 {
292
- return fmt .Errorf ("multiple ids returned from image pull" )
293
- }
294
-
295
- image , err := images .GetImage (p .Ctx , p .ImageNameOrId , & images.GetOptions {})
296
- if err != nil {
297
- return fmt .Errorf ("failed to get image: %w" , err )
298
- }
299
- p .imageData = image
300
-
301
- imageId := ids [0 ]
302
- p .ImageId = imageId
303
- p .RepoTag = image .RepoTags [0 ]
304
-
305
- return
306
- }
307
-
308
243
// runInstallContainer runs the bootc installer in a container to create a disk image
309
244
func (p * BootcDisk ) runInstallContainer (quiet bool , config DiskImageConfig ) (err error ) {
310
245
// Create a temporary external shell script with the contents of our losetup wrapper
311
- losetupTemp , err := os .CreateTemp (p .Directory , "losetup-wrapper" )
246
+ losetupTemp , err := os .CreateTemp (p .Cache . GetDirectory () , "losetup-wrapper" )
312
247
if err != nil {
313
248
return fmt .Errorf ("temp losetup wrapper: %w" , err )
314
249
}
@@ -393,7 +328,7 @@ func (p *BootcDisk) createInstallContainer(config DiskImageConfig, tempLosetup s
393
328
Terminal : & trueDat ,
394
329
},
395
330
ContainerStorageConfig : specgen.ContainerStorageConfig {
396
- Image : p .ImageNameOrId ,
331
+ Image : p .ContainerImage . ImageNameOrId ,
397
332
Mounts : []specs.Mount {
398
333
{
399
334
Source : "/var/lib/containers" ,
@@ -406,7 +341,7 @@ func (p *BootcDisk) createInstallContainer(config DiskImageConfig, tempLosetup s
406
341
Type : "bind" ,
407
342
},
408
343
{
409
- Source : p .Directory ,
344
+ Source : p .Cache . GetDirectory () ,
410
345
Destination : "/output" ,
411
346
Type : "bind" ,
412
347
},
0 commit comments