Skip to content

Commit a2f2d81

Browse files
authored
Merge pull request #282 from open-edge-platform/dev_feiyu
Address the read-only repo cache not able to generate repo metadata issue in the iso initramfs system
2 parents 72c7c0b + bdfa9ba commit a2f2d81

File tree

17 files changed

+116
-48
lines changed

17 files changed

+116
-48
lines changed

internal/chroot/chrootbuild/chrootbuild.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type ChrootBuilderInterface interface {
3939
GetChrootEnvConfig() (map[interface{}]interface{}, error)
4040
GetChrootEnvPackageList() ([]string, error)
4141
GetChrootEnvEssentialPackageList() ([]string, error)
42-
UpdateLocalDebRepo(repoPath, targetArch string) error
42+
UpdateLocalDebRepo(repoPath, targetArch string, sudo bool) error
4343
BuildChrootEnv(targetOs string, targetDist string, targetArch string) error
4444
}
4545

@@ -266,8 +266,8 @@ func (chrootBuilder *ChrootBuilder) downloadChrootEnvPackages() ([]string, []str
266266
}
267267
}
268268

269-
func (chrootBuilder *ChrootBuilder) UpdateLocalDebRepo(repoPath, targetArch string) error {
270-
return chrootBuilder.DebInstaller.UpdateLocalDebRepo(repoPath, targetArch)
269+
func (chrootBuilder *ChrootBuilder) UpdateLocalDebRepo(repoPath, targetArch string, sudo bool) error {
270+
return chrootBuilder.DebInstaller.UpdateLocalDebRepo(repoPath, targetArch, sudo)
271271
}
272272

273273
func (chrootBuilder *ChrootBuilder) BuildChrootEnv(targetOs string, targetDist string, targetArch string) error {
@@ -293,7 +293,7 @@ func (chrootBuilder *ChrootBuilder) BuildChrootEnv(targetOs string, targetDist s
293293
return fmt.Errorf("failed to install packages in chroot environment: %w", err)
294294
}
295295
} else if pkgType == "deb" {
296-
if err = chrootBuilder.DebInstaller.UpdateLocalDebRepo(chrootPkgCacheDir, targetArch); err != nil {
296+
if err = chrootBuilder.DebInstaller.UpdateLocalDebRepo(chrootPkgCacheDir, targetArch, false); err != nil {
297297
return fmt.Errorf("failed to create debian local repository: %w", err)
298298
}
299299

internal/chroot/chrootbuild/chrootbuild_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type mockDebInstaller struct {
3131
shouldFailInstall bool
3232
}
3333

34-
func (m *mockDebInstaller) UpdateLocalDebRepo(cacheDir, arch string) error {
34+
func (m *mockDebInstaller) UpdateLocalDebRepo(cacheDir, arch string, sudo bool) error {
3535
if m.shouldFailRepo {
3636
return fmt.Errorf("mock deb repo failure")
3737
}
@@ -77,7 +77,7 @@ func (t *testableChrootBuilder) BuildChrootEnv(targetOs, targetDist, targetArch
7777
}
7878
} else if pkgType == "deb" {
7979
if err = t.ChrootBuilder.DebInstaller.UpdateLocalDebRepo(t.ChrootBuilder.ChrootPkgCacheDir,
80-
targetArch); err != nil {
80+
targetArch, false); err != nil {
8181
return fmt.Errorf("failed to create debian local repository: %w", err)
8282
}
8383

internal/chroot/chrootenv.go

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ type ChrootEnvInterface interface {
4444
UmountChrootPath(chrootPath string) error
4545
CopyFileFromHostToChroot(hostFilePath, chrootPath string) error
4646
CopyFileFromChrootToHost(hostFilePath, chrootPath string) error
47-
RefreshLocalCacheRepo(targetArch string) error
47+
UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error
48+
RefreshLocalCacheRepo() error
4849
InitChrootEnv(targetOs, targetDist, targetArch string) error
4950
CleanupChrootEnv(targetOs, targetDist, targetArch string) error
5051
TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error
@@ -248,29 +249,40 @@ func (chrootEnv *ChrootEnv) updateChrootLocalRPMRepo(chrootRepoDir string) error
248249
return nil
249250
}
250251

251-
func (chrootEnv *ChrootEnv) updateChrootLocalDebRepo(chrootPkgCacheDir, targetArch string) error {
252-
return chrootEnv.ChrootBuilder.UpdateLocalDebRepo(chrootPkgCacheDir, targetArch)
252+
func (chrootEnv *ChrootEnv) updateChrootLocalDebRepo(chrootPkgCacheDir, targetArch string, sudo bool) error {
253+
return chrootEnv.ChrootBuilder.UpdateLocalDebRepo(chrootPkgCacheDir, targetArch, sudo)
253254
}
254255

255-
func (chrootEnv *ChrootEnv) RefreshLocalCacheRepo(targetArch string) error {
256-
// From local.repo
256+
func (chrootEnv *ChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
257257
pkgType := chrootEnv.GetTargetOsPkgType()
258258
if pkgType == "rpm" {
259-
releaseVersion := chrootEnv.GetTargetOsReleaseVersion()
260-
if err := chrootEnv.updateChrootLocalRPMRepo(ChrootRepoDir); err != nil {
261-
return fmt.Errorf("failed to update rpm local cache repository %s: %w", ChrootRepoDir, err)
259+
if err := chrootEnv.updateChrootLocalRPMRepo(chrootRepoDir); err != nil {
260+
return fmt.Errorf("failed to update rpm local cache repository %s: %w", chrootRepoDir, err)
261+
}
262+
} else if pkgType == "deb" {
263+
chrootPkgCacheDir, err := chrootEnv.GetChrootEnvHostPath(chrootRepoDir)
264+
if err != nil {
265+
return fmt.Errorf("failed to get chroot host path for %s: %w", chrootRepoDir, err)
266+
}
267+
if err := chrootEnv.updateChrootLocalDebRepo(chrootPkgCacheDir, targetArch, sudo); err != nil {
268+
return fmt.Errorf("failed to update debian local cache repository: %v", err)
262269
}
270+
} else {
271+
return fmt.Errorf("unsupported package type: %s", pkgType)
272+
}
273+
return nil
274+
}
263275

276+
func (chrootEnv *ChrootEnv) RefreshLocalCacheRepo() error {
277+
// From local.repo
278+
pkgType := chrootEnv.GetTargetOsPkgType()
279+
if pkgType == "rpm" {
280+
releaseVersion := chrootEnv.GetTargetOsReleaseVersion()
264281
cmd := fmt.Sprintf("tdnf makecache --releasever %s", releaseVersion)
265282
if _, err := shell.ExecCmdWithStream(cmd, true, chrootEnv.ChrootEnvRoot, nil); err != nil {
266283
return fmt.Errorf("failed to refresh cache for chroot repository: %w", err)
267284
}
268285
} else if pkgType == "deb" {
269-
chrootPkgCacheDir := chrootEnv.GetChrootPkgCacheDir()
270-
if err := chrootEnv.updateChrootLocalDebRepo(chrootPkgCacheDir, targetArch); err != nil {
271-
return fmt.Errorf("failed to update debian local cache repository: %v", err)
272-
}
273-
274286
cmd := "apt clean"
275287
if _, err := shell.ExecCmdWithStream(cmd, true, chrootEnv.ChrootEnvRoot, nil); err != nil {
276288
return fmt.Errorf("failed to clean cache for chroot repository: %w", err)
@@ -293,7 +305,15 @@ func (chrootEnv *ChrootEnv) initChrootLocalRepo(targetArch string) error {
293305
chrootPkgCacheDir, ChrootRepoDir, err)
294306
}
295307

296-
if err := chrootEnv.RefreshLocalCacheRepo(targetArch); err != nil {
308+
if chrootEnv.ChrootEnvRoot != shell.HostPath {
309+
// Within iso initramfs system, local repo metadata should have been generated
310+
// And the repo cache is read-only, not able to update by live-installer
311+
if err := chrootEnv.UpdateChrootLocalRepoMetadata(ChrootRepoDir, targetArch, false); err != nil {
312+
return fmt.Errorf("failed to update chroot local cache repository metadata: %w", err)
313+
}
314+
}
315+
316+
if err := chrootEnv.RefreshLocalCacheRepo(); err != nil {
297317
return fmt.Errorf("failed to refresh local cache repository: %w", err)
298318
}
299319
return nil

internal/chroot/chrootenv_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type mockChrootBuilder struct {
1717
}
1818

1919
// Add the missing method to satisfy ChrootBuilderInterface
20-
func (m *mockChrootBuilder) UpdateLocalDebRepo(repoPath, targetArch string) error {
20+
func (m *mockChrootBuilder) UpdateLocalDebRepo(repoPath, targetArch string, sudo bool) error {
2121
// For testing, just return the error field
2222
return m.err
2323
}

internal/chroot/deb/installer.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
var log = logger.Logger()
1515

1616
type DebInstallerInterface interface {
17-
UpdateLocalDebRepo(cacheDir, arch string) error
17+
UpdateLocalDebRepo(cacheDir, arch string, sudo bool) error
1818
InstallDebPkg(configDir, chrootPath, cacheDir string, packages []string) error
1919
}
2020

@@ -45,7 +45,7 @@ func (debInstaller *DebInstaller) cleanupOnError(chrootEnvPath, repoPath string,
4545
}
4646
}
4747

48-
func (debInstaller *DebInstaller) UpdateLocalDebRepo(repoPath, targetArch string) error {
48+
func (debInstaller *DebInstaller) UpdateLocalDebRepo(repoPath, targetArch string, sudo bool) error {
4949
if repoPath == "" {
5050
return fmt.Errorf("repository path cannot be empty")
5151
}
@@ -62,19 +62,25 @@ func (debInstaller *DebInstaller) UpdateLocalDebRepo(repoPath, targetArch string
6262
metaDataPath := filepath.Join(repoPath,
6363
fmt.Sprintf("dists/stable/main/binary-%s", targetArch), "Packages.gz")
6464
if _, err := os.Stat(metaDataPath); err == nil {
65-
if _, err = shell.ExecCmd("rm -f "+metaDataPath, false, shell.HostPath, nil); err != nil {
65+
if _, err = shell.ExecCmd("rm -f "+metaDataPath, sudo, shell.HostPath, nil); err != nil {
6666
return fmt.Errorf("failed to remove existing Packages.gz: %w", err)
6767
}
6868
}
6969
metaDataDir := filepath.Dir(metaDataPath)
7070
if _, err := os.Stat(metaDataDir); os.IsNotExist(err) {
71-
if _, err = shell.ExecCmd("mkdir -p "+metaDataDir, false, shell.HostPath, nil); err != nil {
71+
if _, err = shell.ExecCmd("mkdir -p "+metaDataDir, sudo, shell.HostPath, nil); err != nil {
7272
return fmt.Errorf("failed to create metadata directory %s: %w", metaDataDir, err)
7373
}
7474
}
7575

76-
cmd := fmt.Sprintf("cd %s && sudo dpkg-scanpackages . /dev/null | gzip -9c > %s", repoPath, metaDataPath)
77-
if _, err := shell.ExecCmd(cmd, false, shell.HostPath, nil); err != nil {
76+
// Escape any double quotes and dollar signs in the paths
77+
safeRepoPath := strings.ReplaceAll(repoPath, `"`, `\"`)
78+
safeRepoPath = strings.ReplaceAll(safeRepoPath, "$", `\$`)
79+
safeMetaDataPath := strings.ReplaceAll(metaDataPath, `"`, `\"`)
80+
safeMetaDataPath = strings.ReplaceAll(safeMetaDataPath, "$", `\$`)
81+
82+
cmd := fmt.Sprintf("bash -c \"cd %s && dpkg-scanpackages . /dev/null | gzip -9c > %s\"", safeRepoPath, safeMetaDataPath)
83+
if _, err := shell.ExecCmd(cmd, sudo, shell.HostPath, nil); err != nil {
7884
return fmt.Errorf("failed to create local debian cache repository: %w", err)
7985
}
8086

internal/chroot/deb/installer_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func TestUpdateLocalDebRepo_ArchitectureMapping(t *testing.T) {
4444

4545
for _, tt := range tests {
4646
t.Run(tt.name, func(t *testing.T) {
47-
err := installer.UpdateLocalDebRepo(tempDir, tt.inputArch)
47+
err := installer.UpdateLocalDebRepo(tempDir, tt.inputArch, false)
4848

4949
if tt.expectError {
5050
if err == nil {
@@ -76,7 +76,7 @@ func TestUpdateLocalDebRepo_DirectoryCreation(t *testing.T) {
7676
shell.Default = shell.NewMockExecutor(mockExpectedOutput)
7777

7878
// Test that it attempts to create the metadata directory structure
79-
err := installer.UpdateLocalDebRepo(tempDir, "x86_64")
79+
err := installer.UpdateLocalDebRepo(tempDir, "x86_64", false)
8080

8181
// We expect this to fail due to missing dpkg-scanpackages, but the directory should be created
8282
expectedDir := filepath.Join(tempDir, "dists/stable/main/binary-amd64")
@@ -113,7 +113,7 @@ func TestUpdateLocalDebRepo_ExistingPackagesGz(t *testing.T) {
113113
}
114114

115115
// Run UpdateLocalDebRepo
116-
err := installer.UpdateLocalDebRepo(tempDir, "amd64")
116+
err := installer.UpdateLocalDebRepo(tempDir, "amd64", false)
117117

118118
// The file should be removed (and the command will fail due to missing dpkg-scanpackages)
119119
if err != nil && !strings.Contains(err.Error(), "failed to create local debian cache repository") {
@@ -372,7 +372,7 @@ func TestUpdateLocalDebRepo_EmptyRepoPath(t *testing.T) {
372372
}
373373
shell.Default = shell.NewMockExecutor(mockExpectedOutput)
374374

375-
err := installer.UpdateLocalDebRepo("", "amd64")
375+
err := installer.UpdateLocalDebRepo("", "amd64", false)
376376

377377
// Should fail when trying to create directory structure in empty path
378378
if err == nil {

internal/config/schema/os-image-template.schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
"id": { "type": "string", "description": "Partition identifier" },
115115
"name": { "type": "string", "description": "Partition name/label" },
116116
"type": { "type": "string", "description": "Partition type" },
117+
"typeUUID": { "type": "string", "description": "Partition type UUID" },
117118
"fsType": { "type": "string", "description": "Filesystem type" },
118119
"start": { "type": "string", "description": "Partition start offset" },
119120
"end": { "type": "string", "description": "Partition end offset (0 = rest of disk)" },

internal/image/imageboot/imageboot.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ func updateBootConfigTemplate(installRoot, rootDevID, bootUUID, bootPrefix, hash
134134
log.Errorf("Failed to copy boot configuration file: %v", err)
135135
return fmt.Errorf("failed to copy boot configuration file: %w", err)
136136
}
137+
138+
if err := file.ReplacePlaceholdersInFile("{{.Hostname}}", template.GetImageName(), configFinalPath); err != nil {
139+
log.Errorf("Failed to replace Hostname in boot configuration: %v", err)
140+
return fmt.Errorf("failed to replace Hostname in boot configuration: %w", err)
141+
}
137142
case "systemd-boot":
138143
configAssetPath = filepath.Join(configDir, "image", "efi", "bootParams.conf")
139144
configFinalPath = filepath.Join(installRoot, "boot", "cmdline.conf")

internal/image/imageos/imageos_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ func (m *MockChrootEnv) MountChrootPath(hostFullPath, chrootPath, mountFlags str
104104
func (m *MockChrootEnv) UmountChrootPath(chrootPath string) error { return nil }
105105
func (m *MockChrootEnv) CopyFileFromHostToChroot(hostFilePath, chrootPath string) error { return nil }
106106
func (m *MockChrootEnv) CopyFileFromChrootToHost(hostFilePath, chrootPath string) error { return nil }
107-
func (m *MockChrootEnv) RefreshLocalCacheRepo(targetArch string) error { return nil }
107+
func (m *MockChrootEnv) UpdateChrootLocalRepoMetadata(chrootRepoDir string, targetArch string, sudo bool) error {
108+
return nil
109+
}
110+
func (m *MockChrootEnv) RefreshLocalCacheRepo() error { return nil }
108111
func (m *MockChrootEnv) InitChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
109112
func (m *MockChrootEnv) CleanupChrootEnv(targetOs, targetDist, targetArch string) error { return nil }
110113
func (m *MockChrootEnv) TdnfInstallPackage(packageName, installRoot string, repositoryIDList []string) error {
@@ -2284,6 +2287,7 @@ func TestAddImageAdditionalFiles(t *testing.T) {
22842287
mockCommands := []shell.MockCommand{
22852288
{Pattern: ".*cp.*", Output: "", Error: nil},
22862289
{Pattern: "/bin/cp.*", Output: "", Error: nil},
2290+
{Pattern: "mkdir", Output: "", Error: nil},
22872291
}
22882292
shell.Default = shell.NewMockExecutor(mockCommands)
22892293

internal/image/initrdmaker/initrdmaker.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,13 @@ func (initrdMaker *InitrdMaker) DownloadInitrdPkgs() error {
119119
}
120120
}
121121

122-
if err := initrdMaker.ChrootEnv.RefreshLocalCacheRepo(initrdMaker.template.Target.Arch); err != nil {
122+
if err := initrdMaker.ChrootEnv.UpdateChrootLocalRepoMetadata(
123+
chroot.ChrootRepoDir,
124+
initrdMaker.template.Target.Arch, false); err != nil {
125+
return fmt.Errorf("failed to update local cache repository metadata: %w", err)
126+
}
127+
128+
if err := initrdMaker.ChrootEnv.RefreshLocalCacheRepo(); err != nil {
123129
return fmt.Errorf("failed to refresh local cache repository: %w", err)
124130
}
125131
return nil

0 commit comments

Comments
 (0)