Skip to content

Commit dd85493

Browse files
committed
publish: check if storage exists
1 parent 29e643c commit dd85493

14 files changed

Lines changed: 94 additions & 70 deletions

api/files.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func apiFilesUploadOne(c *gin.Context) {
230230
AbortWithJSONError(c, 500, err)
231231
return
232232
}
233-
defer dst.Close()
233+
defer func() { _ = dst.Close() }()
234234

235235
if _, err = io.Copy(dst, c.Request.Body); err != nil {
236236
AbortWithJSONError(c, 500, err)

api/published_file_missing_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ func (s *PublishedFileMissingSuite) TestPublishedFileGoMissing(c *C) {
220220
c.Assert(resp.Code, Equals, 200, Commentf("Failed to update publish: %s", resp.Body.String()))
221221

222222
// Now check if the file is actually accessible in the published location
223-
publishedStorage := s.context.GetPublishedStorage("")
223+
publishedStorage, err := s.context.GetPublishedStorage("")
224+
c.Assert(err, IsNil)
224225
publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath()
225226

226227
// Expected file path: hrt/pool/main/h/hrt-libblobbyclient1/hrt-libblobbyclient1_20250926.152427+hrtdeb11_amd64.deb
@@ -332,7 +333,8 @@ func (s *PublishedFileMissingSuite) TestConcurrentPublishRace(c *C) {
332333
c.Assert(err, IsNil)
333334

334335
// Check published files
335-
publishedStorage := s.context.GetPublishedStorage("")
336+
publishedStorage, err := s.context.GetPublishedStorage("")
337+
c.Assert(err, IsNil)
336338
publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath()
337339

338340
missingFiles := []string{}
@@ -446,7 +448,8 @@ func (s *PublishedFileMissingSuite) TestIdenticalPackageRace(c *C) {
446448
c.Logf("[iter %d] All operations complete", iter)
447449

448450
// Check the shared pool location
449-
publishedStorage := s.context.GetPublishedStorage("")
451+
publishedStorage, err := s.context.GetPublishedStorage("")
452+
c.Assert(err, IsNil)
450453
publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath()
451454

452455
poolSubdir := string(packageName[0])
@@ -663,7 +666,8 @@ func (s *PublishedFileMissingSuite) TestConcurrentSnapshotPublishToSamePrefix(c
663666
c.Assert(bullseyePublishCode, Equals, expectedCode, Commentf("Bullseye publish/update should succeed"))
664667

665668
// Verify ALL package files exist in the published pool
666-
publishedStorage := s.context.GetPublishedStorage("")
669+
publishedStorage, err := s.context.GetPublishedStorage("")
670+
c.Assert(err, IsNil)
667671
publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath()
668672

669673
missingFiles := []string{}

api/repos.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,12 @@ func reposServeInAPIMode(c *gin.Context) {
6060
storage = "filesystem:" + storage
6161
}
6262

63-
publicPath := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage).PublicPath()
63+
ps, err := context.GetPublishedStorage(storage)
64+
if err != nil {
65+
AbortWithJSONError(c, http.StatusNotFound, err)
66+
return
67+
}
68+
publicPath := ps.(aptly.FileSystemPublishedStorage).PublicPath()
6469
c.FileFromFS(pkgpath, http.Dir(publicPath))
6570
}
6671

aptly/interfaces.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ type FileSystemPublishedStorage interface {
9595

9696
// PublishedStorageProvider is a thing that returns PublishedStorage by name
9797
type PublishedStorageProvider interface {
98-
// GetPublishedStorage returns PublishedStorage by name
99-
GetPublishedStorage(name string) PublishedStorage
98+
// GetPublishedStorage returns PublishedStorage by name, or an error if the storage is not configured
99+
GetPublishedStorage(name string) (PublishedStorage, error)
100100
}
101101

102102
// BarType used to differentiate between different progress bars

cmd/publish_snapshot.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,11 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
198198

199199
context.Progress().Printf("\n%s been successfully published.\n", message)
200200

201-
if localStorage, ok := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage); ok {
202-
context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n",
203-
localStorage.PublicPath())
201+
if ps, err := context.GetPublishedStorage(storage); err == nil {
202+
if localStorage, ok := ps.(aptly.FileSystemPublishedStorage); ok {
203+
context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n",
204+
localStorage.PublicPath())
205+
}
204206
}
205207

206208
context.Progress().Printf("Now you can add following line to apt sources:\n")

cmd/serve.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,11 @@ func aptlyServe(cmd *commander.Command, args []string) error {
9797
}
9898
}
9999

100-
publicPath := context.GetPublishedStorage("").(aptly.FileSystemPublishedStorage).PublicPath()
100+
ps, err := context.GetPublishedStorage("")
101+
if err != nil {
102+
return err
103+
}
104+
publicPath := ps.(aptly.FileSystemPublishedStorage).PublicPath()
101105
ShutdownContext()
102106

103107
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)

