m/installer/install: take OCI image in Params
install.Params now takes an OCI image. This avoids some duplicate code
to extract info from the OCI image in all places which create
install.Params.
Change-Id: I2430ce1101befaa1b1a4781f592d06ee015a0f99
Reviewed-on: https://review.monogon.dev/c/monogon/+/4297
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
Tested-by: Jenkins CI
diff --git a/cloud/agent/install.go b/cloud/agent/install.go
index 949a9a7..1ad60fc 100644
--- a/cloud/agent/install.go
+++ b/cloud/agent/install.go
@@ -85,15 +85,6 @@
return fmt.Errorf("failed to fetch OS image: %w", err)
}
- efiPayload, err := osImage.Payload("kernel.efi")
- if err != nil {
- return fmt.Errorf("cannot open EFI payload in OS image: %w", err)
- }
- systemImage, err := osImage.Payload("system")
- if err != nil {
- return fmt.Errorf("cannot open system image in OS image: %w", err)
- }
-
l.Info("OS image config downloaded")
nodeParamsRaw, err := proto.Marshal(req.NodeParameters)
@@ -112,9 +103,7 @@
System: 4096,
Data: 128,
},
- Architecture: osImage.Config.ProductInfo.Architecture(),
- SystemImage: systemImage,
- EFIPayload: efiPayload,
+ OSImage: osImage,
ABLoader: structfs.Bytes(abloader),
NodeParameters: structfs.Bytes(nodeParamsRaw),
Output: rootDev,
diff --git a/metropolis/cli/takeover/install.go b/metropolis/cli/takeover/install.go
index 4d42269..d58d89c 100644
--- a/metropolis/cli/takeover/install.go
+++ b/metropolis/cli/takeover/install.go
@@ -73,24 +73,13 @@
return nil, fmt.Errorf("failed to read OS image: %w", err)
}
- efiPayload, err := osImage.Payload("kernel.efi")
- if err != nil {
- return nil, fmt.Errorf("cannot open EFI payload in OS image: %w", err)
- }
- systemImage, err := osImage.Payload("system")
- if err != nil {
- return nil, fmt.Errorf("cannot open system image in OS image: %w", err)
- }
-
return &install.Params{
PartitionSize: install.PartitionSizeInfo{
ESP: 384,
System: 4096,
Data: 128,
},
- Architecture: osImage.Config.ProductInfo.Architecture(),
- SystemImage: systemImage,
- EFIPayload: efiPayload,
+ OSImage: osImage,
ABLoader: structfs.Bytes(abloader),
NodeParameters: structfs.Bytes(metropolisSpecRaw),
Output: rootDev,
diff --git a/metropolis/installer/install/BUILD.bazel b/metropolis/installer/install/BUILD.bazel
index 1532198..1a0fed3 100644
--- a/metropolis/installer/install/BUILD.bazel
+++ b/metropolis/installer/install/BUILD.bazel
@@ -10,6 +10,7 @@
"//osbase/efivarfs",
"//osbase/fat32",
"//osbase/gpt",
+ "//osbase/oci/osimage",
"//osbase/structfs",
"@com_github_google_uuid//:uuid",
],
diff --git a/metropolis/installer/install/install.go b/metropolis/installer/install/install.go
index a2b9ff8..dda3b7a 100644
--- a/metropolis/installer/install/install.go
+++ b/metropolis/installer/install/install.go
@@ -15,6 +15,7 @@
"source.monogon.dev/osbase/efivarfs"
"source.monogon.dev/osbase/fat32"
"source.monogon.dev/osbase/gpt"
+ "source.monogon.dev/osbase/oci/osimage"
"source.monogon.dev/osbase/structfs"
)
@@ -72,17 +73,14 @@
type Params struct {
// Output is the block device to which the OS is installed.
Output blockdev.BlockDev
- // Architecture is the CPU architecture of the OS image.
- Architecture string
+ // OSImage is the image from which the OS is installed.
+ OSImage *osimage.Image
+ // UnverifiedPayloads disables verification of payloads if set.
+ // This only works with uncompressed OS images.
+ UnverifiedPayloads bool
// ABLoader provides the A/B loader which then loads the EFI loader for the
// correct slot.
ABLoader structfs.Blob
- // EFIPayload provides contents of the EFI payload file. It must not be
- // nil. This gets put into boot slot A.
- EFIPayload structfs.Blob
- // SystemImage provides contents of the Metropolis system partition.
- // If nil, no contents will be copied into the partition.
- SystemImage structfs.Blob
// NodeParameters provides contents of the node parameters file. If nil,
// the node parameters file won't be created in the target ESP
// filesystem.
@@ -102,6 +100,7 @@
type plan struct {
*Params
+ systemImage structfs.Blob
efiBootPath string
efiRoot structfs.Tree
tbl *gpt.Table
@@ -125,11 +124,11 @@
return nil, fmt.Errorf("failed to write FAT32: %w", err)
}
- systemImage, err := i.SystemImage.Open()
+ systemImage, err := i.systemImage.Open()
if err != nil {
return nil, fmt.Errorf("failed to open system image: %w", err)
}
- if _, err := io.CopyN(blockdev.NewRWS(i.systemPartitionA), systemImage, i.SystemImage.Size()); err != nil {
+ if _, err := io.CopyN(blockdev.NewRWS(i.systemPartitionA), systemImage, i.systemImage.Size()); err != nil {
systemImage.Close()
return nil, fmt.Errorf("failed to write system partition A: %w", err)
}
@@ -161,7 +160,19 @@
func Plan(p *Params) (*plan, error) {
params := &plan{Params: p}
- var err error
+ payload := p.OSImage.Payload
+ if p.UnverifiedPayloads {
+ payload = p.OSImage.PayloadUnverified
+ }
+ efiPayload, err := payload("kernel.efi")
+ if err != nil {
+ return nil, fmt.Errorf("cannot open EFI payload in OS image: %w", err)
+ }
+ params.systemImage, err = payload("system")
+ if err != nil {
+ return nil, fmt.Errorf("cannot open system image in OS image: %w", err)
+ }
+
params.tbl, err = gpt.New(params.Output)
if err != nil {
return nil, fmt.Errorf("invalid block device: %w", err)
@@ -178,11 +189,11 @@
return nil, fmt.Errorf("failed to allocate ESP: %w", err)
}
- if err := params.efiRoot.PlaceFile(EFIBootAPath, params.EFIPayload); err != nil {
+ if err := params.efiRoot.PlaceFile(EFIBootAPath, efiPayload); err != nil {
return nil, err
}
// Place the A/B loader at the EFI bootloader autodiscovery path.
- params.efiBootPath, err = EFIBootPath(p.Architecture)
+ params.efiBootPath, err = EFIBootPath(p.OSImage.Config.ProductInfo.Architecture())
if err != nil {
return nil, err
}
@@ -205,26 +216,22 @@
return nil, fmt.Errorf("failed to calculate size of FAT32: %w", err)
}
- // Create the system partition only if its size is specified.
- if params.PartitionSize.System != 0 && params.SystemImage != nil {
- params.systemPartitionA = &gpt.Partition{
- Type: SystemAType,
- Name: SystemALabel,
- }
- if err := params.tbl.AddPartition(params.systemPartitionA, params.PartitionSize.System*Mi); err != nil {
- return nil, fmt.Errorf("failed to allocate system partition A: %w", err)
- }
- params.systemPartitionB = &gpt.Partition{
- Type: SystemBType,
- Name: SystemBLabel,
- }
- if err := params.tbl.AddPartition(params.systemPartitionB, params.PartitionSize.System*Mi); err != nil {
- return nil, fmt.Errorf("failed to allocate system partition B: %w", err)
- }
- } else if params.PartitionSize.System == 0 && params.SystemImage != nil {
- // Safeguard against contradicting parameters.
- return nil, fmt.Errorf("the system image parameter was passed while the associated partition size is zero")
+ // Create the system partition.
+ params.systemPartitionA = &gpt.Partition{
+ Type: SystemAType,
+ Name: SystemALabel,
}
+ if err := params.tbl.AddPartition(params.systemPartitionA, params.PartitionSize.System*Mi); err != nil {
+ return nil, fmt.Errorf("failed to allocate system partition A: %w", err)
+ }
+ params.systemPartitionB = &gpt.Partition{
+ Type: SystemBType,
+ Name: SystemBLabel,
+ }
+ if err := params.tbl.AddPartition(params.systemPartitionB, params.PartitionSize.System*Mi); err != nil {
+ return nil, fmt.Errorf("failed to allocate system partition B: %w", err)
+ }
+
// Create the data partition only if its size is specified.
if params.PartitionSize.Data != 0 {
params.dataPartition = &gpt.Partition{
diff --git a/metropolis/installer/main.go b/metropolis/installer/main.go
index ac6152f..6ecc26e 100644
--- a/metropolis/installer/main.go
+++ b/metropolis/installer/main.go
@@ -164,15 +164,6 @@
return fmt.Errorf("failed to read OS image from ESP: %w", err)
}
- efiPayload, err := osImage.Payload("kernel.efi")
- if err != nil {
- return fmt.Errorf("cannot open EFI payload in OS image: %w", err)
- }
- systemImage, err := osImage.Payload("system")
- if err != nil {
- return fmt.Errorf("cannot open system image in OS image: %w", err)
- }
-
// Build the install parameters.
installParams := install.Params{
PartitionSize: install.PartitionSizeInfo{
@@ -186,9 +177,7 @@
// whenever it's writing to block devices, such as now.
Data: 128,
},
- Architecture: osImage.Config.ProductInfo.Architecture(),
- SystemImage: systemImage,
- EFIPayload: efiPayload,
+ OSImage: osImage,
ABLoader: structfs.Bytes(abloader),
NodeParameters: nodeParameters,
}
diff --git a/metropolis/node/core/update/e2e/BUILD.bazel b/metropolis/node/core/update/e2e/BUILD.bazel
index 5960e66..32f0f52 100644
--- a/metropolis/node/core/update/e2e/BUILD.bazel
+++ b/metropolis/node/core/update/e2e/BUILD.bazel
@@ -8,20 +8,18 @@
"//third_party/edk2:OVMF_CODE.fd",
"//third_party/edk2:OVMF_VARS.fd",
# For the initial image creation
- "//metropolis/node/core/update/e2e/testos:verity_rootfs_x",
- "//metropolis/node/core/update/e2e/testos:kernel_efi_x",
+ "//metropolis/node/core/update/e2e/testos:testos_image_x",
"//metropolis/node/abloader",
# For the two update tests
"//metropolis/node/core/update/e2e/testos:testos_image_y",
"//metropolis/node/core/update/e2e/testos:testos_image_z",
],
x_defs = {
+ "xImageXPath": "$(rlocationpath //metropolis/node/core/update/e2e/testos:testos_image_x )",
"xImageYPath": "$(rlocationpath //metropolis/node/core/update/e2e/testos:testos_image_y )",
"xImageZPath": "$(rlocationpath //metropolis/node/core/update/e2e/testos:testos_image_z )",
"xOvmfVarsPath": "$(rlocationpath //third_party/edk2:OVMF_VARS.fd )",
"xOvmfCodePath": "$(rlocationpath //third_party/edk2:OVMF_CODE.fd )",
- "xBootPath": "$(rlocationpath //metropolis/node/core/update/e2e/testos:kernel_efi_x )",
- "xSystemXPath": "$(rlocationpath //metropolis/node/core/update/e2e/testos:verity_rootfs_x )",
"xAbloaderPath": "$(rlocationpath //metropolis/node/abloader )",
},
deps = [
diff --git a/metropolis/node/core/update/e2e/e2e_test.go b/metropolis/node/core/update/e2e/e2e_test.go
index 124883e..ba41f70 100644
--- a/metropolis/node/core/update/e2e/e2e_test.go
+++ b/metropolis/node/core/update/e2e/e2e_test.go
@@ -32,20 +32,19 @@
// These are filled by bazel at linking time with the canonical path of
// their corresponding file. Inside the init function we resolve it
// with the rules_go runfiles package to the real path.
+ xImageXPath string
xImageYPath string
xImageZPath string
xOvmfVarsPath string
xOvmfCodePath string
- xBootPath string
- xSystemXPath string
xAbloaderPath string
)
func init() {
var err error
for _, path := range []*string{
- &xImageYPath, &xImageZPath, &xOvmfVarsPath,
- &xOvmfCodePath, &xBootPath, &xSystemXPath,
+ &xImageXPath, &xImageYPath, &xImageZPath,
+ &xOvmfVarsPath, &xOvmfCodePath,
&xAbloaderPath,
} {
*path, err = runfiles.Rlocation(*path)
@@ -141,6 +140,10 @@
Port: 80,
}
+ imageX, err := oci.ReadLayout(xImageXPath)
+ if err != nil {
+ t.Fatal(err)
+ }
imageY, err := oci.ReadLayout(xImageYPath)
if err != nil {
t.Fatal(err)
@@ -150,7 +153,7 @@
t.Fatal(err)
}
- osImageY, err := osimage.Read(imageY)
+ osImageX, err := osimage.Read(imageX)
if err != nil {
t.Fatal(err)
}
@@ -175,26 +178,15 @@
t.Cleanup(func() { os.Remove(rootDevPath) })
defer rootDisk.Close()
- boot, err := structfs.OSPathBlob(xBootPath)
- if err != nil {
- t.Fatal(err)
- }
- system, err := structfs.OSPathBlob(xSystemXPath)
- if err != nil {
- t.Fatal(err)
- }
-
loader, err := structfs.OSPathBlob(xAbloaderPath)
if err != nil {
t.Fatal(err)
}
if _, err := install.Write(&install.Params{
- Output: rootDisk,
- Architecture: osImageY.Config.ProductInfo.Architecture(),
- ABLoader: loader,
- EFIPayload: boot,
- SystemImage: system,
+ Output: rootDisk,
+ OSImage: osImageX,
+ ABLoader: loader,
PartitionSize: install.PartitionSizeInfo{
ESP: 128,
System: 256,
diff --git a/metropolis/node/core/update/e2e/testos/testos.bzl b/metropolis/node/core/update/e2e/testos/testos.bzl
index b0665c0..ab7d2f0 100644
--- a/metropolis/node/core/update/e2e/testos/testos.bzl
+++ b/metropolis/node/core/update/e2e/testos/testos.bzl
@@ -24,7 +24,6 @@
verity_image(
name = "verity_rootfs_" + variant,
source = ":rootfs_" + variant,
- visibility = ["//metropolis/node/core/update/e2e:__pkg__"],
)
efi_unified_kernel_image(
@@ -32,7 +31,6 @@
cmdline = "console=ttyS0 quiet rootfstype=erofs init=/init loadpin.exclude=kexec-image,kexec-initramfs",
kernel = "//third_party/linux",
verity = ":verity_rootfs_" + variant,
- visibility = ["//metropolis/node/core/update/e2e:__pkg__"],
)
test_product_info(
diff --git a/metropolis/test/launch/cluster.go b/metropolis/test/launch/cluster.go
index 744c0cc..118b82d 100644
--- a/metropolis/test/launch/cluster.go
+++ b/metropolis/test/launch/cluster.go
@@ -175,15 +175,6 @@
return nil, fmt.Errorf("failed to read OS image: %w", err)
}
- efiPayload, err := osImage.PayloadUnverified("kernel.efi")
- if err != nil {
- return nil, fmt.Errorf("cannot open EFI payload in OS image: %w", err)
- }
- systemImage, err := osImage.PayloadUnverified("system")
- if err != nil {
- return nil, fmt.Errorf("cannot open system image in OS image: %w", err)
- }
-
abloader, err := structfs.OSPathBlob(xAbloaderPath)
if err != nil {
return nil, fmt.Errorf("cannot open abloader: %w", err)
@@ -204,11 +195,10 @@
System: 1024,
Data: 128,
},
- Architecture: osImage.Config.ProductInfo.Architecture(),
- SystemImage: systemImage,
- EFIPayload: efiPayload,
- ABLoader: abloader,
- Output: df,
+ OSImage: osImage,
+ UnverifiedPayloads: true,
+ ABLoader: abloader,
+ Output: df,
}
if _, err := install.Write(installParams); err != nil {