github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/resource/context/context.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package context
     5  
     6  import (
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/juju/errors"
    13  	"github.com/juju/loggo"
    14  	"github.com/juju/utils"
    15  	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
    16  
    17  	"github.com/juju/juju/resource"
    18  	"github.com/juju/juju/resource/context/internal"
    19  )
    20  
    21  var logger = loggo.GetLogger("juju.resource.context")
    22  
    23  // HookContextFacade is the name of the API facade for resources in the uniter.
    24  const HookContextFacade = "ResourcesHookContext"
    25  
    26  // APIClient exposes the uniter API functionality needed for resources.
    27  type APIClient interface {
    28  	// GetResource returns the resource info and content for the given
    29  	// name (and unit-implied application).
    30  	GetResource(resourceName string) (resource.Resource, io.ReadCloser, error)
    31  }
    32  
    33  // Content is the resources portion of a uniter hook context.
    34  type Context struct {
    35  	apiClient APIClient
    36  
    37  	// dataDir is the path to the directory where all resources are
    38  	// stored for a unit. It will look something like this:
    39  	//
    40  	//   /var/lib/juju/agents/unit-spam-1/resources
    41  	dataDir string
    42  }
    43  
    44  // NewContextAPI returns a new Content for the given API client and data dir.
    45  func NewContextAPI(apiClient APIClient, dataDir string) *Context {
    46  	return &Context{
    47  		apiClient: apiClient,
    48  		dataDir:   dataDir,
    49  	}
    50  }
    51  
    52  // Flush implements jujuc.Context.
    53  func (c *Context) Flush() error {
    54  	return nil
    55  }
    56  
    57  // Download downloads the named resource and returns the path
    58  // to which it was downloaded. If the resource does not exist or has
    59  // not been uploaded yet then errors.NotFound is returned.
    60  //
    61  // Note that the downloaded file is checked for correctness.
    62  func (c *Context) Download(name string) (string, error) {
    63  	deps := &contextDeps{
    64  		APIClient: c.apiClient,
    65  		name:      name,
    66  		dataDir:   c.dataDir,
    67  	}
    68  	path, err := internal.ContextDownload(deps)
    69  	if err != nil {
    70  		return "", errors.Trace(err)
    71  	}
    72  	return path, nil
    73  }
    74  
    75  // contextDeps implements all the external dependencies
    76  // of ContextDownload().
    77  type contextDeps struct {
    78  	APIClient
    79  	name    string
    80  	dataDir string
    81  }
    82  
    83  func (deps *contextDeps) NewContextDirectorySpec() internal.ContextDirectorySpec {
    84  	return internal.NewContextDirectorySpec(deps.dataDir, deps.name, deps)
    85  }
    86  
    87  func (deps *contextDeps) OpenResource() (internal.ContextOpenedResource, error) {
    88  	return internal.OpenResource(deps.name, deps)
    89  }
    90  
    91  func (deps *contextDeps) Download(target internal.DownloadTarget, remote internal.ContextOpenedResource) error {
    92  	return internal.DownloadIndirect(target, remote, deps)
    93  }
    94  
    95  func (deps *contextDeps) DownloadDirect(target internal.DownloadTarget, remote internal.ContentSource) error {
    96  	return internal.Download(target, remote)
    97  }
    98  
    99  func (deps *contextDeps) ReplaceDirectory(tgt, src string) error {
   100  	return internal.ReplaceDirectory(tgt, src, deps)
   101  }
   102  
   103  func (deps *contextDeps) NewTempDirSpec() (internal.DownloadTempTarget, error) {
   104  	spec, err := internal.NewTempDirectorySpec(deps.name, deps)
   105  	if err != nil {
   106  		return nil, errors.Trace(err)
   107  	}
   108  	dir := &internal.ContextDownloadDirectory{
   109  		spec,
   110  	}
   111  	return dir, nil
   112  }
   113  
   114  func (deps *contextDeps) WriteContent(target io.Writer, content internal.Content) error {
   115  	return internal.WriteContent(target, content, deps)
   116  }
   117  
   118  func (deps contextDeps) CloseAndLog(closer io.Closer, label string) {
   119  	internal.CloseAndLog(closer, label, logger)
   120  }
   121  
   122  func (deps contextDeps) MkdirAll(dirname string) error {
   123  	return os.MkdirAll(dirname, 0755)
   124  }
   125  
   126  func (deps contextDeps) CreateWriter(filename string) (io.WriteCloser, error) {
   127  	// TODO(ericsnow) chmod 0644?
   128  	return os.Create(filename)
   129  }
   130  
   131  func (deps contextDeps) NewTempDir() (string, error) {
   132  	return ioutil.TempDir("", "juju-resource-")
   133  }
   134  
   135  func (deps contextDeps) RemoveDir(dirname string) error {
   136  	return os.RemoveAll(dirname)
   137  }
   138  
   139  func (deps contextDeps) Move(target, source string) error {
   140  	// Note that we follow the io.Copy() argument arder here
   141  	// (os.Rename does not).
   142  	return os.Rename(source, target)
   143  }
   144  
   145  func (deps contextDeps) Copy(target io.Writer, source io.Reader) error {
   146  	_, err := io.Copy(target, source)
   147  	return err
   148  }
   149  
   150  func (deps contextDeps) FingerprintMatches(filename string, expected charmresource.Fingerprint) (bool, error) {
   151  	return FingerprintMatcher{}.FingerprintMatches(filename, expected)
   152  }
   153  
   154  func (deps contextDeps) Join(path ...string) string {
   155  	return filepath.Join(path...)
   156  }
   157  
   158  func (deps contextDeps) NewChecker(content internal.Content) internal.ContentChecker {
   159  	var sizer utils.SizeTracker
   160  	checksumWriter := charmresource.NewFingerprintHash()
   161  	return internal.NewContentChecker(content, &sizer, checksumWriter)
   162  }