1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
12
"github.com/juju/errors"
13
"github.com/juju/loggo"
14
"github.com/juju/utils"
15
charmresource "gopkg.in/juju/charm.v6-unstable/resource"
17
"github.com/juju/juju/resource"
18
"github.com/juju/juju/resource/context/internal"
21
var logger = loggo.GetLogger("juju.resource.context")
23
// HookContextFacade is the name of the API facade for resources in the uniter.
24
const HookContextFacade = "ResourcesHookContext"
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)
33
// Content is the resources portion of a uniter hook context.
37
// dataDir is the path to the directory where all resources are
38
// stored for a unit. It will look something like this:
40
// /var/lib/juju/agents/unit-spam-1/resources
44
// NewContextAPI returns a new Content for the given API client and data dir.
45
func NewContextAPI(apiClient APIClient, dataDir string) *Context {
52
// Flush implements jujuc.Context.
53
func (c *Context) Flush() error {
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.
61
// Note that the downloaded file is checked for correctness.
62
func (c *Context) Download(name string) (string, error) {
64
APIClient: c.apiClient,
68
path, err := internal.ContextDownload(deps)
70
return "", errors.Trace(err)
75
// contextDeps implements all the external dependencies
76
// of ContextDownload().
77
type contextDeps struct {
83
func (deps *contextDeps) NewContextDirectorySpec() internal.ContextDirectorySpec {
84
return internal.NewContextDirectorySpec(deps.dataDir, deps.name, deps)
87
func (deps *contextDeps) OpenResource() (internal.ContextOpenedResource, error) {
88
return internal.OpenResource(deps.name, deps)
91
func (deps *contextDeps) Download(target internal.DownloadTarget, remote internal.ContextOpenedResource) error {
92
return internal.DownloadIndirect(target, remote, deps)
95
func (deps *contextDeps) DownloadDirect(target internal.DownloadTarget, remote internal.ContentSource) error {
96
return internal.Download(target, remote)
99
func (deps *contextDeps) ReplaceDirectory(tgt, src string) error {
100
return internal.ReplaceDirectory(tgt, src, deps)
103
func (deps *contextDeps) NewTempDirSpec() (internal.DownloadTempTarget, error) {
104
spec, err := internal.NewTempDirectorySpec(deps.name, deps)
106
return nil, errors.Trace(err)
108
dir := &internal.ContextDownloadDirectory{
114
func (deps *contextDeps) WriteContent(target io.Writer, content internal.Content) error {
115
return internal.WriteContent(target, content, deps)
118
func (deps contextDeps) CloseAndLog(closer io.Closer, label string) {
119
internal.CloseAndLog(closer, label, logger)
122
func (deps contextDeps) MkdirAll(dirname string) error {
123
return os.MkdirAll(dirname, 0755)
126
func (deps contextDeps) CreateWriter(filename string) (io.WriteCloser, error) {
127
// TODO(ericsnow) chmod 0644?
128
return os.Create(filename)
131
func (deps contextDeps) NewTempDir() (string, error) {
132
return ioutil.TempDir("", "juju-resource-")
135
func (deps contextDeps) RemoveDir(dirname string) error {
136
return os.RemoveAll(dirname)
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)
145
func (deps contextDeps) Copy(target io.Writer, source io.Reader) error {
146
_, err := io.Copy(target, source)
150
func (deps contextDeps) FingerprintMatches(filename string, expected charmresource.Fingerprint) (bool, error) {
151
return FingerprintMatcher{}.FingerprintMatches(filename, expected)
154
func (deps contextDeps) Join(path ...string) string {
155
return filepath.Join(path...)
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)