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