github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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  	description string
    76  	basePath    string
    77  	storage     StorageReader
    78  	allowRetry  bool
    79  }
    80  
    81  // TestingGetAllowRetry is used in tests which need to see if allowRetry has been
    82  // set on a storageSimpleStreamsDataSource.
    83  func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) {
    84  	if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok {
    85  		return storageDataSource.allowRetry, ok
    86  	}
    87  	return false, false
    88  }
    89  
    90  // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage.
    91  func NewStorageSimpleStreamsDataSource(description string, storage StorageReader, basePath string) simplestreams.DataSource {
    92  	return &storageSimpleStreamsDataSource{description, basePath, storage, false}
    93  }
    94  
    95  func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string {
    96  	relpath := storagePath
    97  	if s.basePath != "" {
    98  		relpath = path.Join(s.basePath, relpath)
    99  	}
   100  	return relpath
   101  }
   102  
   103  // Description is defined in simplestreams.DataSource.
   104  func (s *storageSimpleStreamsDataSource) Description() string {
   105  	return s.description
   106  }
   107  
   108  // Fetch is defined in simplestreams.DataSource.
   109  func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) {
   110  	relpath := s.relpath(path)
   111  	dataURL := relpath
   112  	fullURL, err := s.storage.URL(relpath)
   113  	if err == nil {
   114  		dataURL = fullURL
   115  	}
   116  	var attempt utils.AttemptStrategy
   117  	if s.allowRetry {
   118  		attempt = s.storage.DefaultConsistencyStrategy()
   119  	}
   120  	rc, err := GetWithRetry(s.storage, relpath, attempt)
   121  	if err != nil {
   122  		return nil, dataURL, err
   123  	}
   124  	return rc, dataURL, nil
   125  }
   126  
   127  // URL is defined in simplestreams.DataSource.
   128  func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) {
   129  	return s.storage.URL(s.relpath(path))
   130  }
   131  
   132  // SetAllowRetry is defined in simplestreams.DataSource.
   133  func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) {
   134  	s.allowRetry = allow
   135  }