Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
47 changes: 33 additions & 14 deletions internal/archive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,28 +189,31 @@ var proArchiveInfo = map[string]struct {
},
}

func archiveURL(pro, arch string, oldRelease bool) (string, *credentials, error) {
func archiveURL(pro, arch string, oldRelease bool) (string, string, *credentials, error) {
if pro != "" {
archiveInfo, ok := proArchiveInfo[pro]
if !ok {
return "", nil, fmt.Errorf("invalid pro value: %q", pro)
return "", "", nil, fmt.Errorf("invalid pro value: %q", pro)
}
url := archiveInfo.BaseURL
creds, err := findCredentials(url)
if err != nil {
return "", nil, err
return "", "", nil, err
}
return url, creds, nil
return url, "", creds, nil
}

if oldRelease {
return ubuntuOldReleasesURL, nil, nil
current := ubuntuURL
if arch != "amd64" && arch != "i386" {
current = ubuntuPortsURL
}

if arch == "amd64" || arch == "i386" {
return ubuntuURL, nil, nil
if oldRelease {
// The old release may not have moved from archive.ubuntu.com
// to old-releases.ubuntu.com yet. So return the current
// archive as a fallback.
return ubuntuOldReleasesURL, current, nil, nil
}
return ubuntuPortsURL, nil, nil
return current, "", nil, nil
}

func openUbuntu(options *Options) (Archive, error) {
Expand All @@ -224,21 +227,37 @@ func openUbuntu(options *Options) (Archive, error) {
return nil, fmt.Errorf("archive options missing version")
}

baseURL, creds, err := archiveURL(options.Pro, options.Arch, options.OldRelease)
baseURL, fallbackURL, creds, err := archiveURL(options.Pro, options.Arch, options.OldRelease)
if err != nil {
return nil, err
}

archive := &ubuntuArchive{
options: *options,
cache: &cache.Cache{
Dir: options.CacheDir,
},
cache: &cache.Cache{Dir: options.CacheDir},
pubKeys: options.PubKeys,
baseURL: baseURL,
creds: creds,
}

if fallbackURL != "" {
// Check if the release is in the expected archive, use the
// fallback one if not.
probe := &ubuntuIndex{
label: options.Label,
version: options.Version,
arch: options.Arch,
suite: options.Suites[0],
archive: archive,
}
_, err := probe.fetch(probe.distPath("InRelease"), "", fetchDefault)
if err == errNotFound {
archive.baseURL = fallbackURL
} else if err != nil {
return nil, err
}
}

for _, suite := range options.Suites {
var release control.Section
for _, component := range options.Components {
Expand Down
48 changes: 48 additions & 0 deletions internal/archive/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,54 @@ func (s *httpSuite) TestOpenUnmaintainedArchives(c *C) {
c.Assert(err, IsNil)
}

// TestOpenOldReleaseFallback verifies that when OldRelease is set and the
// old-releases mirror returns 404 (because the release has not yet been
// physically moved), Chisel uses the current archive.
func (s *httpSuite) TestOpenOldReleaseFallback(c *C) {
s.prepareArchive("plucky", "25.04", "amd64", []string{"main"})

// Override Do: return 404 for old-releases, delegate to s.Do (which
// serves the prepared content) for the current archive.
s.restore()
s.restore = archive.FakeDo(func(req *http.Request) (*http.Response, error) {
if strings.HasPrefix(req.URL.String(), "http://old-releases.ubuntu.com/ubuntu/") {
s.requestResults = append(s.requestResults, requestResult{path: req.URL.Path, status: 404})
return &http.Response{
Body: io.NopCloser(strings.NewReader("")),
StatusCode: 404,
}, nil
}
return s.Do(req)
})

options := archive.Options{
Label: "ubuntu",
Version: "25.04",
Arch: "amd64",
Suites: []string{"plucky"},
Components: []string{"main"},
CacheDir: c.MkDir(),
PubKeys: []*packet.PublicKey{s.pubKey},
OldRelease: true,
}

testArchive, err := archive.Open(&options)
c.Assert(err, IsNil)

_, _, err = testArchive.Fetch("mypkg1")
c.Assert(err, IsNil)

// Exactly one 404 (the probe to old-releases); all subsequent
// requests must be served by the current archive.
oldReleasesHits := 0
for _, r := range s.requestResults {
if r.status == 404 {
oldReleasesHits++
}
}
c.Assert(oldReleasesHits, Equals, 1)
}

type verifyArchiveReleaseTest struct {
summary string
pubKeys []*packet.PublicKey
Expand Down
Loading