diff --git a/cmd/chisel/cmd_cut.go b/cmd/chisel/cmd_cut.go index 35c81a79..7c7ac846 100644 --- a/cmd/chisel/cmd_cut.go +++ b/cmd/chisel/cmd_cut.go @@ -3,6 +3,8 @@ package main import ( "fmt" "slices" + "sort" + "strings" "time" "github.com/jessevdk/go-flags" @@ -79,6 +81,7 @@ func (cmd *cmdCut) Execute(args []string) error { } archives := make(map[string]archive.Archive) + var ignoredArchives []string for archiveName, archiveInfo := range release.Archives { openArchive, err := archive.Open(&archive.Options{ Label: archiveName, @@ -94,13 +97,14 @@ func (cmd *cmdCut) Execute(args []string) error { }) if err != nil { if err == archive.ErrCredentialsNotFound { - logf("Archive %q ignored: credentials not found", archiveName) + ignoredArchives = append(ignoredArchives, archiveName) continue } return err } archives[archiveName] = openArchive } + logIgnoredProArchives(ignoredArchives) hasMaintainedArchive := false for _, archive := range archives { @@ -128,3 +132,13 @@ func (cmd *cmdCut) Execute(args []string) error { }) return err } + +// logIgnoredProArchives logs a single message listing the Ubuntu Pro archives +// that were ignored because no credentials were found for them. +func logIgnoredProArchives(archiveNames []string) { + if len(archiveNames) == 0 { + return + } + sort.Strings(archiveNames) + logf("Ubuntu Pro subscription not available, ignoring archives: %s", strings.Join(archiveNames, ", ")) +} diff --git a/cmd/chisel/cmd_debug_check_release_archives.go b/cmd/chisel/cmd_debug_check_release_archives.go index c9c6270e..3602d813 100644 --- a/cmd/chisel/cmd_debug_check_release_archives.go +++ b/cmd/chisel/cmd_debug_check_release_archives.go @@ -63,6 +63,7 @@ func (cmd *cmdDebugCheckReleaseArchives) Execute(args []string) error { } archives := make(map[string]archive.Archive) + var ignoredArchives []string for archiveName, archiveInfo := range release.Archives { openArchive, err := archiveOpen(&archive.Options{ Label: archiveName, @@ -77,13 +78,14 @@ func (cmd *cmdDebugCheckReleaseArchives) Execute(args []string) error { OldRelease: archiveInfo.OldRelease, }) if err == archive.ErrCredentialsNotFound { - logf("Archive %q ignored: credentials not found\n", archiveName) + ignoredArchives = append(ignoredArchives, archiveName) continue } else if err != nil { return err } archives[archiveName] = openArchive } + logIgnoredProArchives(ignoredArchives) pathObs, err := computePathObservations(release, archives) if err != nil { diff --git a/cmd/chisel/cmd_debug_check_release_archives_test.go b/cmd/chisel/cmd_debug_check_release_archives_test.go index 0ca5afb0..33036de8 100644 --- a/cmd/chisel/cmd_debug_check_release_archives_test.go +++ b/cmd/chisel/cmd_debug_check_release_archives_test.go @@ -1,6 +1,8 @@ package main_test import ( + "bytes" + "log" "os" "path/filepath" "slices" @@ -541,6 +543,69 @@ func (s *ChiselSuite) TestRun(c *C) { // makeChiselYaml returns a valid chisel.yaml that contains the archives // supplied. +func (s *ChiselSuite) TestRunIgnoresProArchivesWithoutCredentials(c *C) { + var logBuf bytes.Buffer + chisel.SetLogger(log.New(&logBuf, "", 0)) + defer chisel.SetLogger(nil) + + // Build a chisel.yaml with a regular archive and an Ubuntu Pro archive. + chiselYaml := map[string]any{} + err := yaml.Unmarshal([]byte(testutil.Reindent(testutil.DefaultChiselYaml)), chiselYaml) + c.Assert(err, IsNil) + archivesYaml := chiselYaml["archives"].(map[string]any) + ubuntuArchive := archivesYaml["ubuntu"].(map[string]any) + ubuntuArchive["priority"] = 1 + proArchive := deepCopyYAML(ubuntuArchive) + proArchive["priority"] = 2 + proArchive["pro"] = "esm-apps" + archivesYaml["ubuntu-pro"] = proArchive + bs, err := yaml.Marshal(chiselYaml) + c.Assert(err, IsNil) + + releaseDir := c.MkDir() + release := map[string]string{ + "chisel.yaml": strings.ReplaceAll(string(bs), "T00:00:00Z", ""), + "slices/mydir/pkg-a.yaml": ` + package: pkg-a + slices: + myslice: + contents: + `, + } + for path, data := range release { + fpath := filepath.Join(releaseDir, path) + err := os.MkdirAll(filepath.Dir(fpath), 0755) + c.Assert(err, IsNil) + err = os.WriteFile(fpath, testutil.Reindent(data), 0644) + c.Assert(err, IsNil) + } + + restore := chisel.FakeArchiveOpen(func(options *archive.Options) (archive.Archive, error) { + if options.Pro != "" { + return nil, archive.ErrCredentialsNotFound + } + return &testutil.TestArchive{ + Opts: *options, + Packages: map[string]*testutil.TestPackage{ + "pkg-a": { + Name: "pkg-a", + Data: testutil.MustMakeDeb([]testutil.TarEntry{ + testutil.Dir(0755, "./dir/"), + }), + }, + }, + }, nil + }) + defer restore() + + _, err = chisel.Parser().ParseArgs([]string{"debug", "check-release-archives", "--release", releaseDir}) + c.Assert(err, IsNil) + + logs := logBuf.String() + c.Assert(logs, Matches, "(?s).*Ubuntu Pro subscription not available, ignoring archives: ubuntu-pro\n.*") + c.Assert(strings.Contains(logs, "credentials not found"), Equals, false) +} + func makeChiselYaml(archives []string) string { rawChiselYaml := testutil.Reindent(testutil.DefaultChiselYaml) diff --git a/internal/archive/credentials.go b/internal/archive/credentials.go index 1f8c3289..6d398a8b 100644 --- a/internal/archive/credentials.go +++ b/internal/archive/credentials.go @@ -89,17 +89,19 @@ func findCredentials(repoURL string) (*credentials, error) { } // findCredentialsInDir searches for credentials for repoURL in configuration -// files in credsDir directory. If the directory does not exist, empty -// credentials structure with nil err is returned. +// files in credsDir directory. If the directory does not exist, +// ErrCredentialsNotFound is returned. // Only files that do not begin with dot and have either no or ".conf" // extension are searched. The files are searched in ascending lexicographic // order. The first file that contains machine declaration matching repoURL -// ends the search. If no file contain matching machine declaration, empty -// credentials structure with nil err is returned. +// ends the search. If no file contain matching machine declaration, +// ErrCredentialsNotFound is returned. func findCredentialsInDir(repoURL string, credsDir string) (*credentials, error) { contents, err := os.ReadDir(credsDir) if err != nil { - logf("Cannot open credentials directory %q: %v", credsDir, err) + if !os.IsNotExist(err) { + logf("Cannot open credentials directory %q: %v", credsDir, err) + } return nil, ErrCredentialsNotFound } diff --git a/internal/archive/credentials_test.go b/internal/archive/credentials_test.go index 4cbbb873..39cd4693 100644 --- a/internal/archive/credentials_test.go +++ b/internal/archive/credentials_test.go @@ -1,6 +1,8 @@ package archive_test import ( + "bytes" + "log" "os" "path/filepath" @@ -252,12 +254,19 @@ func (s *S) TestFindCredentialsInDirMissingDir(c *C) { var creds *archive.Credentials var err error + var logBuf bytes.Buffer + archive.SetLogger(log.New(&logBuf, "", 0)) + defer archive.SetLogger(c) + workDir := c.MkDir() credsDir := filepath.Join(workDir, "auth.conf.d") creds, err = archive.FindCredentialsInDir("https://example.com/foo/bar", credsDir) c.Assert(err, ErrorMatches, "^credentials not found$") c.Assert(creds, IsNil) + // A missing credentials directory is expected without Ubuntu Pro + // credentials and must not be logged as if it were an error. + c.Assert(logBuf.String(), Equals, "") err = os.Mkdir(credsDir, 0755) c.Assert(err, IsNil)