github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/resource/context/internal/resource.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package internal 5 6 // TODO(ericsnow) Move this file elsewhere? 7 // (e.g. top-level resource pkg, charm/resource) 8 9 import ( 10 "bytes" 11 "encoding/json" 12 "io" 13 "io/ioutil" 14 15 "github.com/juju/errors" 16 "github.com/juju/juju/core/resources" 17 "gopkg.in/httprequest.v1" 18 charmresource "gopkg.in/juju/charm.v6/resource" 19 "gopkg.in/yaml.v2" 20 21 "github.com/juju/juju/resource" 22 ) 23 24 // OpenedResourceClient exposes the API functionality needed by OpenResource. 25 type OpenedResourceClient interface { 26 // GetResource returns the resource info and content for the given 27 // name (and unit-implied application). 28 GetResource(resourceName string) (resource.Resource, io.ReadCloser, error) 29 } 30 31 // OpenedResource wraps the resource info and reader returned 32 // from the API. 33 type OpenedResource struct { 34 resource.Resource 35 io.ReadCloser 36 } 37 38 // OpenResource opens the identified resource using the provided client. 39 func OpenResource(name string, client OpenedResourceClient) (*OpenedResource, error) { 40 info, reader, err := client.GetResource(name) 41 if err != nil { 42 return nil, errors.Trace(err) 43 } 44 if info.Type == charmresource.TypeContainerImage { 45 info.Path = "content.yaml" 46 // Image data is stored as json but we need to convert to YAMl 47 // as that's what the charm expects. 48 data, err := ioutil.ReadAll(reader) 49 if err != nil { 50 return nil, errors.Trace(err) 51 } 52 if err := reader.Close(); err != nil { 53 return nil, errors.Trace(err) 54 } 55 var yamlBody resources.DockerImageDetails 56 err = json.Unmarshal(data, &yamlBody) 57 if err != nil { 58 return nil, errors.Trace(err) 59 } 60 yamlOut, err := yaml.Marshal(yamlBody) 61 if err != nil { 62 return nil, errors.Trace(err) 63 } 64 reader = httprequest.BytesReaderCloser{bytes.NewReader(yamlOut)} 65 info.Size = int64(len(yamlOut)) 66 } 67 or := &OpenedResource{ 68 Resource: info, 69 ReadCloser: reader, 70 } 71 return or, nil 72 } 73 74 // Content returns the "content" for the opened resource. 75 func (or OpenedResource) Content() Content { 76 return Content{ 77 Data: or.ReadCloser, 78 Size: or.Size, 79 Fingerprint: or.Fingerprint, 80 } 81 } 82 83 // Info returns the info for the opened resource. 84 func (or OpenedResource) Info() resource.Resource { 85 return or.Resource 86 }