context/context.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ func (context *AptlyContext) config() *utils.ConfigStructure {
117117
if err != nil {
118118
fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", homeLocation)
119119

120-
_ = utils.SaveConfigRaw(homeLocation, aptly.AptlyConf)
120+
defaultConfig := aptly.AptlyConf
121+
if len(defaultConfig) == 0 {
122+
defaultConfig = []byte("root_dir: \"\"")
123+
}
124+
125+
_ = utils.SaveConfigRaw(homeLocation, defaultConfig)
121126
err = utils.LoadConfig(homeLocation, &utils.Config)
122127
if err != nil {
123128
Fatal(fmt.Errorf("error loading config file %s: %s", homeLocation, err))
@@ -408,8 +413,8 @@ func (context *AptlyContext) PackagePool() aptly.PackagePool {
408413
return context.packagePool
409414
}
410415

411-
// GetPublishedStorage returns instance of PublishedStorage
412-
func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedStorage {
416+
// GetPublishedStorage returns instance of PublishedStorage, or an error if the storage is not configured
417+
func (context *AptlyContext) GetPublishedStorage(name string) (aptly.PublishedStorage, error) {
413418
context.Lock()
414419
defer context.Unlock()
415420

@@ -420,14 +425,14 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto
420425
} else if strings.HasPrefix(name, "filesystem:") {
421426
params, ok := context.config().FileSystemPublishRoots[name[11:]]
422427
if !ok {
423-
Fatal(fmt.Errorf("published local storage %v not configured", name[11:]))
428+
return nil, fmt.Errorf("published local storage %v not configured", name[11:])
424429
}
425430

426431
publishedStorage = files.NewPublishedStorage(params.RootDir, params.LinkMethod, params.VerifyMethod)
427432
} else if strings.HasPrefix(name, "s3:") {
428433
params, ok := context.config().S3PublishRoots[name[3:]]
429434
if !ok {
430-
Fatal(fmt.Errorf("published S3 storage %v not configured", name[3:]))
435+
return nil, fmt.Errorf("published S3 storage %v not configured", name[3:])
431436
}
432437

433438
var err error
@@ -437,12 +442,12 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto
437442
params.EncryptionMethod, params.PlusWorkaround, params.DisableMultiDel,
438443
params.ForceSigV2, params.ForceVirtualHostedStyle, params.Debug)
439444
if err != nil {
440-
Fatal(err)
445+
return nil, err
441446
}
442447
} else if strings.HasPrefix(name, "gcs:") {
443448
params, ok := context.config().GCSPublishRoots[name[4:]]
444449
if !ok {
445-
Fatal(fmt.Errorf("published GCS storage %v not configured", name[4:]))
450+
return nil, fmt.Errorf("published GCS storage %v not configured", name[4:])
446451
}
447452

448453
var err error
@@ -451,51 +456,51 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto
451456
params.Project, params.Endpoint, params.ACL, params.StorageClass, params.EncryptionKey,
452457
params.DisableMultiDel, params.Debug)
453458
if err != nil {
454-
Fatal(err)
459+
return nil, err
455460
}
456461
} else if strings.HasPrefix(name, "swift:") {
457462
params, ok := context.config().SwiftPublishRoots[name[6:]]
458463
if !ok {
459-
Fatal(fmt.Errorf("published Swift storage %v not configured", name[6:]))
464+
return nil, fmt.Errorf("published Swift storage %v not configured", name[6:])
460465
}
461466

462467
var err error
463468
publishedStorage, err = swift.NewPublishedStorage(params.UserName, params.Password,
464469
params.AuthURL, params.Tenant, params.TenantID, params.Domain, params.DomainID, params.TenantDomain, params.TenantDomainID, params.Container, params.Prefix)
465470
if err != nil {
466-
Fatal(err)
471+
return nil, err
467472
}
468473
} else if strings.HasPrefix(name, "azure:") {
469474
params, ok := context.config().AzurePublishRoots[name[6:]]
470475
if !ok {
471-
Fatal(fmt.Errorf("published Azure storage %v not configured", name[6:]))
476+
return nil, fmt.Errorf("published Azure storage %v not configured", name[6:])
472477
}
473478

474479
var err error
475480
publishedStorage, err = azure.NewPublishedStorage(
476481
params.AccountName, params.AccountKey, params.Container, params.Prefix, params.Endpoint)
477482
if err != nil {
478-
Fatal(err)
483+
return nil, err
479484
}
480485
} else if strings.HasPrefix(name, "jfrog:") {
481486
params, ok := context.config().JFrogPublishRoots[name[6:]]
482487
if !ok {
483-
Fatal(fmt.Errorf("published JFrog storage %v not configured", name[6:]))
488+
return nil, fmt.Errorf("published JFrog storage %v not configured", name[6:])
484489
}
485490

486491
var err error
487492
publishedStorage, err = jfrog.NewPublishedStorage(
488493
name[6:], params)
489494
if err != nil {
490-
Fatal(err)
495+
return nil, fmt.Errorf("error creating jfrog manager: %w", err)
491496
}
492497
} else {
493-
Fatal(fmt.Errorf("unknown published storage format: %v", name))
498+
return nil, fmt.Errorf("unknown published storage format: %v", name)
494499
}
495500
context.publishedStorages[name] = publishedStorage
496501
}
497502

498-
return publishedStorage
503+
return publishedStorage, nil
499504
}
500505

