launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/storage/storage.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"path"
    10  
    11  	"launchpad.net/juju-core/environs/simplestreams"
    12  	"launchpad.net/juju-core/utils"
    13  )
    14  
    15  // RemoveAll is a default implementation for StorageWriter.RemoveAll.
    16  // Providers may have more efficient implementations, or better error handling,
    17  // or safeguards against races with other users of the same storage medium.
    18  // But a simple way to implement RemoveAll would be to delegate to here.
    19  func RemoveAll(stor Storage) error {
    20  	files, err := List(stor, "")
    21  	if err != nil {
    22  		return fmt.Errorf("unable to list files for deletion: %v", err)
    23  	}
    24  
    25  	// Some limited parallellism might be useful in this loop.
    26  	for _, file := range files {
    27  		err = stor.Remove(file)
    28  		if err != nil {
    29  			break
    30  		}
    31  	}
    32  	return err
    33  }
    34  
    35  // Get gets the named file from stor using the stor's default consistency strategy.
    36  func Get(stor StorageReader, name string) (io.ReadCloser, error) {
    37  	return GetWithRetry(stor, name, stor.DefaultConsistencyStrategy())
    38  }
    39  
    40  // GetWithRetry gets the named file from stor using the specified attempt strategy.
    41  func GetWithRetry(stor StorageReader, name string, attempt utils.AttemptStrategy) (r io.ReadCloser, err error) {
    42  	for a := attempt.Start(); a.Next(); {
    43  		r, err = stor.Get(name)
    44  		if err == nil || !stor.ShouldRetry(err) {
    45  			break
    46  		}
    47  	}
    48  	return r, err
    49  }
    50  
    51  // List lists the files matching prefix from stor using the stor's default consistency strategy.
    52  func List(stor StorageReader, prefix string) ([]string, error) {
    53  	return ListWithRetry(stor, prefix, stor.DefaultConsistencyStrategy())
    54  }
    55  
    56  // ListWithRetry lists the files matching prefix from stor using the specified attempt strategy.
    57  func ListWithRetry(stor StorageReader, prefix string, attempt utils.AttemptStrategy) (list []string, err error) {
    58  	for a := attempt.Start(); a.Next(); {
    59  		list, err = stor.List(prefix)
    60  		if err == nil || !stor.ShouldRetry(err) {
    61  			break
    62  		}
    63  	}
    64  	return list, err
    65  }
    66  
    67  // BaseToolsPath is the container where tools tarballs and metadata are found.
    68  var BaseToolsPath = "tools"
    69  
    70  // BaseImagesPath is the container where images metadata is found.
    71  var BaseImagesPath = "images"
    72  
    73  // A storageSimpleStreamsDataSource retrieves data from a StorageReader.
    74  type storageSimpleStreamsDataSource struct {
    75  	basePath   string
    76  	storage    StorageReader
    77  	allowRetry bool
    78  }
    79  
    80  // TestingGetAllowRetry is used in tests which need to see if allowRetry has been
    81  // set on a storageSimpleStreamsDataSource.
    82  func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) {
    83  	if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok {
    84  		return storageDataSource.allowRetry, ok
    85  	}
    86  	return false, false
    87  }
    88  
    89  // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage.
    90  func NewStorageSimpleStreamsDataSource(storage StorageReader, basePath string) simplestreams.DataSource {
    91  	return &storageSimpleStreamsDataSource{basePath, storage, false}
    92  }
    93  
    94  func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string {
    95  	relpath := storagePath
    96  	if s.basePath != "" {
    97  		relpath = path.Join(s.basePath, relpath)
    98  	}
    99  	return relpath
   100  }
   101  
   102  // Fetch is defined in simplestreams.DataSource.
   103  func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) {
   104  	relpath := s.relpath(path)
   105  	dataURL := relpath
   106  	fullURL, err := s.storage.URL(relpath)
   107  	if err == nil {
   108  		dataURL = fullURL
   109  	}
   110  	var attempt utils.AttemptStrategy
   111  	if s.allowRetry {
   112  		attempt = s.storage.DefaultConsistencyStrategy()
   113  	}
   114  	rc, err := GetWithRetry(s.storage, relpath, attempt)
   115  	if err != nil {
   116  		return nil, dataURL, err
   117  	}
   118  	return rc, dataURL, nil
   119  }
   120  
   121  // URL is defined in simplestreams.DataSource.
   122  func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) {
   123  	return s.storage.URL(s.relpath(path))
   124  }
   125  
   126  // SetAllowRetry is defined in simplestreams.DataSource.
   127  func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) {
   128  	s.allowRetry = allow
   129  }