Skip to content

Commit 7e608fa

Browse files
authored
Merge pull request #61 from cgwalters/fix-attach
disk: Switch to just invoking `podman run`
2 parents 79c9266 + 1bef5ec commit 7e608fa

File tree

1 file changed

+33
-104
lines changed

1 file changed

+33
-104
lines changed

pkg/bootc/bootc_disk.go

Lines changed: 33 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
"os/exec"
1011
"path/filepath"
1112
"strings"
1213
"sync"
@@ -19,11 +20,10 @@ import (
1920

2021
"github.com/containers/podman/v5/pkg/bindings/containers"
2122
"github.com/containers/podman/v5/pkg/domain/entities/types"
22-
"github.com/containers/podman/v5/pkg/specgen"
2323
"github.com/docker/go-units"
24-
specs "github.com/opencontainers/runtime-spec/specs-go"
2524
"github.com/sirupsen/logrus"
2625
"golang.org/x/sys/unix"
26+
"golang.org/x/term"
2727
)
2828

2929
// As a baseline heuristic we double the size of
@@ -290,7 +290,7 @@ func (p *BootcDisk) pullImage() error {
290290
}
291291

292292
// runInstallContainer runs the bootc installer in a container to create a disk image
293-
func (p *BootcDisk) runInstallContainer(quiet bool, config DiskImageConfig) (err error) {
293+
func (p *BootcDisk) runInstallContainer(quiet bool, config DiskImageConfig) error {
294294
// Create a temporary external shell script with the contents of our losetup wrapper
295295
losetupTemp, err := os.CreateTemp(p.Directory, "losetup-wrapper")
296296
if err != nil {
@@ -304,55 +304,17 @@ func (p *BootcDisk) runInstallContainer(quiet bool, config DiskImageConfig) (err
304304
return fmt.Errorf("temp losetup wrapper chmod: %w", err)
305305
}
306306

307-
createResponse, err := p.createInstallContainer(config, losetupTemp.Name())
308-
if err != nil {
309-
return fmt.Errorf("failed to create container: %w", err)
310-
}
311-
312-
p.bootcInstallContainerId = createResponse.ID //save the id for possible cleanup
313-
logrus.Debugf("Created install container, id=%s", createResponse.ID)
314-
315-
// run the container to create the disk
316-
err = containers.Start(p.Ctx, p.bootcInstallContainerId, &containers.StartOptions{})
317-
if err != nil {
318-
return fmt.Errorf("failed to start container: %w", err)
319-
}
320-
logrus.Debugf("Started install container")
321-
322-
// Ensure we've cancelled the container attachment when exiting this function, as
323-
// it takes over stdout/stderr handling
324-
attachCancelCtx, cancelAttach := context.WithCancel(p.Ctx)
325-
defer cancelAttach()
326-
var exitCode int32
327-
if !quiet {
328-
attachOpts := new(containers.AttachOptions).WithStream(true)
329-
if err := containers.Attach(attachCancelCtx, p.bootcInstallContainerId, os.Stdin, os.Stdout, os.Stderr, nil, attachOpts); err != nil {
330-
return fmt.Errorf("attaching: %w", err)
331-
}
332-
}
333-
exitCode, err = containers.Wait(p.Ctx, p.bootcInstallContainerId, nil)
334-
if err != nil {
335-
return fmt.Errorf("failed to wait for container: %w", err)
307+
c := p.createInstallContainer(config, losetupTemp.Name())
308+
if err := c.Run(); err != nil {
309+
return fmt.Errorf("failed to invoke install: %w", err)
336310
}
337-
338-
if exitCode != 0 {
339-
return fmt.Errorf("failed to run bootc install")
340-
}
341-
342-
return
311+
return nil
343312
}
344313

345-
// createInstallContainer creates a container to run the bootc installer
346-
func (p *BootcDisk) createInstallContainer(config DiskImageConfig, tempLosetup string) (createResponse types.ContainerCreateResponse, err error) {
347-
privileged := true
348-
autoRemove := true
349-
labelNested := true
350-
351-
targetEnv := make(map[string]string)
352-
if v, ok := os.LookupEnv("BOOTC_INSTALL_LOG"); ok {
353-
targetEnv["RUST_LOG"] = v
354-
}
355-
314+
// createInstallContainer creates a podman command to run the bootc installer.
315+
// Note: This code used to use the Go bindings for the podman remote client, but the
316+
// Attach interface currently leaks goroutines.
317+
func (p *BootcDisk) createInstallContainer(config DiskImageConfig, tempLosetup string) *exec.Cmd {
356318
bootcInstallArgs := []string{
357319
"bootc", "install", "to-disk", "--via-loopback", "--generic-image",
358320
"--skip-fetch-check",
@@ -365,60 +327,27 @@ func (p *BootcDisk) createInstallContainer(config DiskImageConfig, tempLosetup s
365327
}
366328
bootcInstallArgs = append(bootcInstallArgs, "/output/"+filepath.Base(p.file.Name()))
367329

368-
// Allocate pty so we can show progress bars, spinners etc.
369-
trueDat := true
370-
s := &specgen.SpecGenerator{
371-
ContainerBasicConfig: specgen.ContainerBasicConfig{
372-
Command: bootcInstallArgs,
373-
PidNS: specgen.Namespace{NSMode: specgen.Host},
374-
Remove: &autoRemove,
375-
Annotations: map[string]string{"io.podman.annotations.label": "type:unconfined_t"},
376-
Env: targetEnv,
377-
Terminal: &trueDat,
378-
},
379-
ContainerStorageConfig: specgen.ContainerStorageConfig{
380-
Image: p.ImageNameOrId,
381-
Mounts: []specs.Mount{
382-
{
383-
Source: "/var/lib/containers",
384-
Destination: "/var/lib/containers",
385-
Type: "bind",
386-
},
387-
{
388-
Source: "/dev",
389-
Destination: "/dev",
390-
Type: "bind",
391-
},
392-
{
393-
Source: p.Directory,
394-
Destination: "/output",
395-
Type: "bind",
396-
},
397-
{
398-
Source: tempLosetup,
399-
// Note that the default $PATH has /usr/local/sbin first
400-
Destination: "/usr/local/sbin/losetup",
401-
Type: "bind",
402-
Options: []string{"ro"},
403-
},
404-
},
405-
},
406-
ContainerSecurityConfig: specgen.ContainerSecurityConfig{
407-
Privileged: &privileged,
408-
LabelNested: &labelNested,
409-
SelinuxOpts: []string{"type:unconfined_t"},
410-
},
411-
ContainerNetworkConfig: specgen.ContainerNetworkConfig{
412-
NetNS: specgen.Namespace{
413-
NSMode: specgen.Bridge,
414-
},
415-
},
330+
// Basic config:
331+
// - force on --remote because we depend on podman machine.
332+
// - add privileged, pid=host, SELinux config and bind mounts per https://containers.github.io/bootc/bootc-install.html
333+
podmanArgs := []string{"--remote", "run", "--rm", "-i", "--pid=host", "--privileged", "--security-opt=label=type:unconfined_t", "--volume=/dev:/dev", "--volume=/var/lib/containers:/var/lib/containers"}
334+
// Custom bind mounts
335+
podmanArgs = append(podmanArgs, fmt.Sprintf("--volume=%s:/output", p.Directory), fmt.Sprintf("--volume=%s:/usr/local/sbin/losetup:ro", tempLosetup))
336+
if term.IsTerminal(int(os.Stdin.Fd())) {
337+
podmanArgs = append(podmanArgs, "-t")
416338
}
417-
418-
createResponse, err = containers.CreateWithSpec(p.Ctx, s, &containers.CreateOptions{})
419-
if err != nil {
420-
return createResponse, fmt.Errorf("failed to create container: %w", err)
421-
}
422-
423-
return
339+
// Other conditional arguments
340+
if v, ok := os.LookupEnv("BOOTC_INSTALL_LOG"); ok {
341+
podmanArgs = append(podmanArgs, fmt.Sprintf("--env=RUST_LOG=%s", v))
342+
}
343+
// The image name
344+
podmanArgs = append(podmanArgs, p.ImageNameOrId)
345+
// And the remaining arguments for bootc install
346+
podmanArgs = append(podmanArgs, bootcInstallArgs...)
347+
348+
c := exec.Command("podman", podmanArgs...)
349+
c.Stdin = os.Stdin
350+
c.Stdout = os.Stdout
351+
c.Stderr = os.Stderr
352+
return c
424353
}

0 commit comments

Comments
 (0)