From fd93d7c202863b04407eaf6db3f3ffdef1e12b3a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 5 Aug 2025 17:50:32 +0200 Subject: [PATCH 1/8] fixup! run go get github.com/osbuild/images@main Replace this with an images library release --- bib/go.mod | 38 +++++++++++++-------------- bib/go.sum | 76 +++++++++++++++++++++++++++--------------------------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/bib/go.mod b/bib/go.mod index c06261ddd..bdc37a5a3 100644 --- a/bib/go.mod +++ b/bib/go.mod @@ -7,7 +7,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/osbuild/blueprint v1.13.0 github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3 - github.com/osbuild/images v0.179.0 + github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.7 @@ -23,25 +23,25 @@ require ( github.com/Microsoft/hcsshim v0.13.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect - github.com/aws/aws-sdk-go-v2 v1.38.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.38.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 // indirect - github.com/aws/aws-sdk-go-v2/config v1.31.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.4 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.2 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.244.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.245.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.3 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.87.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.28.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.37.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.4 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.87.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect github.com/aws/smithy-go v1.22.5 // indirect github.com/containerd/cgroups/v3 v3.0.5 // indirect github.com/containerd/errdefs v1.0.0 // indirect @@ -127,8 +127,8 @@ require ( golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect google.golang.org/grpc v1.74.2 // indirect google.golang.org/protobuf v1.36.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/bib/go.sum b/bib/go.sum index f8e4ed121..818795241 100644 --- a/bib/go.sum +++ b/bib/go.sum @@ -14,44 +14,44 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/aws/aws-sdk-go-v2 v1.38.0 h1:UCRQ5mlqcFk9HJDIqENSLR3wiG1VTWlyUfLDEvY7RxU= -github.com/aws/aws-sdk-go-v2 v1.38.0/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= +github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 h1:6GMWV6CNpA/6fbFHnoAjrv4+LGfyTqZz2LtCHnspgDg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0/go.mod h1:/mXlTIVG9jbxkqDnr5UQNQxW1HRYxeGklkM9vAFeabg= -github.com/aws/aws-sdk-go-v2/config v1.31.0 h1:9yH0xiY5fUnVNLRWO0AtayqwU1ndriZdN78LlhruJR4= -github.com/aws/aws-sdk-go-v2/config v1.31.0/go.mod h1:VeV3K72nXnhbe4EuxxhzsDc/ByrCSlZwUnWH52Nde/I= -github.com/aws/aws-sdk-go-v2/credentials v1.18.4 h1:IPd0Algf1b+Qy9BcDp0sCUcIWdCQPSzDoMK3a8pcbUM= -github.com/aws/aws-sdk-go-v2/credentials v1.18.4/go.mod h1:nwg78FjH2qvsRM1EVZlX9WuGUJOL5od+0qvm0adEzHk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3 h1:GicIdnekoJsjq9wqnvyi2elW6CGMSYKhdozE7/Svh78= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.3/go.mod h1:R7BIi6WNC5mc1kfRM7XM/VHC3uRWkjc396sfabq4iOo= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4 h1:0SzCLoPRSK3qSydsaFQWugP+lOBCTPwfcBOm6222+UA= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.18.4/go.mod h1:JAet9FsBHjfdI+TnMBX4ModNNaQHAd3dc/Bk+cNsxeM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3 h1:o9RnO+YZ4X+kt5Z7Nvcishlz0nksIt2PIzDglLMP0vA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.3/go.mod h1:+6aLJzOG1fvMOyzIySYjOFjcguGvVRL68R+uoRencN4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3 h1:joyyUFhiTQQmVK6ImzNU9TQSNRNeD9kOklqTzyk5v6s= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.3/go.mod h1:+vNIyZQP3b3B1tSLI0lxvrU9cfM7gpdRXMFfm67ZcPc= +github.com/aws/aws-sdk-go-v2/config v1.31.2 h1:NOaSZpVGEH2Np/c1toSeW0jooNl+9ALmsUTZ8YvkJR0= +github.com/aws/aws-sdk-go-v2/config v1.31.2/go.mod h1:17ft42Yb2lF6OigqSYiDAiUcX4RIkEMY6XxEMJsrAes= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiarX4T9qU/6AZ9SucU= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.0 h1:2FFgK3oFA8PTNBjprLFfcmkgg7U9YuSimBvR64RUmiA= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.0/go.mod h1:xdxj6nC1aU/jAO80RIlIj3fU40MOSqutEA9N2XFct04= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.3 h1:ZV2XK2L3HBq9sCKQiQ/MdhZJppH/rH0vddEAamsHUIs= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.3/go.mod h1:b9F9tk2HdHpbf3xbN7rUZcfmJI26N6NcJu/8OsBFI/0= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.244.0 h1:KfETrpt7yv2nkSrjOltgmKyAl8scbzYc4TFtZeoV6uc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.244.0/go.mod h1:EeWmteKqZjaMj45MUmPET1SisFI+HkqWIRQoyjMivcc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.4 h1:BE/MNQ86yzTINrfxPPFS86QCBNQeLKY2A0KhDh47+wI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.4/go.mod h1:SPBBhkJxjcrzJBc+qY85e83MQ2q3qdra8fghhkkyrJg= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.245.2 h1:P94OfRObDwjklbvdJTGuRZXeGYF7Bv5NNUo+I628kKQ= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.245.2/go.mod h1:D8Wb993SJuFQ10Lp95Vod8VTpYjJz4v0LeW4rEI471c= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.3 h1:3ZKmesYBaFX33czDl6mbrcHb6jeheg6LqjJhQdefhsY= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.3/go.mod h1:7ryVb78GLCnjq7cw45N6oUb9REl7/vNUwjvIqC5UgdY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3 h1:ieRzyHXypu5ByllM7Sp4hC5f/1Fy5wqxqY0yB85hC7s= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.3/go.mod h1:O5ROz8jHiOAKAwx179v+7sHMhfobFVi6nZt8DEyiYoM= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.3 h1:SE/e52dq9a05RuxzLcjT+S5ZpQobj3ie3UTaSf2NnZc= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.3/go.mod h1:zkpvBTsR020VVr8TOrwK2TrUW9pOir28sH5ECHpnAfo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.87.0 h1:egoDf+Geuuntmw79Mz6mk9gGmELCPzg5PFEABOHB+6Y= -github.com/aws/aws-sdk-go-v2/service/s3 v1.87.0/go.mod h1:t9MDi29H+HDbkolTSQtbI0HP9DemAWQzUjmWC7LGMnE= -github.com/aws/aws-sdk-go-v2/service/sso v1.28.0 h1:Mc/MKBf2m4VynyJkABoVEN+QzkfLqGj0aiJuEe7cMeM= -github.com/aws/aws-sdk-go-v2/service/sso v1.28.0/go.mod h1:iS5OmxEcN4QIPXARGhavH7S8kETNL11kym6jhoS7IUQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0 h1:6csaS/aJmqZQbKhi1EyEMM7yBW653Wy/B9hnBofW+sw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.0/go.mod h1:59qHWaY5B+Rs7HGTuVGaC32m0rdpQ68N8QCN3khYiqs= -github.com/aws/aws-sdk-go-v2/service/sts v1.37.0 h1:MG9VFW43M4A8BYeAfaJJZWrroinxeTi2r3+SnmLQfSA= -github.com/aws/aws-sdk-go-v2/service/sts v1.37.0/go.mod h1:JdeBDPgpJfuS6rU/hNglmOigKhyEZtBmbraLE4GK1J8= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.4 h1:Beh9oVgtQnBgR4sKKzkUBRQpf1GnL4wt0l4s8h2VCJ0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.4/go.mod h1:b17At0o8inygF+c6FOD3rNyYZufPw62o9XJbSfQPgbo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.4 h1:HVSeukL40rHclNcUqVcBwE1YoZhOkoLeBfhUqR3tjIU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.4/go.mod h1:DnbBOv4FlIXHj2/xmrUQYtawRFC9L9ZmQPz+DBc6X5I= +github.com/aws/aws-sdk-go-v2/service/s3 v1.87.1 h1:2n6Pd67eJwAb/5KCX62/8RTU0aFAAW7V5XIGSghiHrw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.87.1/go.mod h1:w5PC+6GHLkvMJKasYGVloB3TduOtROEMqm15HSuIbw4= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 h1:iV1Ko4Em/lkJIsoKyGfc0nQySi+v0Udxr6Igq+y9JZc= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -245,8 +245,8 @@ github.com/osbuild/blueprint v1.13.0 h1:blo22+S2ZX5bBmjGcRveoTUrV4Ms7kLfKyb32Wyu github.com/osbuild/blueprint v1.13.0/go.mod h1:HPlJzkEl7q5g8hzaGksUk7ifFAy9QFw9LmzhuFOAVm4= github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3 h1:M3yYunKH4quwJLQrnFo7dEwCTKorafNC+AUqAo7m5Yo= github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3/go.mod h1:0sEmiQiMo1ChSuOoeONN0RmsoZbQEvj2mlO2448gC5w= -github.com/osbuild/images v0.179.0 h1:E0CkI/UVuiVmgq0BIhzanjaOkf4auFSSDNXiy9jwDl4= -github.com/osbuild/images v0.179.0/go.mod h1:7CfDwGb8YA4erIzvMnqJysVpSu52i6l/f3h82usGPTg= +github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f h1:y3TJJ8Gy8LZwk9NYGESD9U9IxkkCS1rVHz1jwFn9UyE= +github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f/go.mod h1:qbGjthiOmiZr1xCJEYMHv5oPNXXcxkJyvj7dky4/ibw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -463,10 +463,10 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From a3594ebcf5884a7b2b8860b86db9b1acb4de499e Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 5 Aug 2025 13:24:59 +0200 Subject: [PATCH 2/8] many: switch to use manifests from the "images" library This commit removes most of the code that deals with generating the osbuild manifest and imports the new support for this from the images library instead. Only disk images are supported for now. --- bib/cmd/bootc-image-builder/image.go | 388 --------------------------- bib/cmd/bootc-image-builder/main.go | 92 ++++--- 2 files changed, 59 insertions(+), 421 deletions(-) diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index 8ea203191..e4ffbf382 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -2,7 +2,6 @@ package main import ( cryptorand "crypto/rand" - "errors" "fmt" "math" "math/big" @@ -17,15 +16,12 @@ import ( "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/customizations/anaconda" "github.com/osbuild/images/pkg/customizations/kickstart" - "github.com/osbuild/images/pkg/customizations/users" "github.com/osbuild/images/pkg/disk" "github.com/osbuild/images/pkg/disk/partition" "github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/osbuild" - "github.com/osbuild/images/pkg/pathpolicy" "github.com/osbuild/images/pkg/platform" - "github.com/osbuild/images/pkg/policies" "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/runner" "github.com/sirupsen/logrus" @@ -34,9 +30,6 @@ import ( "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" ) -// TODO: Auto-detect this from container image metadata -const DEFAULT_SIZE = uint64(10 * GibiByte) - type ManifestConfig struct { // OCI image path (without the transport, that is always docker://) Imgref string @@ -50,10 +43,6 @@ type ManifestConfig struct { // CPU architecture of the image Architecture arch.Arch - // The minimum size required for the root fs in order to fit the container - // contents - RootfsMinsize uint64 - // Paths to the directory with the distro definitions DistroDefPaths []string @@ -68,383 +57,6 @@ type ManifestConfig struct { UseLibrepo bool } -func Manifest(c *ManifestConfig) (*manifest.Manifest, error) { - rng := createRand() - - if c.ImageTypes.BuildsISO() { - return manifestForISO(c, rng) - } - return manifestForDiskImage(c, rng) -} - -var ( - // The mountpoint policy for bootc images is more restrictive than the - // ostree mountpoint policy defined in osbuild/images. It only allows / - // (for sizing the root partition) and custom mountpoints under /var but - // not /var itself. - - // Since our policy library doesn't support denying a path while allowing - // its subpaths (only the opposite), we augment the standard policy check - // with a simple search through the custom mountpoints to deny /var - // specifically. - mountpointPolicy = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{ - // allow all existing mountpoints (but no subdirs) to support size customizations - "/": {Deny: false, Exact: true}, - "/boot": {Deny: false, Exact: true}, - - // /var is not allowed, but we need to allow any subdirectories that - // are not denied below, so we allow it initially and then check it - // separately (in checkMountpoints()) - "/var": {Deny: false}, - - // /var subdir denials - "/var/home": {Deny: true}, - "/var/lock": {Deny: true}, // symlink to ../run/lock which is on tmpfs - "/var/mail": {Deny: true}, // symlink to spool/mail - "/var/mnt": {Deny: true}, - "/var/roothome": {Deny: true}, - "/var/run": {Deny: true}, // symlink to ../run which is on tmpfs - "/var/srv": {Deny: true}, - "/var/usrlocal": {Deny: true}, - }) - - mountpointMinimalPolicy = pathpolicy.NewPathPolicies(map[string]pathpolicy.PathPolicy{ - // allow all existing mountpoints to support size customizations - "/": {Deny: false, Exact: true}, - "/boot": {Deny: false, Exact: true}, - }) -) - -func checkMountpoints(filesystems []blueprint.FilesystemCustomization, policy *pathpolicy.PathPolicies) error { - errs := []error{} - for _, fs := range filesystems { - if err := policy.Check(fs.Mountpoint); err != nil { - errs = append(errs, err) - } - if fs.Mountpoint == "/var" { - // this error message is consistent with the errors returned by policy.Check() - // TODO: remove trailing space inside the quoted path when the function is fixed in osbuild/images. - errs = append(errs, fmt.Errorf(`path "/var" is not allowed`)) - } - } - if len(errs) > 0 { - return fmt.Errorf("the following errors occurred while validating custom mountpoints:\n%w", errors.Join(errs...)) - } - return nil -} - -func checkFilesystemCustomizations(fsCustomizations []blueprint.FilesystemCustomization, ptmode partition.PartitioningMode) error { - var policy *pathpolicy.PathPolicies - switch ptmode { - case partition.BtrfsPartitioningMode: - // btrfs subvolumes are not supported at build time yet, so we only - // allow / and /boot to be customized when building a btrfs disk (the - // minimal policy) - policy = mountpointMinimalPolicy - default: - policy = mountpointPolicy - } - if err := checkMountpoints(fsCustomizations, policy); err != nil { - return err - } - return nil -} - -// updateFilesystemSizes updates the size of the root filesystem customization -// based on the minRootSize. The new min size whichever is larger between the -// existing size and the minRootSize. If the root filesystem is not already -// configured, a new customization is added. -func updateFilesystemSizes(fsCustomizations []blueprint.FilesystemCustomization, minRootSize uint64) []blueprint.FilesystemCustomization { - updated := make([]blueprint.FilesystemCustomization, len(fsCustomizations), len(fsCustomizations)+1) - hasRoot := false - for idx, fsc := range fsCustomizations { - updated[idx] = fsc - if updated[idx].Mountpoint == "/" { - updated[idx].MinSize = max(updated[idx].MinSize, minRootSize) - hasRoot = true - } - } - - if !hasRoot { - // no root customization found: add it - updated = append(updated, blueprint.FilesystemCustomization{Mountpoint: "/", MinSize: minRootSize}) - } - return updated -} - -// setFSTypes sets the filesystem types for all mountable entities to match the -// selected rootfs type. -// If rootfs is 'btrfs', the function will keep '/boot' to its default. -func setFSTypes(pt *disk.PartitionTable, rootfs string) error { - if rootfs == "" { - return fmt.Errorf("root filesystem type is empty") - } - - return pt.ForEachMountable(func(mnt disk.Mountable, _ []disk.Entity) error { - switch mnt.GetMountpoint() { - case "/boot/efi": - // never change the efi partition's type - return nil - case "/boot": - // change only if we're not doing btrfs - if rootfs == "btrfs" { - return nil - } - fallthrough - default: - switch elem := mnt.(type) { - case *disk.Filesystem: - elem.Type = rootfs - case *disk.BtrfsSubvolume: - // nothing to do - default: - return fmt.Errorf("the mountable disk entity for %q of the base partition table is not an ordinary filesystem but %T", mnt.GetMountpoint(), mnt) - } - return nil - } - }) -} - -func genPartitionTable(c *ManifestConfig, customizations *blueprint.Customizations, rng *rand.Rand) (*disk.PartitionTable, error) { - fsCust := customizations.GetFilesystems() - diskCust, err := customizations.GetPartitioning() - if err != nil { - return nil, fmt.Errorf("error reading disk customizations: %w", err) - } - - // Embedded disk customization applies if there was no local customization - if fsCust == nil && diskCust == nil && c.SourceInfo != nil && c.SourceInfo.ImageCustomization != nil { - imageCustomizations := c.SourceInfo.ImageCustomization - - fsCust = imageCustomizations.GetFilesystems() - diskCust, err = imageCustomizations.GetPartitioning() - if err != nil { - return nil, fmt.Errorf("error reading disk customizations: %w", err) - } - } - - var partitionTable *disk.PartitionTable - switch { - // XXX: move into images library - case fsCust != nil && diskCust != nil: - return nil, fmt.Errorf("cannot combine disk and filesystem customizations") - case diskCust != nil: - partitionTable, err = genPartitionTableDiskCust(c, diskCust, rng) - if err != nil { - return nil, err - } - default: - partitionTable, err = genPartitionTableFsCust(c, fsCust, rng) - if err != nil { - return nil, err - } - } - - // Ensure ext4 rootfs has fs-verity enabled - rootfs := partitionTable.FindMountable("/") - if rootfs != nil { - switch elem := rootfs.(type) { - case *disk.Filesystem: - if elem.Type == "ext4" { - elem.MkfsOptions = append(elem.MkfsOptions, []disk.MkfsOption{disk.MkfsVerity}...) - } - } - } - - return partitionTable, nil -} - -// calcRequiredDirectorySizes will calculate the minimum sizes for / -// for disk customizations. We need this because with advanced partitioning -// we never grow the rootfs to the size of the disk (unlike the tranditional -// filesystem customizations). -// -// So we need to go over the customizations and ensure the min-size for "/" -// is at least rootfsMinSize. -// -// Note that a custom "/usr" is not supported in image mode so splitting -// rootfsMinSize between / and /usr is not a concern. -func calcRequiredDirectorySizes(distCust *blueprint.DiskCustomization, rootfsMinSize uint64) (map[string]uint64, error) { - // XXX: this has *way* too much low-level knowledge about the - // inner workings of blueprint.DiskCustomizations plus when - // a new type it needs to get added here too, think about - // moving into "images" instead (at least partly) - mounts := map[string]uint64{} - for _, part := range distCust.Partitions { - switch part.Type { - case "", "plain": - mounts[part.Mountpoint] = part.MinSize - case "lvm": - for _, lv := range part.LogicalVolumes { - mounts[lv.Mountpoint] = part.MinSize - } - case "btrfs": - for _, subvol := range part.Subvolumes { - mounts[subvol.Mountpoint] = part.MinSize - } - default: - return nil, fmt.Errorf("unknown disk customization type %q", part.Type) - } - } - // ensure rootfsMinSize is respected - return map[string]uint64{ - "/": max(rootfsMinSize, mounts["/"]), - }, nil -} - -func genPartitionTableDiskCust(c *ManifestConfig, diskCust *blueprint.DiskCustomization, rng *rand.Rand) (*disk.PartitionTable, error) { - if err := diskCust.ValidateLayoutConstraints(); err != nil { - return nil, fmt.Errorf("cannot use disk customization: %w", err) - } - - diskCust.MinSize = max(diskCust.MinSize, c.RootfsMinsize) - - basept, ok := partitionTables[c.Architecture.String()] - if !ok { - return nil, fmt.Errorf("pipelines: no partition tables defined for %s", c.Architecture) - } - defaultFSType, err := disk.NewFSType(c.RootFSType) - if err != nil { - return nil, err - } - requiredMinSizes, err := calcRequiredDirectorySizes(diskCust, c.RootfsMinsize) - if err != nil { - return nil, err - } - partOptions := &disk.CustomPartitionTableOptions{ - PartitionTableType: basept.Type, - // XXX: not setting/defaults will fail to boot with btrfs/lvm - BootMode: platform.BOOT_HYBRID, - DefaultFSType: defaultFSType, - RequiredMinSizes: requiredMinSizes, - Architecture: c.Architecture, - } - return disk.NewCustomPartitionTable(diskCust, partOptions, rng) -} - -func genPartitionTableFsCust(c *ManifestConfig, fsCust []blueprint.FilesystemCustomization, rng *rand.Rand) (*disk.PartitionTable, error) { - basept, ok := partitionTables[c.Architecture.String()] - if !ok { - return nil, fmt.Errorf("pipelines: no partition tables defined for %s", c.Architecture) - } - - partitioningMode := partition.RawPartitioningMode - if c.RootFSType == "btrfs" { - partitioningMode = partition.BtrfsPartitioningMode - } - if err := checkFilesystemCustomizations(fsCust, partitioningMode); err != nil { - return nil, err - } - fsCustomizations := updateFilesystemSizes(fsCust, c.RootfsMinsize) - - pt, err := disk.NewPartitionTable(&basept, fsCustomizations, DEFAULT_SIZE, partitioningMode, c.Architecture, nil, rng) - if err != nil { - return nil, err - } - - if err := setFSTypes(pt, c.RootFSType); err != nil { - return nil, fmt.Errorf("error setting root filesystem type: %w", err) - } - return pt, nil -} - -func manifestForDiskImage(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest, error) { - if c.Imgref == "" { - return nil, fmt.Errorf("pipeline: no base image defined") - } - containerSource := container.SourceSpec{ - Source: c.Imgref, - Name: c.Imgref, - Local: true, - } - buildContainerSource := container.SourceSpec{ - Source: c.BuildImgref, - Name: c.BuildImgref, - Local: true, - } - - var customizations *blueprint.Customizations - if c.Config != nil { - customizations = c.Config.Customizations - } - - img := image.NewBootcDiskImage(containerSource, buildContainerSource) - img.OSCustomizations.Users = users.UsersFromBP(customizations.GetUsers()) - img.OSCustomizations.Groups = users.GroupsFromBP(customizations.GetGroups()) - img.OSCustomizations.SELinux = c.SourceInfo.SELinuxPolicy - img.OSCustomizations.BuildSELinux = img.OSCustomizations.SELinux - if c.BuildSourceInfo != nil { - img.OSCustomizations.BuildSELinux = c.BuildSourceInfo.SELinuxPolicy - } - - img.OSCustomizations.KernelOptionsAppend = []string{ - "rw", - // TODO: Drop this as we expect kargs to come from the container image, - // xref https://github.com/CentOS/centos-bootc-layered/blob/main/cloud/usr/lib/bootc/install/05-cloud-kargs.toml - "console=tty0", - "console=ttyS0", - } - - img.Platform = &platform.Data{ - Arch: c.Architecture, - UEFIVendor: c.SourceInfo.UEFIVendor, - QCOW2Compat: "1.1", - } - switch c.Architecture { - case arch.ARCH_X86_64: - img.Platform.(*platform.Data).BIOSPlatform = "i386-pc" - case arch.ARCH_PPC64LE: - img.Platform.(*platform.Data).BIOSPlatform = "powerpc-ieee1275" - case arch.ARCH_S390X: - img.Platform.(*platform.Data).ZiplSupport = true - } - - if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" { - img.OSCustomizations.KernelOptionsAppend = append(img.OSCustomizations.KernelOptionsAppend, kopts.Append) - } - - pt, err := genPartitionTable(c, customizations, rng) - if err != nil { - return nil, err - } - img.PartitionTable = pt - - // Check Directory/File Customizations are valid - dc := customizations.GetDirectories() - fc := customizations.GetFiles() - if err := blueprint.ValidateDirFileCustomizations(dc, fc); err != nil { - return nil, err - } - if err := blueprint.CheckDirectoryCustomizationsPolicy(dc, policies.OstreeCustomDirectoriesPolicies); err != nil { - return nil, err - } - if err := blueprint.CheckFileCustomizationsPolicy(fc, policies.OstreeCustomFilesPolicies); err != nil { - return nil, err - } - img.OSCustomizations.Files, err = blueprint.FileCustomizationsToFsNodeFiles(fc) - if err != nil { - return nil, err - } - img.OSCustomizations.Directories, err = blueprint.DirectoryCustomizationsToFsNodeDirectories(dc) - if err != nil { - return nil, err - } - - // For the bootc-disk image, the filename is the basename and the extension - // is added automatically for each disk format - img.Filename = "disk" - - mf := manifest.New() - mf.Distro = manifest.DISTRO_FEDORA - runner := &runner.Linux{} - - if err := img.InstantiateManifestFromContainers(&mf, []container.SourceSpec{containerSource}, runner, rng); err != nil { - return nil, err - } - - return &mf, nil -} - func labelForISO(os *osinfo.OSRelease, arch *arch.Arch) string { switch os.ID { case "fedora": diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index db1ee508d..2e2993005 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -1,10 +1,12 @@ package main import ( + "bytes" "encoding/json" "errors" "fmt" "io" + "io/fs" "log" "os" "os/exec" @@ -18,15 +20,19 @@ import ( "github.com/spf13/pflag" "golang.org/x/exp/slices" + repos "github.com/osbuild/images/data/repositories" "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/bib/blueprintload" "github.com/osbuild/images/pkg/cloud" "github.com/osbuild/images/pkg/cloud/awscloud" "github.com/osbuild/images/pkg/container" + "github.com/osbuild/images/pkg/distro/bootc" "github.com/osbuild/images/pkg/dnfjson" "github.com/osbuild/images/pkg/experimentalflags" "github.com/osbuild/images/pkg/manifest" + "github.com/osbuild/images/pkg/manifestgen" "github.com/osbuild/images/pkg/osbuild" + "github.com/osbuild/images/pkg/reporegistry" "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" @@ -35,15 +41,6 @@ import ( "github.com/osbuild/image-builder-cli/pkg/progress" "github.com/osbuild/image-builder-cli/pkg/setup" - "github.com/osbuild/image-builder-cli/pkg/util" -) - -const ( - // As a baseline heuristic we double the size of - // the input container to support in-place updates. - // This is planned to be more configurable in the - // future. - containerSizeToDiskSizeMultiplier = 2 ) // all possible locations for the bib's distro definitions @@ -96,23 +93,9 @@ func inContainerOrUnknown() bool { return err == nil } -// getContainerSize returns the size of an already pulled container image in bytes -func getContainerSize(imgref string) (uint64, error) { - output, err := exec.Command("podman", "image", "inspect", imgref, "--format", "{{.Size}}").Output() - if err != nil { - return 0, fmt.Errorf("failed inspect image: %w", util.OutputErr(err)) - } - size, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64) - if err != nil { - return 0, fmt.Errorf("cannot parse image size: %w", err) - } - - logrus.Debugf("container size: %v", size) - return size, nil -} - func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (manifest.OSBuildManifest, map[string][]rpmmd.RepoConfig, error) { - mani, err := Manifest(c) + rng := createRand() + mani, err := manifestForISO(c, rng) if err != nil { return nil, nil, fmt.Errorf("cannot get manifest: %w", err) } @@ -245,23 +228,67 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress if err != nil { return nil, nil, fmt.Errorf("cannot detect build types %v: %w", imgTypes, err) } - config, err := blueprintload.LoadWithFallback(userConfigFile) if err != nil { return nil, nil, fmt.Errorf("cannot read config: %w", err) } - pbar.SetPulseMsgf("Manifest generation step") - pbar.Start() - if err := setup.ValidateHasContainerTags(imgref); err != nil { return nil, nil, err } - cntSize, err := getContainerSize(imgref) - if err != nil { - return nil, nil, fmt.Errorf("cannot get container size: %w", err) + pbar.SetPulseMsgf("Manifest generation step") + pbar.Start() + + // For now shortcut here and build ding "images" for anything + // that is not the iso + if !imageTypes.BuildsISO() { + distro, err := bootc.NewBootcDistro(imgref) + if err != nil { + return nil, nil, err + } + if err := distro.SetBuildContainer(buildImgref); err != nil { + return nil, nil, err + } + if err := distro.SetDefaultFs(rootFs); err != nil { + return nil, nil, err + } + // XXX: consider target-arch + archi, err := distro.GetArch(cntArch.String()) + if err != nil { + return nil, nil, err + } + // XXX: how to generate for all image types + imgType, err := archi.GetImageType(imgTypes[0]) + if err != nil { + return nil, nil, err + } + + var buf bytes.Buffer + repos, err := reporegistry.New(nil, []fs.FS{repos.FS}) + if err != nil { + return nil, nil, err + } + mg, err := manifestgen.New(repos, &manifestgen.Options{ + Output: &buf, + // XXX: hack to skip repo loading for the bootc image. + // We need to add a SkipRepositories or similar to + // manifestgen instead to make this clean + OverrideRepos: []rpmmd.RepoConfig{ + { + BaseURLs: []string{"https://example.com/not-used"}, + }, + }, + }) + if err != nil { + return nil, nil, err + } + if err := mg.Generate(config, distro, imgType, archi, nil); err != nil { + return nil, nil, err + } + return buf.Bytes(), nil, nil } + container, err := podman_container.New(imgref) if err != nil { return nil, nil, err @@ -334,7 +361,6 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress ImageTypes: imageTypes, Imgref: imgref, BuildImgref: buildImgref, - RootfsMinsize: cntSize * containerSizeToDiskSizeMultiplier, DistroDefPaths: distroDefPaths, SourceInfo: sourceinfo, BuildSourceInfo: buildSourceinfo, From 91016d679c354bcc99ba04dfea91107be80b479f Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 7 Aug 2025 21:08:45 +0200 Subject: [PATCH 3/8] test: update architecutre mismatch error string --- test/test_manifest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_manifest.py b/test/test_manifest.py index 91b99b861..082f3f8c0 100644 --- a/test/test_manifest.py +++ b/test/test_manifest.py @@ -151,7 +151,8 @@ def test_manifest_cross_arch_check(tmp_path, build_container): "manifest", "--target-arch=aarch64", f"localhost/{container_tag}" ], check=True, capture_output=True, encoding="utf8") - assert 'image found is for unexpected architecture "x86_64"' in exc.value.stderr + assert 'cannot generate manifest: requested container architecture '\ + 'does not match resolved container: "x86_64" !=' in exc.value.stderr def find_rootfs_type_from(manifest_str): From e797c57aaa23c357d14cc6711dde3f454ad6cde9 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 27 Aug 2025 18:50:16 +0200 Subject: [PATCH 4/8] image: update for latest images API changes The image.NewAnaconda*() functions take the platform/filename now. --- bib/cmd/bootc-image-builder/image.go | 48 +++++++++++++--------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index e4ffbf382..cf33d4edc 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -17,7 +17,6 @@ import ( "github.com/osbuild/images/pkg/customizations/anaconda" "github.com/osbuild/images/pkg/customizations/kickstart" "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/disk/partition" "github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/osbuild" @@ -95,11 +94,32 @@ func manifestForISO(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest, erro Local: true, } + platform := &platform.Data{ + Arch: c.Architecture, + ImageFormat: platform.FORMAT_ISO, + UEFIVendor: c.SourceInfo.UEFIVendor, + } + switch c.Architecture { + case arch.ARCH_X86_64: + platform.BIOSPlatform = "i386-pc" + case arch.ARCH_AARCH64: + // aarch64 always uses UEFI, so let's enforce the vendor + if c.SourceInfo.UEFIVendor == "" { + return nil, fmt.Errorf("UEFI vendor must be set for aarch64 ISO") + } + case arch.ARCH_S390X: + platform.ZiplSupport = true + case arch.ARCH_PPC64LE: + platform.BIOSPlatform = "powerpc-ieee1275" + } // The ref is not needed and will be removed from the ctor later // in time - img := image.NewAnacondaContainerInstaller(containerSource, "") + img := image.NewAnacondaContainerInstaller(platform, "install.iso", containerSource, "") img.ContainerRemoveSignatures = true img.RootfsCompression = "zstd" + if c.Architecture == arch.ARCH_X86_64 { + img.InstallerCustomizations.ISOBoot = manifest.Grub2ISOBoot + } img.Product = c.SourceInfo.OSRelease.Name img.OSVersion = c.SourceInfo.OSRelease.VersionID @@ -149,32 +169,8 @@ func manifestForISO(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest, erro } img.InstallerCustomizations.UseRHELLoraxTemplates = needsRHELLoraxTemplates(c.SourceInfo.OSRelease) - img.Platform = &platform.Data{ - Arch: c.Architecture, - ImageFormat: platform.FORMAT_ISO, - UEFIVendor: c.SourceInfo.UEFIVendor, - } - switch c.Architecture { - case arch.ARCH_X86_64: - img.Platform.(*platform.Data).BIOSPlatform = "i386-pc" - img.InstallerCustomizations.ISOBoot = manifest.Grub2ISOBoot - case arch.ARCH_AARCH64: - // aarch64 always uses UEFI, so let's enforce the vendor - if c.SourceInfo.UEFIVendor == "" { - return nil, fmt.Errorf("UEFI vendor must be set for aarch64 ISO") - } - case arch.ARCH_S390X: - img.Platform.(*platform.Data).ZiplSupport = true - case arch.ARCH_PPC64LE: - img.Platform.(*platform.Data).BIOSPlatform = "powerpc-ieee1275" - case arch.ARCH_RISCV64: - // nothing special needed - default: - return nil, fmt.Errorf("unsupported architecture %v", c.Architecture) - } // see https://github.com/osbuild/bootc-image-builder/issues/733 img.InstallerCustomizations.ISORootfsType = manifest.SquashfsRootfs - img.Filename = "install.iso" installRootfsType, err := disk.NewFSType(c.RootFSType) if err != nil { From 36aef0100cf8607f4ba3fa72a903a6a0630d5abc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 27 Aug 2025 18:56:42 +0200 Subject: [PATCH 5/8] bib: remove partition_table.go -> moved to images --- .../bootc-image-builder/partition_tables.go | 139 ------------------ 1 file changed, 139 deletions(-) delete mode 100644 bib/cmd/bootc-image-builder/partition_tables.go diff --git a/bib/cmd/bootc-image-builder/partition_tables.go b/bib/cmd/bootc-image-builder/partition_tables.go deleted file mode 100644 index 9ce5468c5..000000000 --- a/bib/cmd/bootc-image-builder/partition_tables.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "github.com/osbuild/images/pkg/arch" - "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/distro" -) - -const ( - MebiByte = 1024 * 1024 // MiB - GibiByte = 1024 * 1024 * 1024 // GiB - // BootOptions defines the mountpoint options for /boot - // See https://github.com/containers/bootc/pull/341 for the rationale for - // using `ro` by default. Briefly it protects against corruption - // by non-ostree aware tools. - BootOptions = "ro" - // And we default to `ro` for the rootfs too, because we assume the input - // container image is using composefs. For more info, see - // https://github.com/containers/bootc/pull/417 and - // https://github.com/ostreedev/ostree/issues/3193 - RootOptions = "ro" -) - -// diskUuidOfUnknownOrigin is used by default for disk images, -// picked by someone in the past for unknown reasons. More in -// e.g. https://github.com/osbuild/bootc-image-builder/pull/568 and -// https://github.com/osbuild/images/pull/823 -const diskUuidOfUnknownOrigin = "D209C89E-EA5E-4FBD-B161-B461CCE297E0" - -// efiPartition defines the default ESP. See also -// https://en.wikipedia.org/wiki/EFI_system_partition -var efiPartition = disk.Partition{ - Size: 501 * MebiByte, - Type: disk.EFISystemPartitionGUID, - UUID: disk.EFISystemPartitionUUID, - Payload: &disk.Filesystem{ - Type: "vfat", - UUID: disk.EFIFilesystemUUID, - Mountpoint: "/boot/efi", - Label: "EFI-SYSTEM", - FSTabOptions: "umask=0077,shortname=winnt", - FSTabFreq: 0, - FSTabPassNo: 2, - }, -} - -// bootPartition defines a distinct filesystem for /boot -// which is needed for e.g. LVM or LUKS when using GRUB -// (which this project doesn't support today...) -// See also https://github.com/containers/bootc/pull/529/commits/e5548d8765079171e6ed39a3ab0479bc8681a1c9 -var bootPartition = disk.Partition{ - Size: 1 * GibiByte, - Type: disk.FilesystemDataGUID, - UUID: disk.DataPartitionUUID, - Payload: &disk.Filesystem{ - Type: "ext4", - Mountpoint: "/boot", - Label: "boot", - FSTabOptions: BootOptions, - FSTabFreq: 1, - FSTabPassNo: 2, - }, -} - -// rootPartition holds the root filesystem; however note -// that while the type here defines "ext4" because the data -// type requires something there, in practice we pull -// the rootfs type from the container image by default. -// See https://containers.github.io/bootc/bootc-install.html -var rootPartition = disk.Partition{ - Size: 2 * GibiByte, - Type: disk.FilesystemDataGUID, - UUID: disk.RootPartitionUUID, - Payload: &disk.Filesystem{ - Type: "ext4", - Label: "root", - Mountpoint: "/", - FSTabOptions: RootOptions, - FSTabFreq: 1, - FSTabPassNo: 1, - }, -} - -var partitionTables = distro.BasePartitionTableMap{ - arch.ARCH_X86_64.String(): disk.PartitionTable{ - UUID: diskUuidOfUnknownOrigin, - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - { - Size: 1 * MebiByte, - Bootable: true, - Type: disk.BIOSBootPartitionGUID, - UUID: disk.BIOSBootPartitionUUID, - }, - efiPartition, - bootPartition, - rootPartition, - }, - }, - arch.ARCH_AARCH64.String(): disk.PartitionTable{ - UUID: diskUuidOfUnknownOrigin, - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - efiPartition, - bootPartition, - rootPartition, - }, - }, - arch.ARCH_S390X.String(): disk.PartitionTable{ - UUID: diskUuidOfUnknownOrigin, - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - bootPartition, - rootPartition, - }, - }, - arch.ARCH_PPC64LE.String(): disk.PartitionTable{ - UUID: diskUuidOfUnknownOrigin, - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - { - Size: 4 * MebiByte, - Type: disk.PRePartitionGUID, - Bootable: true, - }, - bootPartition, - rootPartition, - }, - }, - arch.ARCH_RISCV64.String(): disk.PartitionTable{ - UUID: diskUuidOfUnknownOrigin, - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - efiPartition, - bootPartition, - rootPartition, - }, - }, -} From 52fba9b577af42237ba1b535a87d489b7530f234 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 27 Aug 2025 19:12:43 +0200 Subject: [PATCH 6/8] bib: drop tests that moved to "images/pkg/distro/bootc" --- bib/cmd/bootc-image-builder/export_test.go | 14 +- bib/cmd/bootc-image-builder/image_test.go | 660 --------------------- bib/cmd/bootc-image-builder/main_test.go | 472 --------------- 3 files changed, 4 insertions(+), 1142 deletions(-) diff --git a/bib/cmd/bootc-image-builder/export_test.go b/bib/cmd/bootc-image-builder/export_test.go index ae62449d2..8dcbaef91 100644 --- a/bib/cmd/bootc-image-builder/export_test.go +++ b/bib/cmd/bootc-image-builder/export_test.go @@ -1,16 +1,10 @@ package main var ( - CanChownInPath = canChownInPath - CheckFilesystemCustomizations = checkFilesystemCustomizations - GetDistroAndRunner = getDistroAndRunner - CheckMountpoints = checkMountpoints - PartitionTables = partitionTables - UpdateFilesystemSizes = updateFilesystemSizes - GenPartitionTable = genPartitionTable - CreateRand = createRand - BuildCobraCmdline = buildCobraCmdline - CalcRequiredDirectorySizes = calcRequiredDirectorySizes + CanChownInPath = canChownInPath + GetDistroAndRunner = getDistroAndRunner + CreateRand = createRand + BuildCobraCmdline = buildCobraCmdline ) func MockOsGetuid(new func() int) (restore func()) { diff --git a/bib/cmd/bootc-image-builder/image_test.go b/bib/cmd/bootc-image-builder/image_test.go index acddc18fe..a204b1811 100644 --- a/bib/cmd/bootc-image-builder/image_test.go +++ b/bib/cmd/bootc-image-builder/image_test.go @@ -7,11 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/osbuild/blueprint/pkg/blueprint" - "github.com/osbuild/images/pkg/arch" - "github.com/osbuild/images/pkg/datasizes" - "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/disk/partition" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/runner" @@ -61,658 +56,3 @@ func TestGetDistroAndRunner(t *testing.T) { }) } } - -func TestCheckFilesystemCustomizationsValidates(t *testing.T) { - for _, tc := range []struct { - fsCust []blueprint.FilesystemCustomization - ptmode partition.PartitioningMode - expectedErr string - }{ - // happy - { - fsCust: []blueprint.FilesystemCustomization{}, - expectedErr: "", - }, - { - fsCust: []blueprint.FilesystemCustomization{}, - ptmode: partition.BtrfsPartitioningMode, - expectedErr: "", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, {Mountpoint: "/boot"}, - }, - ptmode: partition.RawPartitioningMode, - expectedErr: "", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, {Mountpoint: "/boot"}, - }, - ptmode: partition.BtrfsPartitioningMode, - expectedErr: "", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/boot"}, - {Mountpoint: "/var/log"}, - {Mountpoint: "/var/data"}, - }, - expectedErr: "", - }, - // sad - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/ostree"}, - }, - ptmode: partition.RawPartitioningMode, - expectedErr: "the following errors occurred while validating custom mountpoints:\npath \"/ostree\" is not allowed", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/var"}, - }, - ptmode: partition.RawPartitioningMode, - expectedErr: "the following errors occurred while validating custom mountpoints:\npath \"/var\" is not allowed", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/var/data"}, - }, - ptmode: partition.BtrfsPartitioningMode, - expectedErr: "the following errors occurred while validating custom mountpoints:\npath \"/var/data\" is not allowed", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/boot/"}, - }, - ptmode: partition.BtrfsPartitioningMode, - expectedErr: "the following errors occurred while validating custom mountpoints:\npath \"/boot/\" must be canonical", - }, - { - fsCust: []blueprint.FilesystemCustomization{ - {Mountpoint: "/"}, - {Mountpoint: "/boot/"}, - {Mountpoint: "/opt"}, - }, - ptmode: partition.BtrfsPartitioningMode, - expectedErr: "the following errors occurred while validating custom mountpoints:\npath \"/boot/\" must be canonical\npath \"/opt\" is not allowed", - }, - } { - if tc.expectedErr == "" { - assert.NoError(t, bib.CheckFilesystemCustomizations(tc.fsCust, tc.ptmode)) - } else { - assert.ErrorContains(t, bib.CheckFilesystemCustomizations(tc.fsCust, tc.ptmode), tc.expectedErr) - } - } -} - -func TestLocalMountpointPolicy(t *testing.T) { - // extended testing of the general mountpoint policy (non-minimal) - type testCase struct { - path string - allowed bool - } - - testCases := []testCase{ - // existing mountpoints / and /boot are fine for sizing - {"/", true}, - {"/boot", true}, - - // root mountpoints are not allowed - {"/data", false}, - {"/opt", false}, - {"/stuff", false}, - {"/usr", false}, - - // /var explicitly is not allowed - {"/var", false}, - - // subdirs of /boot are not allowed - {"/boot/stuff", false}, - {"/boot/loader", false}, - - // /var subdirectories are allowed - {"/var/data", true}, - {"/var/scratch", true}, - {"/var/log", true}, - {"/var/opt", true}, - {"/var/opt/application", true}, - - // but not these - {"/var/home", false}, - {"/var/lock", false}, // symlink to ../run/lock which is on tmpfs - {"/var/mail", false}, // symlink to spool/mail - {"/var/mnt", false}, - {"/var/roothome", false}, - {"/var/run", false}, // symlink to ../run which is on tmpfs - {"/var/srv", false}, - {"/var/usrlocal", false}, - - // nor their subdirs - {"/var/run/subrun", false}, - {"/var/srv/test", false}, - {"/var/home/user", false}, - {"/var/usrlocal/bin", false}, - } - - for _, tc := range testCases { - t.Run(tc.path, func(t *testing.T) { - err := bib.CheckFilesystemCustomizations([]blueprint.FilesystemCustomization{{Mountpoint: tc.path}}, partition.RawPartitioningMode) - if err != nil && tc.allowed { - t.Errorf("expected %s to be allowed, but got error: %v", tc.path, err) - } else if err == nil && !tc.allowed { - t.Errorf("expected %s to be denied, but got no error", tc.path) - } - }) - } -} - -func TestBasePartitionTablesHaveRoot(t *testing.T) { - // make sure that all base partition tables have at least a root partition defined - for arch, pt := range bib.PartitionTables { - rootMountable := pt.FindMountable("/") - if rootMountable == nil { - t.Errorf("partition table %q does not define a root filesystem", arch) - } - _, isFS := rootMountable.(*disk.Filesystem) - if !isFS { - t.Errorf("root mountable for %q is not an ordinary filesystem", arch) - } - } - -} - -func TestUpdateFilesystemSizes(t *testing.T) { - type testCase struct { - customizations []blueprint.FilesystemCustomization - minRootSize uint64 - expected []blueprint.FilesystemCustomization - } - - testCases := map[string]testCase{ - "simple": { - customizations: nil, - minRootSize: 999, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/", - MinSize: 999, - }, - }, - }, - "container-is-larger": { - customizations: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/", - MinSize: 10, - }, - }, - minRootSize: 999, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/", - MinSize: 999, - }, - }, - }, - "container-is-smaller": { - customizations: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/", - MinSize: 1000, - }, - }, - minRootSize: 892, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/", - MinSize: 1000, - }, - }, - }, - "customizations-noroot": { - customizations: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - }, - minRootSize: 9000, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - { - Mountpoint: "/", - MinSize: 9000, - }, - }, - }, - "customizations-withroot-smallcontainer": { - customizations: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - { - Mountpoint: "/", - MinSize: 2_000_000, - }, - }, - minRootSize: 9000, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - { - Mountpoint: "/", - MinSize: 2_000_000, - }, - }, - }, - "customizations-withroot-largecontainer": { - customizations: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - { - Mountpoint: "/", - MinSize: 2_000_000, - }, - }, - minRootSize: 9_000_000, - expected: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/data", - MinSize: 1_000_000, - }, - { - Mountpoint: "/", - MinSize: 9_000_000, - }, - }, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert.ElementsMatch(t, bib.UpdateFilesystemSizes(tc.customizations, tc.minRootSize), tc.expected) - }) - } - -} - -func findMountableSizeableFor(pt *disk.PartitionTable, needle string) (disk.Mountable, disk.Sizeable) { - var foundMnt disk.Mountable - var foundParent disk.Sizeable - err := pt.ForEachMountable(func(mnt disk.Mountable, path []disk.Entity) error { - if mnt.GetMountpoint() == needle { - foundMnt = mnt - for idx := len(path) - 1; idx >= 0; idx-- { - if sz, ok := path[idx].(disk.Sizeable); ok { - foundParent = sz - break - } - } - } - return nil - }) - if err != nil { - panic(err) - } - return foundMnt, foundParent -} - -func TestGenPartitionTableSetsRootfsForAllFilesystemsXFS(t *testing.T) { - rng := bib.CreateRand() - - cnf := &bib.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - RootFSType: "xfs", - } - cus := &blueprint.Customizations{ - Filesystem: []blueprint.FilesystemCustomization{ - {Mountpoint: "/var/data", MinSize: 2_000_000}, - {Mountpoint: "/var/stuff", MinSize: 10_000_000}, - }, - } - pt, err := bib.GenPartitionTable(cnf, cus, rng) - assert.NoError(t, err) - - for _, mntPoint := range []string{"/", "/boot", "/var/data"} { - mnt, _ := findMountableSizeableFor(pt, mntPoint) - assert.Equal(t, "xfs", mnt.GetFSType()) - } - _, parent := findMountableSizeableFor(pt, "/var/data") - assert.True(t, parent.GetSize() >= 2_000_000) - - _, parent = findMountableSizeableFor(pt, "/var/stuff") - assert.True(t, parent.GetSize() >= 10_000_000) - - // ESP is always vfat - mnt, _ := findMountableSizeableFor(pt, "/boot/efi") - assert.Equal(t, "vfat", mnt.GetFSType()) -} - -func TestGenPartitionTableSetsRootfsForAllFilesystemsBtrfs(t *testing.T) { - rng := bib.CreateRand() - - cnf := &bib.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - RootFSType: "btrfs", - } - cus := &blueprint.Customizations{} - pt, err := bib.GenPartitionTable(cnf, cus, rng) - assert.NoError(t, err) - - mnt, _ := findMountableSizeableFor(pt, "/") - assert.Equal(t, "btrfs", mnt.GetFSType()) - - // btrfs has a default (ext4) /boot - mnt, _ = findMountableSizeableFor(pt, "/boot") - assert.Equal(t, "ext4", mnt.GetFSType()) - - // ESP is always vfat - mnt, _ = findMountableSizeableFor(pt, "/boot/efi") - assert.Equal(t, "vfat", mnt.GetFSType()) -} - -func TestGenPartitionTableDiskCustomizationRunsValidateLayoutConstraints(t *testing.T) { - rng := bib.CreateRand() - - cnf := &bib.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - RootFSType: "xfs", - } - cus := &blueprint.Customizations{ - Disk: &blueprint.DiskCustomization{ - Partitions: []blueprint.PartitionCustomization{ - { - Type: "lvm", - VGCustomization: blueprint.VGCustomization{}, - }, - { - Type: "lvm", - VGCustomization: blueprint.VGCustomization{}, - }, - }, - }, - } - _, err := bib.GenPartitionTable(cnf, cus, rng) - assert.EqualError(t, err, "cannot use disk customization: multiple LVM volume groups are not yet supported") -} - -func TestGenPartitionTableDiskCustomizationUnknownTypesError(t *testing.T) { - cus := &blueprint.Customizations{ - Disk: &blueprint.DiskCustomization{ - Partitions: []blueprint.PartitionCustomization{ - { - Type: "rando", - }, - }, - }, - } - _, err := bib.CalcRequiredDirectorySizes(cus.Disk, 5*datasizes.GiB) - assert.EqualError(t, err, `unknown disk customization type "rando"`) -} - -func TestGenPartitionTableDiskCustomizationSizes(t *testing.T) { - rng := bib.CreateRand() - - for _, tc := range []struct { - name string - rootfsMinSize uint64 - partitions []blueprint.PartitionCustomization - expectedMinRootSize uint64 - }{ - { - "empty disk customizaton, root expands to rootfsMinsize", - 2 * datasizes.GiB, - nil, - 2 * datasizes.GiB, - }, - // plain - { - "plain, no root minsize, expands to rootfsMinSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - MinSize: 10 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/var", - FSType: "xfs", - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "plain, small root minsize, expands to rootfsMnSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - MinSize: 1 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/", - FSType: "xfs", - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "plain, big root minsize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - MinSize: 10 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/", - FSType: "xfs", - }, - }, - }, - 10 * datasizes.GiB, - }, - // btrfs - { - "btrfs, no root minsize, expands to rootfsMinSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "btrfs", - MinSize: 10 * datasizes.GiB, - BtrfsVolumeCustomization: blueprint.BtrfsVolumeCustomization{ - Subvolumes: []blueprint.BtrfsSubvolumeCustomization{ - { - Mountpoint: "/var", - Name: "varvol", - }, - }, - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "btrfs, small root minsize, expands to rootfsMnSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "btrfs", - MinSize: 1 * datasizes.GiB, - BtrfsVolumeCustomization: blueprint.BtrfsVolumeCustomization{ - Subvolumes: []blueprint.BtrfsSubvolumeCustomization{ - { - Mountpoint: "/", - Name: "rootvol", - }, - }, - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "btrfs, big root minsize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "btrfs", - MinSize: 10 * datasizes.GiB, - BtrfsVolumeCustomization: blueprint.BtrfsVolumeCustomization{ - Subvolumes: []blueprint.BtrfsSubvolumeCustomization{ - { - Mountpoint: "/", - Name: "rootvol", - }, - }, - }, - }, - }, - 10 * datasizes.GiB, - }, - // lvm - { - "lvm, no root minsize, expands to rootfsMinSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "lvm", - MinSize: 10 * datasizes.GiB, - VGCustomization: blueprint.VGCustomization{ - LogicalVolumes: []blueprint.LVCustomization{ - { - MinSize: 10 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/var", - FSType: "xfs", - }, - }, - }, - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "lvm, small root minsize, expands to rootfsMnSize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "lvm", - MinSize: 1 * datasizes.GiB, - VGCustomization: blueprint.VGCustomization{ - LogicalVolumes: []blueprint.LVCustomization{ - { - MinSize: 1 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/", - FSType: "xfs", - }, - }, - }, - }, - }, - }, - 5 * datasizes.GiB, - }, - { - "lvm, big root minsize", - 5 * datasizes.GiB, - []blueprint.PartitionCustomization{ - { - Type: "lvm", - MinSize: 10 * datasizes.GiB, - VGCustomization: blueprint.VGCustomization{ - LogicalVolumes: []blueprint.LVCustomization{ - { - MinSize: 10 * datasizes.GiB, - FilesystemTypedCustomization: blueprint.FilesystemTypedCustomization{ - Mountpoint: "/", - FSType: "xfs", - }, - }, - }, - }, - }, - }, - 10 * datasizes.GiB, - }, - } { - t.Run(tc.name, func(t *testing.T) { - cnf := &bib.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - RootFSType: "xfs", - RootfsMinsize: tc.rootfsMinSize, - } - cus := &blueprint.Customizations{ - Disk: &blueprint.DiskCustomization{ - Partitions: tc.partitions, - }, - } - pt, err := bib.GenPartitionTable(cnf, cus, rng) - assert.NoError(t, err) - - var rootSize uint64 - err = pt.ForEachMountable(func(mnt disk.Mountable, path []disk.Entity) error { - if mnt.GetMountpoint() == "/" { - for idx := len(path) - 1; idx >= 0; idx-- { - if parent, ok := path[idx].(disk.Sizeable); ok { - rootSize = parent.GetSize() - break - } - } - } - return nil - }) - assert.NoError(t, err) - // expected size is within a reasonable limit - assert.True(t, rootSize >= tc.expectedMinRootSize && rootSize < tc.expectedMinRootSize+5*datasizes.MiB) - }) - } -} - -func TestManifestFilecustomizationsSad(t *testing.T) { - config := getBaseConfig() - config.ImageTypes = []string{"qcow2"} - config.Config = &blueprint.Blueprint{ - Customizations: &blueprint.Customizations{ - Files: []blueprint.FileCustomization{ - { - Path: "/not/allowed", - Data: "some-data", - }, - }, - }, - } - - _, err := bib.Manifest(config) - assert.EqualError(t, err, `the following custom files are not allowed: ["/not/allowed"]`) -} - -func TestManifestDirCustomizationsSad(t *testing.T) { - config := getBaseConfig() - config.ImageTypes = []string{"qcow2"} - config.Config = &blueprint.Blueprint{ - Customizations: &blueprint.Customizations{ - Directories: []blueprint.DirectoryCustomization{ - { - Path: "/dir/not/allowed", - }, - }, - }, - } - - _, err := bib.Manifest(config) - assert.EqualError(t, err, `the following custom directories are not allowed: ["/dir/not/allowed"]`) -} diff --git a/bib/cmd/bootc-image-builder/main_test.go b/bib/cmd/bootc-image-builder/main_test.go index 21bbd940c..9ee0b9333 100644 --- a/bib/cmd/bootc-image-builder/main_test.go +++ b/bib/cmd/bootc-image-builder/main_test.go @@ -1,8 +1,6 @@ package main_test import ( - "encoding/json" - "errors" "fmt" "os" "strings" @@ -14,16 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/osbuild/blueprint/pkg/blueprint" - "github.com/osbuild/images/pkg/arch" - "github.com/osbuild/images/pkg/bib/osinfo" - "github.com/osbuild/images/pkg/container" - "github.com/osbuild/images/pkg/dnfjson" - "github.com/osbuild/images/pkg/manifest" - "github.com/osbuild/images/pkg/rpmmd" - main "github.com/osbuild/bootc-image-builder/bib/cmd/bootc-image-builder" - "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" ) func TestCanChownInPathHappy(t *testing.T) { @@ -60,467 +49,6 @@ func TestCanChownInPathCannotChange(t *testing.T) { assert.Equal(t, canChown, false) } -type manifestTestCase struct { - config *main.ManifestConfig - imageTypes imagetypes.ImageTypes - depsolved map[string]dnfjson.DepsolveResult - containers map[string][]container.Spec - expStages map[string][]string - notExpectedStages map[string][]string - err interface{} -} - -func getBaseConfig() *main.ManifestConfig { - return &main.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - Imgref: "testempty", - SourceInfo: &osinfo.Info{ - OSRelease: osinfo.OSRelease{ - ID: "fedora", - VersionID: "40", - Name: "Fedora Linux", - PlatformID: "platform:f40", - }, - UEFIVendor: "fedora", - }, - - // We need the real path here, because we are creating real manifests - DistroDefPaths: []string{"../../data/defs"}, - - // RootFSType is required to create a Manifest - RootFSType: "ext4", - } -} - -func getUserConfig() *main.ManifestConfig { - // add a user - pass := "super-secret-password-42" - key := "ssh-ed25519 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - return &main.ManifestConfig{ - Architecture: arch.ARCH_X86_64, - Imgref: "testuser", - Config: &blueprint.Blueprint{ - Customizations: &blueprint.Customizations{ - User: []blueprint.UserCustomization{ - { - Name: "tester", - Password: &pass, - Key: &key, - }, - }, - }, - }, - SourceInfo: &osinfo.Info{ - OSRelease: osinfo.OSRelease{ - ID: "fedora", - VersionID: "40", - Name: "Fedora Linux", - PlatformID: "platform:f40", - }, - UEFIVendor: "fedora", - }, - - // We need the real path here, because we are creating real manifests - DistroDefPaths: []string{"../../data/defs"}, - - // RootFSType is required to create a Manifest - RootFSType: "ext4", - } -} - -func TestManifestGenerationEmptyConfig(t *testing.T) { - baseConfig := getBaseConfig() - testCases := map[string]manifestTestCase{ - "ami-base": { - config: baseConfig, - imageTypes: []string{"ami"}, - }, - "raw-base": { - config: baseConfig, - imageTypes: []string{"raw"}, - }, - "qcow2-base": { - config: baseConfig, - imageTypes: []string{"qcow2"}, - }, - "iso-base": { - config: baseConfig, - imageTypes: []string{"iso"}, - }, - "empty-config": { - config: &main.ManifestConfig{}, - imageTypes: []string{"qcow2"}, - err: errors.New("pipeline: no base image defined"), - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - config := main.ManifestConfig(*tc.config) - config.ImageTypes = tc.imageTypes - _, err := main.Manifest(&config) - assert.Equal(t, err, tc.err) - }) - } -} - -func TestManifestGenerationUserConfig(t *testing.T) { - userConfig := getUserConfig() - testCases := map[string]manifestTestCase{ - "ami-user": { - config: userConfig, - imageTypes: []string{"ami"}, - }, - "raw-user": { - config: userConfig, - imageTypes: []string{"raw"}, - }, - "qcow2-user": { - config: userConfig, - imageTypes: []string{"qcow2"}, - }, - "iso-user": { - config: userConfig, - imageTypes: []string{"iso"}, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - config := main.ManifestConfig(*tc.config) - config.ImageTypes = tc.imageTypes - _, err := main.Manifest(&config) - assert.NoError(t, err) - }) - } -} - -// Disk images require a container for the build/image pipelines -var containerSpec = container.Spec{ - Source: "test-container", - Digest: "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", - ImageID: "sha256:1111111111111111111111111111111111111111111111111111111111111111", -} - -// diskContainers can be passed to Serialize() to get a minimal disk image -var diskContainers = map[string][]container.Spec{ - "build": { - containerSpec, - }, - "image": { - containerSpec, - }, - "target": { - containerSpec, - }, -} - -// TODO: this tests at this layer is not ideal, it has too much knowledge -// over the implementation details of the "images" library and how an -// image.NewBootcDiskImage() works (i.e. what the pipeline names are and -// what key piplines to expect). These details should be tested in "images" -// and here we would just check (somehow) that image.NewBootcDiskImage() -// (or image.NewAnacondaContainerInstaller()) is called and the right -// customizations are passed. The existing layout makes this hard so this -// is fine for now but would be nice to revisit this. -func TestManifestSerialization(t *testing.T) { - // Tests that the manifest is generated without error and is serialized - // with expected key stages. - - // ISOs require a container for the bootiso-tree, build packages, and packages for the anaconda-tree (with a kernel). - var isoContainers = map[string][]container.Spec{ - "bootiso-tree": { - containerSpec, - }, - } - isoPackages := map[string]dnfjson.DepsolveResult{ - "build": { - Packages: []rpmmd.PackageSpec{ - { - Name: "package", - Version: "113", - Checksum: "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - }, - }, - }, - "anaconda-tree": { - Packages: []rpmmd.PackageSpec{ - { - Name: "kernel", - Version: "10.11", - Checksum: "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - }, - { - Name: "package", - Version: "113", - Checksum: "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - }, - }, - }, - } - - pkgsNoBuild := map[string]dnfjson.DepsolveResult{ - "anaconda-tree": { - Packages: []rpmmd.PackageSpec{ - - { - Name: "kernel", - Version: "10.11", - Checksum: "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - }, - { - Name: "package", - Version: "113", - Checksum: "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - }, - }, - }, - } - - baseConfig := getBaseConfig() - userConfig := getUserConfig() - testCases := map[string]manifestTestCase{ - "ami-base": { - config: baseConfig, - imageTypes: []string{"ami"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - "image": { - "org.osbuild.users", - }, - }, - }, - "raw-base": { - config: baseConfig, - imageTypes: []string{"raw"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - "image": { - "org.osbuild.users", - }, - }, - }, - "qcow2-base": { - config: baseConfig, - imageTypes: []string{"qcow2"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - "image": { - "org.osbuild.users", - }, - }, - }, - "ami-user": { - config: userConfig, - imageTypes: []string{"ami"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.users", - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - }, - }, - "raw-user": { - config: userConfig, - imageTypes: []string{"raw"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.users", // user creation stage when we add users - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - }, - }, - "qcow2-user": { - config: userConfig, - imageTypes: []string{"qcow2"}, - containers: diskContainers, - expStages: map[string][]string{ - "build": {"org.osbuild.container-deploy"}, - "image": { - "org.osbuild.users", // user creation stage when we add users - "org.osbuild.bootc.install-to-filesystem", - }, - }, - notExpectedStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - }, - }, - "iso-user": { - config: userConfig, - imageTypes: []string{"iso"}, - containers: isoContainers, - depsolved: isoPackages, - expStages: map[string][]string{ - "build": {"org.osbuild.rpm"}, - "bootiso-tree": {"org.osbuild.skopeo"}, // adds the container to the ISO tree - }, - }, - "iso-nobuildpkg": { - config: userConfig, - imageTypes: []string{"iso"}, - containers: isoContainers, - depsolved: pkgsNoBuild, - err: "serialization not started", - }, - "iso-nocontainer": { - config: userConfig, - imageTypes: []string{"iso"}, - depsolved: isoPackages, - err: "missing ostree, container, or ospipeline parameters in ISO tree pipeline", - }, - "ami-nocontainer": { - config: userConfig, - imageTypes: []string{"ami"}, - // errors come from BuildrootFromContainer() - // TODO: think about better error and testing here (not the ideal layer or err msg) - err: "serialization not started", - }, - "raw-nocontainer": { - config: userConfig, - imageTypes: []string{"raw"}, - // errors come from BuildrootFromContainer() - // TODO: think about better error and testing here (not the ideal layer or err msg) - err: "serialization not started", - }, - "qcow2-nocontainer": { - config: userConfig, - imageTypes: []string{"qcow2"}, - // errors come from BuildrootFromContainer() - // TODO: think about better error and testing here (not the ideal layer or err msg) - err: "serialization not started", - }, - } - - // Use an empty config: only the imgref is required - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - config := main.ManifestConfig(*tc.config) - config.ImageTypes = tc.imageTypes - mf, err := main.Manifest(&config) - assert.NoError(err) // this isn't the error we're testing for - - if tc.err != nil { - assert.PanicsWithValue(tc.err, func() { - _, err := mf.Serialize(tc.depsolved, tc.containers, nil, nil) - assert.NoError(err) - }) - } else { - manifestJson, err := mf.Serialize(tc.depsolved, tc.containers, nil, nil) - assert.NoError(err) - assert.NoError(checkStages(manifestJson, tc.expStages, tc.notExpectedStages)) - } - }) - } - - { - // this one panics with a typed error and needs to be tested separately from the above (PanicsWithError()) - t.Run("iso-nopkgs", func(t *testing.T) { - assert := assert.New(t) - config := main.ManifestConfig(*userConfig) - config.ImageTypes, _ = imagetypes.New("iso") - manifest, err := main.Manifest(&config) - assert.NoError(err) // this isn't the error we're testing for - - expError := "package \"kernel\" not found in the PackageSpec list" - assert.PanicsWithError(expError, func() { - _, err := manifest.Serialize(nil, isoContainers, nil, nil) - assert.NoError(err) - }) - }) - } -} - -// simplified representation of a manifest -type testManifest struct { - Pipelines []pipeline `json:"pipelines"` -} -type pipeline struct { - Name string `json:"name"` - Stages []stage `json:"stages"` -} -type stage struct { - Type string `json:"type"` -} - -func checkStages(serialized manifest.OSBuildManifest, pipelineStages map[string][]string, missingStages map[string][]string) error { - mf := &testManifest{} - if err := json.Unmarshal(serialized, mf); err != nil { - return err - } - pipelineMap := map[string]pipeline{} - for _, pl := range mf.Pipelines { - pipelineMap[pl.Name] = pl - } - - for plname, stages := range pipelineStages { - pl, found := pipelineMap[plname] - if !found { - return fmt.Errorf("pipeline %q not found", plname) - } - - stageMap := map[string]bool{} - for _, stage := range pl.Stages { - stageMap[stage.Type] = true - } - for _, stage := range stages { - if _, found := stageMap[stage]; !found { - return fmt.Errorf("pipeline %q - stage %q - not found", plname, stage) - } - } - } - - for plname, stages := range missingStages { - pl, found := pipelineMap[plname] - if !found { - return fmt.Errorf("pipeline %q not found", plname) - } - - stageMap := map[string]bool{} - for _, stage := range pl.Stages { - stageMap[stage.Type] = true - } - for _, stage := range stages { - if _, found := stageMap[stage]; found { - return fmt.Errorf("pipeline %q - stage %q - found (but should not be)", plname, stage) - } - } - } - - return nil -} - func mockOsArgs(new []string) (restore func()) { saved := os.Args os.Args = append([]string{"argv0"}, new...) From 2c8f6a9545a970db6770116dfe84448eed0708bb Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 19 Aug 2025 18:12:05 +0200 Subject: [PATCH 7/8] bib: use image library for iso generation too XXX: we need to port the TLS key extraction from the container --- bib/cmd/bootc-image-builder/image.go | 121 --------------- bib/cmd/bootc-image-builder/main.go | 221 +++++---------------------- bib/go.mod | 4 +- bib/go.sum | 4 +- 4 files changed, 41 insertions(+), 309 deletions(-) diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index cf33d4edc..2ede45cbd 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -13,19 +13,10 @@ import ( "github.com/osbuild/blueprint/pkg/blueprint" "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/bib/osinfo" - "github.com/osbuild/images/pkg/container" - "github.com/osbuild/images/pkg/customizations/anaconda" - "github.com/osbuild/images/pkg/customizations/kickstart" - "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/image" "github.com/osbuild/images/pkg/manifest" - "github.com/osbuild/images/pkg/osbuild" - "github.com/osbuild/images/pkg/platform" - "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/images/pkg/runner" "github.com/sirupsen/logrus" - "github.com/osbuild/bootc-image-builder/bib/internal/distrodef" "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" ) @@ -78,118 +69,6 @@ func needsRHELLoraxTemplates(si osinfo.OSRelease) bool { return si.ID == "rhel" || slices.Contains(si.IDLike, "rhel") || si.VersionID == "eln" } -func manifestForISO(c *ManifestConfig, rng *rand.Rand) (*manifest.Manifest, error) { - if c.Imgref == "" { - return nil, fmt.Errorf("pipeline: no base image defined") - } - - imageDef, err := distrodef.LoadImageDef(c.DistroDefPaths, c.SourceInfo.OSRelease.ID, c.SourceInfo.OSRelease.VersionID, "anaconda-iso") - if err != nil { - return nil, err - } - - containerSource := container.SourceSpec{ - Source: c.Imgref, - Name: c.Imgref, - Local: true, - } - - platform := &platform.Data{ - Arch: c.Architecture, - ImageFormat: platform.FORMAT_ISO, - UEFIVendor: c.SourceInfo.UEFIVendor, - } - switch c.Architecture { - case arch.ARCH_X86_64: - platform.BIOSPlatform = "i386-pc" - case arch.ARCH_AARCH64: - // aarch64 always uses UEFI, so let's enforce the vendor - if c.SourceInfo.UEFIVendor == "" { - return nil, fmt.Errorf("UEFI vendor must be set for aarch64 ISO") - } - case arch.ARCH_S390X: - platform.ZiplSupport = true - case arch.ARCH_PPC64LE: - platform.BIOSPlatform = "powerpc-ieee1275" - } - // The ref is not needed and will be removed from the ctor later - // in time - img := image.NewAnacondaContainerInstaller(platform, "install.iso", containerSource, "") - img.ContainerRemoveSignatures = true - img.RootfsCompression = "zstd" - if c.Architecture == arch.ARCH_X86_64 { - img.InstallerCustomizations.ISOBoot = manifest.Grub2ISOBoot - } - - img.Product = c.SourceInfo.OSRelease.Name - img.OSVersion = c.SourceInfo.OSRelease.VersionID - - img.ExtraBasePackages = rpmmd.PackageSet{ - Include: imageDef.Packages, - } - - img.ISOLabel = labelForISO(&c.SourceInfo.OSRelease, &c.Architecture) - - var customizations *blueprint.Customizations - if c.Config != nil { - customizations = c.Config.Customizations - } - img.InstallerCustomizations.FIPS = customizations.GetFIPS() - img.Kickstart, err = kickstart.New(customizations) - if err != nil { - return nil, err - } - img.Kickstart.Path = osbuild.KickstartPathOSBuild - if kopts := customizations.GetKernel(); kopts != nil && kopts.Append != "" { - img.Kickstart.KernelOptionsAppend = append(img.Kickstart.KernelOptionsAppend, kopts.Append) - } - img.Kickstart.NetworkOnBoot = true - - instCust, err := customizations.GetInstaller() - if err != nil { - return nil, err - } - if instCust != nil && instCust.Modules != nil { - img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, instCust.Modules.Enable...) - img.InstallerCustomizations.DisabledAnacondaModules = append(img.InstallerCustomizations.DisabledAnacondaModules, instCust.Modules.Disable...) - } - img.InstallerCustomizations.EnabledAnacondaModules = append(img.InstallerCustomizations.EnabledAnacondaModules, - anaconda.ModuleUsers, - anaconda.ModuleServices, - anaconda.ModuleSecurity, - // XXX: get from the imagedefs - anaconda.ModuleNetwork, - anaconda.ModulePayloads, - anaconda.ModuleRuntime, - anaconda.ModuleStorage, - ) - - img.Kickstart.OSTree = &kickstart.OSTree{ - OSName: "default", - } - img.InstallerCustomizations.UseRHELLoraxTemplates = needsRHELLoraxTemplates(c.SourceInfo.OSRelease) - - // see https://github.com/osbuild/bootc-image-builder/issues/733 - img.InstallerCustomizations.ISORootfsType = manifest.SquashfsRootfs - - installRootfsType, err := disk.NewFSType(c.RootFSType) - if err != nil { - return nil, err - } - img.InstallRootfsType = installRootfsType - - mf := manifest.New() - - foundDistro, foundRunner, err := getDistroAndRunner(c.SourceInfo.OSRelease) - if err != nil { - return nil, fmt.Errorf("failed to infer distro and runner: %w", err) - } - mf.Distro = foundDistro - - _, err = img.InstantiateManifest(&mf, nil, foundRunner, rng) - return &mf, err -} - func getDistroAndRunner(osRelease osinfo.OSRelease) (manifest.Distro, runner.Runner, error) { switch osRelease.ID { case "fedora": diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index 2e2993005..c44643274 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -25,19 +25,14 @@ import ( "github.com/osbuild/images/pkg/bib/blueprintload" "github.com/osbuild/images/pkg/cloud" "github.com/osbuild/images/pkg/cloud/awscloud" - "github.com/osbuild/images/pkg/container" "github.com/osbuild/images/pkg/distro/bootc" - "github.com/osbuild/images/pkg/dnfjson" "github.com/osbuild/images/pkg/experimentalflags" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/manifestgen" - "github.com/osbuild/images/pkg/osbuild" "github.com/osbuild/images/pkg/reporegistry" "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" - podman_container "github.com/osbuild/images/pkg/bib/container" - "github.com/osbuild/images/pkg/bib/osinfo" "github.com/osbuild/image-builder-cli/pkg/progress" "github.com/osbuild/image-builder-cli/pkg/setup" @@ -93,63 +88,6 @@ func inContainerOrUnknown() bool { return err == nil } -func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (manifest.OSBuildManifest, map[string][]rpmmd.RepoConfig, error) { - rng := createRand() - mani, err := manifestForISO(c, rng) - if err != nil { - return nil, nil, fmt.Errorf("cannot get manifest: %w", err) - } - - // depsolve packages - depsolvedSets := make(map[string]dnfjson.DepsolveResult) - depsolvedRepos := make(map[string][]rpmmd.RepoConfig) - for name, pkgSet := range mani.GetPackageSetChains() { - res, err := solver.Depsolve(pkgSet, 0) - if err != nil { - return nil, nil, fmt.Errorf("cannot depsolve: %w", err) - } - depsolvedSets[name] = *res - depsolvedRepos[name] = res.Repos - } - - // Resolve container - the normal case is that host and target - // architecture are the same. However it is possible to build - // cross-arch images by using qemu-user. This will run everything - // (including the build-root) with the target arch then, it - // is fast enough (given that it's mostly I/O and all I/O is - // run naively via syscall translation) - - // XXX: should NewResolver() take "arch.Arch"? - resolver := container.NewResolver(c.Architecture.String()) - - containerSpecs := make(map[string][]container.Spec) - for plName, sourceSpecs := range mani.GetContainerSourceSpecs() { - for _, c := range sourceSpecs { - resolver.Add(c) - } - specs, err := resolver.Finish() - if err != nil { - return nil, nil, fmt.Errorf("cannot resolve containers: %w", err) - } - for _, spec := range specs { - if spec.Arch != c.Architecture { - return nil, nil, fmt.Errorf("image found is for unexpected architecture %q (expected %q), if that is intentional, please make sure --target-arch matches", spec.Arch, c.Architecture) - } - } - containerSpecs[plName] = specs - } - - var opts manifest.SerializeOptions - if c.UseLibrepo { - opts.RpmDownloader = osbuild.RpmDownloaderLibrepo - } - mf, err := mani.Serialize(depsolvedSets, containerSpecs, nil, &opts) - if err != nil { - return nil, nil, fmt.Errorf("[ERROR] manifest serialization failed: %s", err.Error()) - } - return mf, depsolvedRepos, nil -} - func saveManifest(ms manifest.OSBuildManifest, fpath string) (err error) { b, err := json.MarshalIndent(ms, "", " ") if err != nil { @@ -183,11 +121,11 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress imgref := args[0] userConfigFile, _ := cmd.Flags().GetString("config") imgTypes, _ := cmd.Flags().GetStringArray("type") - rpmCacheRoot, _ := cmd.Flags().GetString("rpmmd") + //rpmCacheRoot, _ := cmd.Flags().GetString("rpmmd") targetArch, _ := cmd.Flags().GetString("target-arch") rootFs, _ := cmd.Flags().GetString("rootfs") buildImgref, _ := cmd.Flags().GetString("build-container") - useLibrepo, _ := cmd.Flags().GetBool("use-librepo") + //useLibrepo, _ := cmd.Flags().GetBool("use-librepo") // If --local was given, warn in the case of --local or --local=true (true is the default), error in the case of --local=false if cmd.Flags().Changed("local") { @@ -224,10 +162,6 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress return nil, nil, fmt.Errorf("could not access container storage, did you forget -v /var/lib/containers/storage:/var/lib/containers/storage? (%w)", err) } - imageTypes, err := imagetypes.New(imgTypes...) - if err != nil { - return nil, nil, fmt.Errorf("cannot detect build types %v: %w", imgTypes, err) - } config, err := blueprintload.LoadWithFallback(userConfigFile) if err != nil { return nil, nil, fmt.Errorf("cannot read config: %w", err) @@ -242,143 +176,60 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress // For now shortcut here and build ding "images" for anything // that is not the iso - if !imageTypes.BuildsISO() { - distro, err := bootc.NewBootcDistro(imgref) - if err != nil { - return nil, nil, err - } - if err := distro.SetBuildContainer(buildImgref); err != nil { - return nil, nil, err - } - if err := distro.SetDefaultFs(rootFs); err != nil { - return nil, nil, err - } - // XXX: consider target-arch - archi, err := distro.GetArch(cntArch.String()) - if err != nil { - return nil, nil, err - } - // XXX: how to generate for all image types - imgType, err := archi.GetImageType(imgTypes[0]) - if err != nil { - return nil, nil, err - } - var buf bytes.Buffer - repos, err := reporegistry.New(nil, []fs.FS{repos.FS}) - if err != nil { - return nil, nil, err - } - mg, err := manifestgen.New(repos, &manifestgen.Options{ - Output: &buf, - // XXX: hack to skip repo loading for the bootc image. - // We need to add a SkipRepositories or similar to - // manifestgen instead to make this clean - OverrideRepos: []rpmmd.RepoConfig{ - { - BaseURLs: []string{"https://example.com/not-used"}, - }, - }, - }) - if err != nil { - return nil, nil, err - } - if err := mg.Generate(config, distro, imgType, archi, nil); err != nil { - return nil, nil, err - } - return buf.Bytes(), nil, nil - } - - container, err := podman_container.New(imgref) + distro, err := bootc.NewBootcDistro(imgref) if err != nil { return nil, nil, err } - defer func() { - if err := container.Stop(); err != nil { - logrus.Warnf("error stopping container: %v", err) - } - }() - - var rootfsType string - if rootFs != "" { - rootfsType = rootFs - } else { - rootfsType, err = container.DefaultRootfsType() - if err != nil { - return nil, nil, fmt.Errorf("cannot get rootfs type for container: %w", err) - } - if rootfsType == "" { - return nil, nil, fmt.Errorf(`no default root filesystem type specified in container, please use "--rootfs" to set manually`) - } - } - - // Gather some data from the containers distro - sourceinfo, err := osinfo.Load(container.Root()) - if err != nil { + if err := distro.SetBuildContainer(buildImgref); err != nil { return nil, nil, err } - - buildContainer := container - buildSourceinfo := sourceinfo - startedBuildContainer := false - defer func() { - if startedBuildContainer { - if err := buildContainer.Stop(); err != nil { - logrus.Warnf("error stopping container: %v", err) - } - } - }() - - if buildImgref != "" { - buildContainer, err = podman_container.New(buildImgref) - if err != nil { - return nil, nil, err - } - startedBuildContainer = true - - // Gather some data from the containers distro - buildSourceinfo, err = osinfo.Load(buildContainer.Root()) - if err != nil { - return nil, nil, err - } - } else { - buildImgref = imgref - } - - // This is needed just for RHEL and RHSM in most cases, but let's run it every time in case - // the image has some non-standard dnf plugins. - if err := buildContainer.InitDNF(); err != nil { + if err := distro.SetDefaultFs(rootFs); err != nil { return nil, nil, err } - solver, err := buildContainer.NewContainerSolver(rpmCacheRoot, cntArch, sourceinfo) + // XXX: consider target-arch + archi, err := distro.GetArch(cntArch.String()) if err != nil { return nil, nil, err } - - manifestConfig := &ManifestConfig{ - Architecture: cntArch, - Config: config, - ImageTypes: imageTypes, - Imgref: imgref, - BuildImgref: buildImgref, - DistroDefPaths: distroDefPaths, - SourceInfo: sourceinfo, - BuildSourceInfo: buildSourceinfo, - RootFSType: rootfsType, - UseLibrepo: useLibrepo, + // XXX: how to generate for all image types + imgType, err := archi.GetImageType(imgTypes[0]) + if err != nil { + return nil, nil, err } - manifest, repos, err := makeManifest(manifestConfig, solver, rpmCacheRoot) + var buf bytes.Buffer + repos, err := reporegistry.New(nil, []fs.FS{repos.FS}) if err != nil { return nil, nil, err } - - mTLS, err := extractTLSKeys(repos) + mg, err := manifestgen.New(repos, &manifestgen.Options{ + Output: &buf, + // XXX: hack to skip repo loading for the bootc image. + // We need to add a SkipRepositories or similar to + // manifestgen instead to make this clean + OverrideRepos: []rpmmd.RepoConfig{ + { + BaseURLs: []string{"https://example.com/not-used"}, + }, + }, + }) if err != nil { return nil, nil, err } + if err := mg.Generate(config, distro, imgType, archi, nil); err != nil { + return nil, nil, err + } + return buf.Bytes(), nil, nil + // XXX: portme + /* + mTLS, err := extractTLSKeys(SimpleFileReader{}, repos) + if err != nil { + return nil, nil, err + } - return manifest, mTLS, nil + return manifest, mTLS, nil + */ } func cmdManifest(cmd *cobra.Command, args []string) error { diff --git a/bib/go.mod b/bib/go.mod index bdc37a5a3..b7d7f5eb4 100644 --- a/bib/go.mod +++ b/bib/go.mod @@ -5,7 +5,6 @@ go 1.23.9 require ( github.com/cheggaaa/pb/v3 v3.1.7 github.com/hashicorp/go-version v1.7.0 - github.com/osbuild/blueprint v1.13.0 github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3 github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f github.com/sirupsen/logrus v1.9.3 @@ -99,6 +98,7 @@ require ( github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/runtime-spec v1.2.1 // indirect github.com/opencontainers/selinux v1.12.0 // indirect + github.com/osbuild/blueprint v1.13.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/proglottis/gpgme v0.1.4 // indirect @@ -133,3 +133,5 @@ require ( google.golang.org/protobuf v1.36.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) + +replace github.com/osbuild/images => github.com/mvo5/images v0.0.0-20250828130520-bbe53a9fa6ad diff --git a/bib/go.sum b/bib/go.sum index 818795241..f83a8974d 100644 --- a/bib/go.sum +++ b/bib/go.sum @@ -233,6 +233,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mvo5/images v0.0.0-20250828130520-bbe53a9fa6ad h1:2d5YjL5nshIBMzzMOWogXFJRYdpyykp0Kw6Y2oOTtEM= +github.com/mvo5/images v0.0.0-20250828130520-bbe53a9fa6ad/go.mod h1:qbGjthiOmiZr1xCJEYMHv5oPNXXcxkJyvj7dky4/ibw= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -245,8 +247,6 @@ github.com/osbuild/blueprint v1.13.0 h1:blo22+S2ZX5bBmjGcRveoTUrV4Ms7kLfKyb32Wyu github.com/osbuild/blueprint v1.13.0/go.mod h1:HPlJzkEl7q5g8hzaGksUk7ifFAy9QFw9LmzhuFOAVm4= github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3 h1:M3yYunKH4quwJLQrnFo7dEwCTKorafNC+AUqAo7m5Yo= github.com/osbuild/image-builder-cli v0.0.0-20250331194259-63bb56e12db3/go.mod h1:0sEmiQiMo1ChSuOoeONN0RmsoZbQEvj2mlO2448gC5w= -github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f h1:y3TJJ8Gy8LZwk9NYGESD9U9IxkkCS1rVHz1jwFn9UyE= -github.com/osbuild/images v0.180.1-0.20250827153323-b3eeac43188f/go.mod h1:qbGjthiOmiZr1xCJEYMHv5oPNXXcxkJyvj7dky4/ibw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= From b9b9c02f25d343f3ff03698b0622ba22ec81fedb Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 20 Aug 2025 14:55:12 +0200 Subject: [PATCH 8/8] wip --- bib/cmd/bootc-image-builder/image.go | 3 ++- bib/cmd/bootc-image-builder/main.go | 15 ++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index 2ede45cbd..2e6561335 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -10,12 +10,13 @@ import ( "strconv" "strings" + "github.com/sirupsen/logrus" + "github.com/osbuild/blueprint/pkg/blueprint" "github.com/osbuild/images/pkg/arch" "github.com/osbuild/images/pkg/bib/osinfo" "github.com/osbuild/images/pkg/manifest" "github.com/osbuild/images/pkg/runner" - "github.com/sirupsen/logrus" "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" ) diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index c44643274..8a8f59de8 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -220,16 +220,21 @@ func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.Progress if err := mg.Generate(config, distro, imgType, archi, nil); err != nil { return nil, nil, err } + return buf.Bytes(), nil, nil // XXX: portme /* - mTLS, err := extractTLSKeys(SimpleFileReader{}, repos) - if err != nil { - return nil, nil, err - } + osbuildExtraEnv := mg.OsbuildExtraEnv - return manifest, mTLS, nil + mTLS, err := extractTLSKeys(repos) + if err != nil { + return nil, nil, err + } + + return manifest, mTLS, nil */ + + return buf.Bytes(), nil, nil } func cmdManifest(cmd *cobra.Command, args []string) error {