501506
// UploadPath builds path to upload storage

context/context_test.go

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package context
22

33
import (
44
"fmt"
5-
"os"
65
"reflect"
76
"testing"
87

@@ -81,12 +80,11 @@ func (s *AptlyContextSuite) SetUpTest(c *C) {
8180

8281
func (s *AptlyContextSuite) TestGetPublishedStorageBadFS(c *C) {
8382
// https://github.com/aptly-dev/aptly/issues/711
84-
// This will fail on account of us not having a config, so the
85-
// storage never exists.
86-
c.Assert(func() { s.context.GetPublishedStorage("filesystem:fuji") },
87-
FatalErrorPanicMatches,
88-
&FatalError{ReturnCode: 1, Message: fmt.Sprintf("error loading config file %s/.aptly.conf: invalid yaml (EOF) or json (EOF)",
89-
os.Getenv("HOME"))})
83+
// https://github.com/aptly-dev/aptly/issues/1477
84+
// GetPublishedStorage must return an error (not panic) when the
85+
// requested storage is not configured.
86+
_, err := s.context.GetPublishedStorage("filesystem:fuji")
87+
c.Assert(err, NotNil)
9088
}
9189

9290
func (s *AptlyContextSuite) TestGetPublishedStorageJFrogConfigured(c *C) {
@@ -98,18 +96,20 @@ func (s *AptlyContextSuite) TestGetPublishedStorageJFrogConfigured(c *C) {
9896
utils.Config.JFrogPublishRoots = map[string]utils.JFrogPublishRoot{
9997
"test": {
10098
Repository: "aptly-repo",
101-
Url: "https://example.jfrog.local/artifactory",
99+
URL: "https://example.jfrog.local/artifactory",
102100
AccessToken: "token",
103101
Prefix: "public",
104102
},
105103
}
106104

107-
storage := s.context.GetPublishedStorage("jfrog:test")
105+
storage, err := s.context.GetPublishedStorage("jfrog:test")
106+
c.Assert(err, IsNil)
108107
c.Assert(storage, NotNil)
109108
c.Assert(fmt.Sprintf("%v", storage), Equals, "jfrog:aptly-repo:public")
110109

111110
// Ensure we get the cached object on repeated lookups.
112-
storageAgain := s.context.GetPublishedStorage("jfrog:test")
111+
storageAgain, err := s.context.GetPublishedStorage("jfrog:test")
112+
c.Assert(err, IsNil)
113113
c.Assert(storageAgain, Equals, storage)
114114
}
115115

@@ -120,9 +120,9 @@ func (s *AptlyContextSuite) TestGetPublishedStorageJFrogMissing(c *C) {
120120
s.context.configLoaded = true
121121
utils.Config.JFrogPublishRoots = map[string]utils.JFrogPublishRoot{}
122122

123-
c.Assert(func() { s.context.GetPublishedStorage("jfrog:missing") },
124-
FatalErrorPanicMatches,
125-
&FatalError{ReturnCode: 1, Message: "published JFrog storage missing not configured"})
123+
_, err := s.context.GetPublishedStorage("jfrog:missing")
124+
c.Assert(err, NotNil)
125+
c.Check(err.Error(), Equals, "published JFrog storage missing not configured")
126126
}
127127

128128
func (s *AptlyContextSuite) TestGetPublishedStorageJFrogInitError(c *C) {
@@ -133,19 +133,11 @@ func (s *AptlyContextSuite) TestGetPublishedStorageJFrogInitError(c *C) {
133133
utils.Config.JFrogPublishRoots = map[string]utils.JFrogPublishRoot{
134134
"broken": {
135135
Repository: "aptly-repo",
136-
Url: "ssh://example.local/artifactory",
136+
URL: "ssh://example.local/artifactory",
137137
},
138138
}
139139

140-
defer func() {
141-
obtained := recover()
142-
c.Assert(obtained, NotNil)
143-
144-
fatalErr, ok := obtained.(*FatalError)
145-
c.Assert(ok, Equals, true)
146-
c.Check(fatalErr.ReturnCode, Equals, 1)
147-
c.Check(fatalErr.Message, Matches, `error creating jfrog manager: .*`)
148-
}()
149-
150-
s.context.GetPublishedStorage("jfrog:broken")
140+
_, err := s.context.GetPublishedStorage("jfrog:broken")
141+
c.Assert(err, NotNil)
142+
c.Check(err.Error(), Matches, `error creating jfrog manager: .*`)
151143
}

deb/publish.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,12 @@ func (p *PublishedRepo) GetSkelFiles(skelDir string, component string) (map[stri
832832
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
833833
func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider,
834834
collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool, skelDir string) error {
835-
publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage)
835+
publishedStorage, err := publishedStorageProvider.GetPublishedStorage(p.Storage)
836+
if err != nil {
837+
return err
838+
}
836839

837-
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
840+
err = publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
838841
if err != nil {
839842
return err
840843
}
@@ -1258,7 +1261,10 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
12581261
// It can remove prefix fully, and part of pool (for specific component)
12591262
func (p *PublishedRepo) RemoveFiles(publishedStorageProvider aptly.PublishedStorageProvider, removePrefix bool,
12601263
removePoolComponents []string, progress aptly.Progress) error {
1261-
publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage)
1264+
publishedStorage, err := publishedStorageProvider.GetPublishedStorage(p.Storage)
1265+
if err != nil {
1266+
return err
1267+
}
12621268

12631269
// I. Easy: remove whole prefix (meta+packages)
12641270
if removePrefix {
@@ -1271,7 +1277,7 @@ func (p *PublishedRepo) RemoveFiles(publishedStorageProvider aptly.PublishedStor
12711277
}
12721278

12731279
// II. Medium: remove metadata, it can't be shared as prefix/distribution as unique
1274-
err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution), progress)
1280+
err = publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution), progress)
12751281
if err != nil {
12761282
return err
12771283
}
@@ -1631,7 +1637,10 @@ func (collection *PublishedRepoCollection) CleanupAfterMultiDistToggle(published
16311637
}
16321638

16331639
// true→false: directly remove the per-distribution pool directories.
1634-
publishedStorage := publishedStorageProvider.GetPublishedStorage(published.Storage)
1640+
publishedStorage, err := publishedStorageProvider.GetPublishedStorage(published.Storage)
1641+
if err != nil {
1642+
return err
1643+
}
16351644
for _, component := range cleanComponents {
16361645
poolDir := filepath.Join(published.Prefix, "pool", published.Distribution, component)
16371646
if err := publishedStorage.RemoveDirs(poolDir, progress); err != nil {
@@ -1657,7 +1666,10 @@ func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(published
16571666
distribution := published.Distribution
16581667

16591668
rootPath := filepath.Join(prefix, "dists", distribution)
1660-
publishedStorage := publishedStorageProvider.GetPublishedStorage(published.Storage)
1669+
publishedStorage, err := publishedStorageProvider.GetPublishedStorage(published.Storage)
1670+
if err != nil {
1671+
return err
1672+
}
16611673

16621674
sort.Strings(cleanComponents)
16631675
publishedComponents := published.Components()

deb/publish_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ type FakeStorageProvider struct {
6262
storages map[string]aptly.PublishedStorage
6363
}
6464

65-
func (p *FakeStorageProvider) GetPublishedStorage(name string) aptly.PublishedStorage {
65+
func (p *FakeStorageProvider) GetPublishedStorage(name string) (aptly.PublishedStorage, error) {
6666
storage, ok := p.storages[name]
6767
if !ok {
68-
panic(fmt.Sprintf("unknown storage: %#v", name))
68+
return nil, fmt.Errorf("unknown storage: %#v", name)
6969
}
70-
return storage
70+
return storage, nil
7171
}
7272

7373
type PublishedRepoSuite struct {

0 commit comments

Comments
 (0)