github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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  //
    43  // TODO(katco): 2016-08-09: lp:1611427
    44  func GetWithRetry(stor StorageReader, name string, attempt utils.AttemptStrategy) (r io.ReadCloser, err error) {
    45  	for a := attempt.Start(); a.Next(); {
    46  		r, err = stor.Get(name)
    47  		if err == nil || !stor.ShouldRetry(err) {
    48  			break
    49  		}
    50  	}
    51  	return r, err
    52  }
    53  
    54  // List lists the files matching prefix from stor using the stor's default consistency strategy.
    55  func List(stor StorageReader, prefix string) ([]string, error) {
    56  	return ListWithRetry(stor, prefix, stor.DefaultConsistencyStrategy())
    57  }
    58  
    59  // ListWithRetry lists the files matching prefix from stor using the specified attempt strategy.
    60  //
    61  // TODO(katco): 2016-08-09: lp:1611427
    62  func ListWithRetry(stor StorageReader, prefix string, attempt utils.AttemptStrategy) (list []string, err error) {
    63  	for a := attempt.Start(); a.Next(); {
    64  		list, err = stor.List(prefix)
    65  		if err == nil || !stor.ShouldRetry(err) {
    66  			break
    67  		}
    68  	}
    69  	return list, err
    70  }
    71  
    72  // BaseToolsPath is the container where tools tarballs and metadata are found.
    73  var BaseToolsPath = "tools"
    74  
    75  // BaseImagesPath is the container where images metadata is found.
    76  var BaseImagesPath = "images"
    77  
    78  // A storageSimpleStreamsDataSource retrieves data from a StorageReader.
    79  type storageSimpleStreamsDataSource struct {
    80  	description   string
    81  	basePath      string
    82  	storage       StorageReader
    83  	allowRetry    bool
    84  	priority      int
    85  	requireSigned bool
    86  }
    87  
    88  // TestingGetAllowRetry is used in tests which need to see if allowRetry has been
    89  // set on a storageSimpleStreamsDataSource.
    90  func TestingGetAllowRetry(s simplestreams.DataSource) (bool, ok bool) {
    91  	if storageDataSource, ok := s.(*storageSimpleStreamsDataSource); ok {
    92  		return storageDataSource.allowRetry, ok
    93  	}
    94  	return false, false
    95  }
    96  
    97  // NewStorageSimpleStreamsDataSource returns a new datasource reading from the specified storage.
    98  func NewStorageSimpleStreamsDataSource(description string, storage StorageReader, basePath string, priority int, requireSigned bool) simplestreams.DataSource {
    99  	return &storageSimpleStreamsDataSource{description, basePath, storage, false, priority, requireSigned}
   100  }
   101  
   102  func (s *storageSimpleStreamsDataSource) relpath(storagePath string) string {
   103  	relpath := storagePath
   104  	if s.basePath != "" {
   105  		relpath = path.Join(s.basePath, relpath)
   106  	}
   107  	return relpath
   108  }
   109  
   110  // Description is defined in simplestreams.DataSource.
   111  func (s *storageSimpleStreamsDataSource) Description() string {
   112  	return s.description
   113  }
   114  
   115  // Fetch is defined in simplestreams.DataSource.
   116  func (s *storageSimpleStreamsDataSource) Fetch(path string) (io.ReadCloser, string, error) {
   117  	relpath := s.relpath(path)
   118  	dataURL := relpath
   119  	fullURL, err := s.storage.URL(relpath)
   120  	if err == nil {
   121  		dataURL = fullURL
   122  	}
   123  	// TODO(katco): 2016-08-09: lp:1611427
   124  	var attempt utils.AttemptStrategy
   125  	if s.allowRetry {
   126  		attempt = s.storage.DefaultConsistencyStrategy()
   127  	}
   128  	rc, err := GetWithRetry(s.storage, relpath, attempt)
   129  	if err != nil {
   130  		return nil, dataURL, err
   131  	}
   132  	return rc, dataURL, nil
   133  }
   134  
   135  // URL is defined in simplestreams.DataSource.
   136  func (s *storageSimpleStreamsDataSource) URL(path string) (string, error) {
   137  	return s.storage.URL(s.relpath(path))
   138  }
   139  
   140  // PublicSigningKey is defined in simplestreams.DataSource.
   141  func (u *storageSimpleStreamsDataSource) PublicSigningKey() string {
   142  	return ""
   143  }
   144  
   145  // SetAllowRetry is defined in simplestreams.DataSource.
   146  func (s *storageSimpleStreamsDataSource) SetAllowRetry(allow bool) {
   147  	s.allowRetry = allow
   148  }
   149  
   150  // Priority is defined in simplestreams.DataSource.
   151  func (s *storageSimpleStreamsDataSource) Priority() int {
   152  	return s.priority
   153  }
   154  
   155  // RequireSigned is defined in simplestreams.DataSource.
   156  func (s *storageSimpleStreamsDataSource) RequireSigned() bool {
   157  	return s.requireSigned
   158  }