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  }