Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/os-image-composer/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ post:

func displayImageBuildTiming(imageType string, template *config.ImageTemplate) {
startToDownloadImagePkgsDuration := template.GetDurationStartToDownloadImagePkgs()
chrootPkgDownloadDuration := template.GetChrootPkgDownloadDuration()
downloadImagePkgsToPureBuildDuration := template.GetDurationDownloadImagePkgsToPureBuild()
pureImageBuildDuration := template.GetPureImageBuildDuration()
downloadImagePkgsDuration := template.GetDownloadImagePkgsDuration()
Expand All @@ -157,6 +158,7 @@ func displayImageBuildTiming(imageType string, template *config.ImageTemplate) {
imageType,
startToDownloadImagePkgsDuration,
downloadImagePkgsDuration,
chrootPkgDownloadDuration,
downloadImagePkgsToPureBuildDuration,
pureImageBuildDuration,
convertImageDuration,
Expand Down
54 changes: 37 additions & 17 deletions image-templates/ubuntu24-x86_64-minimal-raw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,43 @@ target:
arch: x86_64
imageType: raw

# Sample list of additional package repositories; replace codename, url, and pkey values as needed
packageRepositories:
- codename: "company-internal"
url: "<URL>"
pkey: "<PUBLIC_KEY_URL>" # Uncomment and replace in real config
component: "main"
disk:
name: Minimal_Raw # 1:1 mapping to the systemConfigs name
artifacts:
-
type: raw # image file format, valid value [raw, vhd, vhdx, qcow2, vmdk, vdi]
compression: gz # image compression format (optional)
- type: vhdx
size: 4GiB # 4G, 4GB, 4096 MiB also valid. (Required for raw)
partitionTableType: gpt # Partition table type, valid value: [gpt, mbr]
partitions: # Required for raw, optional for ISO, not needed for rootfs.
- id: boot
type: esp
flags:
- esp
- boot
start: 1MiB
end: 513MiB
fsType: fat32
mountPoint: /boot/efi
mountOptions: umask=0077

- codename: "dev-tools"
url: "<URL>"
pkey: "<PUBLIC_KEY_URL>" # Uncomment and replace in real config

- codename: "intel-openvino"
url: "<URL>"
pkey: "<PUBLIC_KEY_URL>" # Uncomment and replace in real config
component: "restricted"
- id: rootfs
type: linux-root-amd64
start: 513MiB
end: "0"
fsType: ext4
mountPoint: /
mountOptions: defaults

systemConfig:
name: minimal
description: Minimal ubuntu image

bootloader:
bootType: efi
provider: grub

immutability:
enabled: false # default is true
# To enable Secure Boot, provide the actual file paths for your environment below and uncomment the relevant lines.
Expand All @@ -53,10 +70,13 @@ systemConfig:

packages:
- ubuntu-minimal
- systemd-boot
- dracut-core
- grub-efi-amd64-signed
- initramfs-tools
- grub2-common
- grub-pc-bin
- grub-efi-amd64
- grub-efi-amd64-bin
- systemd
- cryptsetup-bin
- openssh-server
- systemd-resolved
- systemd-timesyncd
Expand Down
8 changes: 8 additions & 0 deletions internal/chroot/chrootbuild/chrootbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,15 @@ type ChrootBuilder struct {
TargetOsConfig map[string]interface{}
ChrootBuildDir string
ChrootPkgCacheDir string
BuildTemplate *config.ImageTemplate
RpmInstaller rpm.RpmInstallerInterface
DebInstaller deb.DebInstallerInterface
}

func (chrootBuilder *ChrootBuilder) SetBuildTemplate(template *config.ImageTemplate) {
chrootBuilder.BuildTemplate = template
}

// ChrootenvConfig represents the structure of a chrootenv configuration file
type ChrootenvConfig struct {
Essential []string `yaml:"essential,omitempty" json:"essential,omitempty"`
Expand Down Expand Up @@ -284,6 +289,9 @@ func (chrootBuilder *ChrootBuilder) BuildChrootEnv(targetOs string, targetDist s
if err != nil {
return fmt.Errorf("failed to download chroot environment packages: %w", err)
}
if chrootBuilder.BuildTemplate != nil {
chrootBuilder.BuildTemplate.FinishChrootPkgDownloadTimer()
}
log.Infof("Downloaded %d packages for chroot environment", len(allPkgsList))

chrootPkgCacheDir := chrootBuilder.GetChrootPkgCacheDir()
Expand Down
11 changes: 11 additions & 0 deletions internal/chroot/chrootenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type ChrootEnv struct {
ChrootEnvRoot string
ChrootImageBuildDir string
ChrootBuilder chrootbuild.ChrootBuilderInterface
buildTemplate *config.ImageTemplate
TargetOs string // Store targetOs for package manager selection
}

Expand Down Expand Up @@ -89,6 +90,13 @@ func (chrootEnv *ChrootEnv) GetChrootEnvRoot() string {
return chrootEnv.ChrootEnvRoot
}

func (chrootEnv *ChrootEnv) SetBuildTemplate(template *config.ImageTemplate) {
chrootEnv.buildTemplate = template
if templateAwareBuilder, ok := chrootEnv.ChrootBuilder.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareBuilder.SetBuildTemplate(template)
}
}

func (chrootEnv *ChrootEnv) GetChrootImageBuildDir() string {
return chrootEnv.ChrootImageBuildDir
}
Expand Down Expand Up @@ -392,6 +400,9 @@ func (chrootEnv *ChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch strin
chrootBuildDir := chrootEnv.ChrootBuilder.GetChrootBuildDir()
chrootEnvTarPath := filepath.Join(chrootBuildDir, "chrootenv.tar.gz")
if _, err := os.Stat(chrootEnvTarPath); os.IsNotExist(err) {
if templateAwareBuilder, ok := chrootEnv.ChrootBuilder.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareBuilder.SetBuildTemplate(chrootEnv.buildTemplate)
}
// Build chroot environment tarball
if err = chrootEnv.ChrootBuilder.BuildChrootEnv(targetOs, targetDist, targetArch); err != nil {
return fmt.Errorf("failed to build chroot environment: %w", err)
Expand Down
29 changes: 29 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ type ImageTemplate struct {
downloadPkgsDuration time.Duration
convertImageStart time.Time
convertImageDuration time.Duration
chrootPkgDlStart time.Time
chrootPkgDlDuration time.Duration
buildTimelineStart time.Time
buildFinishedAt time.Time
}
Expand Down Expand Up @@ -362,6 +364,26 @@ func (t *ImageTemplate) FinishDownloadImagePkgsTimer() {
}

t.downloadPkgsDuration = time.Since(t.downloadPkgsStart)
t.chrootPkgDlStart = time.Now()
t.chrootPkgDlDuration = 0
}

// FinishChrootPkgDownloadTimer stores elapsed chroot package download wait time if tracking was started.
func (t *ImageTemplate) FinishChrootPkgDownloadTimer() {
if t == nil || t.chrootPkgDlStart.IsZero() {
return
}

t.chrootPkgDlDuration = time.Since(t.chrootPkgDlStart)
}

// GetChrootPkgDownloadDuration returns tracked chroot package download wait duration.
func (t *ImageTemplate) GetChrootPkgDownloadDuration() time.Duration {
if t == nil {
return 0
}

return t.chrootPkgDlDuration
}

// GetDownloadImagePkgsDuration returns tracked downloadImagePkgs duration.
Expand Down Expand Up @@ -399,6 +421,13 @@ func (t *ImageTemplate) GetDurationDownloadImagePkgsToPureBuild() time.Duration
return 0
}

if t.chrootPkgDlDuration > 0 {
d -= t.chrootPkgDlDuration
if d < 0 {
return 0
}
}

return d
}

Expand Down
6 changes: 4 additions & 2 deletions internal/image/imageos/imageos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ func (m *MockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string
func (m *MockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
return nil
}
func (m *MockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *MockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *MockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *MockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
return nil
}
func (m *MockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *MockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
return nil
Expand Down
3 changes: 2 additions & 1 deletion internal/image/isomaker/isomaker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

var log = logger.Logger()

// Mock implementation: always succeed

// Mock implementations for testing
type mockChrootEnv struct {
pkgType string
Expand Down Expand Up @@ -117,7 +119,6 @@ func (m *mockChrootEnv) RefreshLocalCacheRepo() error {

// Add missing method to satisfy chroot.ChrootEnvInterface
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
// Mock implementation: always succeed
return nil
}

Expand Down
3 changes: 3 additions & 0 deletions internal/provider/azl/azl.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func (p *AzureLinux) PreProcess(template *config.ImageTemplate) error {
return fmt.Errorf("failed to download image packages: %w", err)
}
template.FinishDownloadImagePkgsTimer()
if templateAwareChrootEnv, ok := p.chrootEnv.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareChrootEnv.SetBuildTemplate(template)
}

if err := p.chrootEnv.InitChrootEnv(template.Target.OS,
template.Target.Dist, template.Target.Arch); err != nil {
Expand Down
6 changes: 4 additions & 2 deletions internal/provider/azl/azl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ func (m *mockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string
func (m *mockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
return nil
}
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
return nil
}
func (m *mockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
return nil
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/elxr/elxr.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func (p *eLxr) PreProcess(template *config.ImageTemplate) error {
return fmt.Errorf("failed to download image packages: %w", err)
}
template.FinishDownloadImagePkgsTimer()
if templateAwareChrootEnv, ok := p.chrootEnv.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareChrootEnv.SetBuildTemplate(template)
}

if err := p.chrootEnv.InitChrootEnv(template.Target.OS,
template.Target.Dist, template.Target.Arch); err != nil {
Expand Down
6 changes: 4 additions & 2 deletions internal/provider/elxr/elxr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,10 @@ func (m *mockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string
func (m *mockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
return nil
}
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
return nil
}
func (m *mockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
return nil
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/emt/emt.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ func (p *Emt) PreProcess(template *config.ImageTemplate) error {
return fmt.Errorf("failed to download image packages: %w", err)
}
template.FinishDownloadImagePkgsTimer()
if templateAwareChrootEnv, ok := p.chrootEnv.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareChrootEnv.SetBuildTemplate(template)
}

if err := p.chrootEnv.InitChrootEnv(template.Target.OS,
template.Target.Dist, template.Target.Arch); err != nil {
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/rcd/rcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func (p *RCD) PreProcess(template *config.ImageTemplate) error {
return fmt.Errorf("failed to download image packages: %w", err)
}
template.FinishDownloadImagePkgsTimer()
if templateAwareChrootEnv, ok := p.chrootEnv.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareChrootEnv.SetBuildTemplate(template)
}

if err := p.chrootEnv.InitChrootEnv(template.Target.OS,
template.Target.Dist, template.Target.Arch); err != nil {
Expand Down
6 changes: 4 additions & 2 deletions internal/provider/rcd/rcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ func (m *mockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string
func (m *mockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
return nil
}
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
return nil
}
func (m *mockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
return nil
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/ubuntu/ubuntu.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ func (p *ubuntu) PreProcess(template *config.ImageTemplate) error {
return fmt.Errorf("failed to download image packages: %w", err)
}
template.FinishDownloadImagePkgsTimer()
if templateAwareChrootEnv, ok := p.chrootEnv.(interface{ SetBuildTemplate(*config.ImageTemplate) }); ok {
templateAwareChrootEnv.SetBuildTemplate(template)
}

if err := p.chrootEnv.InitChrootEnv(template.Target.OS,
template.Target.Dist, template.Target.Arch); err != nil {
Expand Down
6 changes: 4 additions & 2 deletions internal/provider/ubuntu/ubuntu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,10 @@ func (m *mockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string
func (m *mockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
return nil
}
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) RefreshLocalCacheRepo() error { return nil }
func (m *mockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error {
return nil
}
func (m *mockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
func (m *mockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
return nil
Expand Down
8 changes: 4 additions & 4 deletions internal/utils/display/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func PrintImageBuildingTiming(
imageType string,
startToDownloadImagePkgsTime,
downloadImagePkgsTime,
chrootPkgDownloadTime,
downloadImagePkgsToPureBuildTime,
pureImageBuildTime,
convertImageTime time.Duration,
Expand All @@ -103,6 +104,7 @@ func PrintImageBuildingTiming(
}{
{stage: "Initialization and Configuration", duration: startToDownloadImagePkgsTime},
{stage: "Package Download", duration: downloadImagePkgsTime},
{stage: "Chroot Package Download", duration: chrootPkgDownloadTime},
{stage: "Chroot Env Initialization", duration: downloadImagePkgsToPureBuildTime},
{stage: "Image Build", duration: pureImageBuildTime},
{stage: "Image Conversion", duration: convertImageTime},
Expand All @@ -115,10 +117,8 @@ func PrintImageBuildingTiming(
}
var totalDuration time.Duration
for _, row := range timingRows {
if row.duration > 0 {
visibleTimingRows = append(visibleTimingRows, row)
totalDuration += row.duration
}
visibleTimingRows = append(visibleTimingRows, row)
totalDuration += row.duration
}

if len(visibleTimingRows) > 0 {
Expand Down
8 changes: 5 additions & 3 deletions internal/utils/display/display_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestPrintImageDirectorySummary_WithArtifacts(t *testing.T) {

func TestPrintImageBuildingTiming_NoVisibleRows(t *testing.T) {
logs := captureLogs(t, func() {
display.PrintImageBuildingTiming("raw", 0, 0, 0, 0, 0, 0)
display.PrintImageBuildingTiming("raw", 0, 0, 0, 0, 0, 0, 0)
})

if strings.Contains(logs, "Build Timings:") {
Expand All @@ -103,10 +103,11 @@ func TestPrintImageBuildingTiming_TableIncludesVisibleRowsAndTotal(t *testing.T)
"iso",
1500*time.Millisecond,
0,
500*time.Millisecond,
250*time.Millisecond,
2*time.Second,
0,
1250*time.Millisecond,
750*time.Millisecond,
)
})

Expand All @@ -119,6 +120,7 @@ func TestPrintImageBuildingTiming_TableIncludesVisibleRowsAndTotal(t *testing.T)

visibleStages := []string{
"Initialization and Configuration",
"Chroot Package Download",
"Chroot Env Initialization",
"Image Build",
"Finalization and Clean Up",
Expand All @@ -129,7 +131,7 @@ func TestPrintImageBuildingTiming_TableIncludesVisibleRowsAndTotal(t *testing.T)
}
}

hiddenStages := []string{"Package Download", "Image Conversion"}
hiddenStages := []string{"| Package Download ", "| Image Conversion "}
for _, stage := range hiddenStages {
if strings.Contains(logs, stage) {
t.Fatalf("expected zero-duration stage %q to be hidden", stage)
Expand Down
Loading