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 }