vendor: Updating github.com/gophercloud/gophercloud

Add github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects and
github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts
This commit is contained in:
Gavin Williams 2016-11-01 13:24:00 +00:00
parent ac07430124
commit 2bf054d0d6
10 changed files with 1236 additions and 0 deletions

View File

@ -0,0 +1,8 @@
// Package accounts contains functionality for working with Object Storage
// account resources. An account is the top-level resource the object storage
// hierarchy: containers belong to accounts, objects belong to containers.
//
// Another way of thinking of an account is like a namespace for all your
// resources. It is synonymous with a project or tenant in other OpenStack
// services.
package accounts

View File

@ -0,0 +1,100 @@
package accounts
import "github.com/gophercloud/gophercloud"
// GetOptsBuilder allows extensions to add additional headers to the Get
// request.
type GetOptsBuilder interface {
ToAccountGetMap() (map[string]string, error)
}
// GetOpts is a structure that contains parameters for getting an account's
// metadata.
type GetOpts struct {
Newest bool `h:"X-Newest"`
}
// ToAccountGetMap formats a GetOpts into a map[string]string of headers.
func (opts GetOpts) ToAccountGetMap() (map[string]string, error) {
return gophercloud.BuildHeaders(opts)
}
// Get is a function that retrieves an account's metadata. To extract just the
// custom metadata, call the ExtractMetadata method on the GetResult. To extract
// all the headers that are returned (including the metadata), call the
// ExtractHeader method on the GetResult.
func Get(c *gophercloud.ServiceClient, opts GetOptsBuilder) (r GetResult) {
h := make(map[string]string)
if opts != nil {
headers, err := opts.ToAccountGetMap()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
}
resp, err := c.Request("HEAD", getURL(c), &gophercloud.RequestOpts{
MoreHeaders: h,
OkCodes: []int{204},
})
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}
// UpdateOptsBuilder allows extensions to add additional headers to the Update
// request.
type UpdateOptsBuilder interface {
ToAccountUpdateMap() (map[string]string, error)
}
// UpdateOpts is a structure that contains parameters for updating, creating, or
// deleting an account's metadata.
type UpdateOpts struct {
Metadata map[string]string
ContentType string `h:"Content-Type"`
DetectContentType bool `h:"X-Detect-Content-Type"`
TempURLKey string `h:"X-Account-Meta-Temp-URL-Key"`
TempURLKey2 string `h:"X-Account-Meta-Temp-URL-Key-2"`
}
// ToAccountUpdateMap formats an UpdateOpts into a map[string]string of headers.
func (opts UpdateOpts) ToAccountUpdateMap() (map[string]string, error) {
headers, err := gophercloud.BuildHeaders(opts)
if err != nil {
return nil, err
}
for k, v := range opts.Metadata {
headers["X-Account-Meta-"+k] = v
}
return headers, err
}
// Update is a function that creates, updates, or deletes an account's metadata.
// To extract the headers returned, call the Extract method on the UpdateResult.
func Update(c *gophercloud.ServiceClient, opts UpdateOptsBuilder) (r UpdateResult) {
h := make(map[string]string)
if opts != nil {
headers, err := opts.ToAccountUpdateMap()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
}
resp, err := c.Request("POST", updateURL(c), &gophercloud.RequestOpts{
MoreHeaders: h,
OkCodes: []int{201, 202, 204},
})
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}

View File

@ -0,0 +1,160 @@
package accounts
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/gophercloud/gophercloud"
)
// UpdateResult is returned from a call to the Update function.
type UpdateResult struct {
gophercloud.HeaderResult
}
// UpdateHeader represents the headers returned in the response from an Update request.
type UpdateHeader struct {
ContentLength int64 `json:"-"`
ContentType string `json:"Content-Type"`
TransID string `json:"X-Trans-Id"`
Date gophercloud.JSONRFC1123 `json:"Date"`
}
func (h *UpdateHeader) UnmarshalJSON(b []byte) error {
type tmp UpdateHeader
var updateHeader *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &updateHeader)
if err != nil {
return err
}
*h = UpdateHeader(updateHeader.tmp)
switch updateHeader.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(updateHeader.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// Extract will return a struct of headers returned from a call to Get. To obtain
// a map of headers, call the ExtractHeader method on the GetResult.
func (ur UpdateResult) Extract() (*UpdateHeader, error) {
var uh *UpdateHeader
err := ur.ExtractInto(&uh)
return uh, err
}
// GetHeader represents the headers returned in the response from a Get request.
type GetHeader struct {
BytesUsed int64 `json:"-"`
ContainerCount int64 `json:"-"`
ContentLength int64 `json:"-"`
ObjectCount int64 `json:"-"`
ContentType string `json:"Content-Type"`
TransID string `json:"X-Trans-Id"`
TempURLKey string `json:"X-Account-Meta-Temp-URL-Key"`
TempURLKey2 string `json:"X-Account-Meta-Temp-URL-Key-2"`
Date gophercloud.JSONRFC1123 `json:"Date"`
}
func (h *GetHeader) UnmarshalJSON(b []byte) error {
type tmp GetHeader
var getHeader *struct {
tmp
BytesUsed string `json:"X-Account-Bytes-Used"`
ContentLength string `json:"Content-Length"`
ContainerCount string `json:"X-Account-Container-Count"`
ObjectCount string `json:"X-Account-Object-Count"`
}
err := json.Unmarshal(b, &getHeader)
if err != nil {
return err
}
*h = GetHeader(getHeader.tmp)
switch getHeader.BytesUsed {
case "":
h.BytesUsed = 0
default:
h.BytesUsed, err = strconv.ParseInt(getHeader.BytesUsed, 10, 64)
if err != nil {
return err
}
}
fmt.Println("getHeader: ", getHeader.ContentLength)
switch getHeader.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(getHeader.ContentLength, 10, 64)
if err != nil {
return err
}
}
switch getHeader.ObjectCount {
case "":
h.ObjectCount = 0
default:
h.ObjectCount, err = strconv.ParseInt(getHeader.ObjectCount, 10, 64)
if err != nil {
return err
}
}
switch getHeader.ContainerCount {
case "":
h.ContainerCount = 0
default:
h.ContainerCount, err = strconv.ParseInt(getHeader.ContainerCount, 10, 64)
if err != nil {
return err
}
}
return nil
}
// GetResult is returned from a call to the Get function.
type GetResult struct {
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Get. To obtain
// a map of headers, call the ExtractHeader method on the GetResult.
func (r GetResult) Extract() (*GetHeader, error) {
var s *GetHeader
err := r.ExtractInto(&s)
return s, err
}
// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
// and returns the custom metatdata associated with the account.
func (r GetResult) ExtractMetadata() (map[string]string, error) {
if r.Err != nil {
return nil, r.Err
}
metadata := make(map[string]string)
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Account-Meta-") {
key := strings.TrimPrefix(k, "X-Account-Meta-")
metadata[key] = v[0]
}
}
return metadata, nil
}

View File

@ -0,0 +1,11 @@
package accounts
import "github.com/gophercloud/gophercloud"
func getURL(c *gophercloud.ServiceClient) string {
return c.Endpoint
}
func updateURL(c *gophercloud.ServiceClient) string {
return getURL(c)
}

View File

@ -0,0 +1,5 @@
// Package objects contains functionality for working with Object Storage
// object resources. An object is a resource that represents and contains data
// - such as documents, images, and so on. You can also store custom metadata
// with an object.
package objects

View File

@ -0,0 +1,13 @@
package objects
import "github.com/gophercloud/gophercloud"
// ErrWrongChecksum is the error when the checksum generated for an object
// doesn't match the ETAG header.
type ErrWrongChecksum struct {
gophercloud.BaseError
}
func (e ErrWrongChecksum) Error() string {
return "Local checksum does not match API ETag header"
}

View File

@ -0,0 +1,453 @@
package objects
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"fmt"
"io"
"strings"
"time"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts"
"github.com/gophercloud/gophercloud/pagination"
)
// ListOptsBuilder allows extensions to add additional parameters to the List
// request.
type ListOptsBuilder interface {
ToObjectListParams() (bool, string, error)
}
// ListOpts is a structure that holds parameters for listing objects.
type ListOpts struct {
// Full is a true/false value that represents the amount of object information
// returned. If Full is set to true, then the content-type, number of bytes, hash
// date last modified, and name are returned. If set to false or not set, then
// only the object names are returned.
Full bool
Limit int `q:"limit"`
Marker string `q:"marker"`
EndMarker string `q:"end_marker"`
Format string `q:"format"`
Prefix string `q:"prefix"`
Delimiter string `q:"delimiter"`
Path string `q:"path"`
}
// ToObjectListParams formats a ListOpts into a query string and boolean
// representing whether to list complete information for each object.
func (opts ListOpts) ToObjectListParams() (bool, string, error) {
q, err := gophercloud.BuildQueryString(opts)
return opts.Full, q.String(), err
}
// List is a function that retrieves all objects in a container. It also returns the details
// for the container. To extract only the object information or names, pass the ListResult
// response to the ExtractInfo or ExtractNames function, respectively.
func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager {
headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"}
url := listURL(c, containerName)
if opts != nil {
full, query, err := opts.ToObjectListParams()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
if full {
headers = map[string]string{"Accept": "application/json", "Content-Type": "application/json"}
}
}
pager := pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
p := ObjectPage{pagination.MarkerPageBase{PageResult: r}}
p.MarkerPageBase.Owner = p
return p
})
pager.Headers = headers
return pager
}
// DownloadOptsBuilder allows extensions to add additional parameters to the
// Download request.
type DownloadOptsBuilder interface {
ToObjectDownloadParams() (map[string]string, string, error)
}
// DownloadOpts is a structure that holds parameters for downloading an object.
type DownloadOpts struct {
IfMatch string `h:"If-Match"`
IfModifiedSince time.Time `h:"If-Modified-Since"`
IfNoneMatch string `h:"If-None-Match"`
IfUnmodifiedSince time.Time `h:"If-Unmodified-Since"`
Range string `h:"Range"`
Expires string `q:"expires"`
MultipartManifest string `q:"multipart-manifest"`
Signature string `q:"signature"`
}
// ToObjectDownloadParams formats a DownloadOpts into a query string and map of
// headers.
func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, error) {
q, err := gophercloud.BuildQueryString(opts)
if err != nil {
return nil, "", err
}
h, err := gophercloud.BuildHeaders(opts)
if err != nil {
return nil, q.String(), err
}
return h, q.String(), nil
}
// Download is a function that retrieves the content and metadata for an object.
// To extract just the content, pass the DownloadResult response to the
// ExtractContent function.
func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) (r DownloadResult) {
url := downloadURL(c, containerName, objectName)
h := make(map[string]string)
if opts != nil {
headers, query, err := opts.ToObjectDownloadParams()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
url += query
}
resp, err := c.Get(url, nil, &gophercloud.RequestOpts{
MoreHeaders: h,
OkCodes: []int{200, 304},
})
if resp != nil {
r.Header = resp.Header
r.Body = resp.Body
}
r.Err = err
return
}
// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToObjectCreateParams() (io.Reader, map[string]string, string, error)
}
// CreateOpts is a structure that holds parameters for creating an object.
type CreateOpts struct {
Content io.Reader
Metadata map[string]string
CacheControl string `h:"Cache-Control"`
ContentDisposition string `h:"Content-Disposition"`
ContentEncoding string `h:"Content-Encoding"`
ContentLength int64 `h:"Content-Length"`
ContentType string `h:"Content-Type"`
CopyFrom string `h:"X-Copy-From"`
DeleteAfter int `h:"X-Delete-After"`
DeleteAt int `h:"X-Delete-At"`
DetectContentType string `h:"X-Detect-Content-Type"`
ETag string `h:"ETag"`
IfNoneMatch string `h:"If-None-Match"`
ObjectManifest string `h:"X-Object-Manifest"`
TransferEncoding string `h:"Transfer-Encoding"`
Expires string `q:"expires"`
MultipartManifest string `q:"multipart-manifest"`
Signature string `q:"signature"`
}
// ToObjectCreateParams formats a CreateOpts into a query string and map of
// headers.
func (opts CreateOpts) ToObjectCreateParams() (io.Reader, map[string]string, string, error) {
q, err := gophercloud.BuildQueryString(opts)
if err != nil {
return nil, nil, "", err
}
h, err := gophercloud.BuildHeaders(opts)
if err != nil {
return nil, nil, "", err
}
for k, v := range opts.Metadata {
h["X-Object-Meta-"+k] = v
}
hash := md5.New()
buf := bytes.NewBuffer([]byte{})
_, err = io.Copy(io.MultiWriter(hash, buf), opts.Content)
if err != nil {
return nil, nil, "", err
}
localChecksum := fmt.Sprintf("%x", hash.Sum(nil))
h["ETag"] = localChecksum
return buf, h, q.String(), nil
}
// Create is a function that creates a new object or replaces an existing object. If the returned response's ETag
// header fails to match the local checksum, the failed request will automatically be retried up to a maximum of 3 times.
func Create(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateOptsBuilder) (r CreateResult) {
url := createURL(c, containerName, objectName)
h := make(map[string]string)
var b io.Reader
if opts != nil {
tmpB, headers, query, err := opts.ToObjectCreateParams()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
url += query
b = tmpB
}
resp, err := c.Put(url, nil, nil, &gophercloud.RequestOpts{
RawBody: b,
MoreHeaders: h,
})
r.Err = err
if resp != nil {
r.Header = resp.Header
}
return
}
// CopyOptsBuilder allows extensions to add additional parameters to the
// Copy request.
type CopyOptsBuilder interface {
ToObjectCopyMap() (map[string]string, error)
}
// CopyOpts is a structure that holds parameters for copying one object to
// another.
type CopyOpts struct {
Metadata map[string]string
ContentDisposition string `h:"Content-Disposition"`
ContentEncoding string `h:"Content-Encoding"`
ContentType string `h:"Content-Type"`
Destination string `h:"Destination" required:"true"`
}
// ToObjectCopyMap formats a CopyOpts into a map of headers.
func (opts CopyOpts) ToObjectCopyMap() (map[string]string, error) {
h, err := gophercloud.BuildHeaders(opts)
if err != nil {
return nil, err
}
for k, v := range opts.Metadata {
h["X-Object-Meta-"+k] = v
}
return h, nil
}
// Copy is a function that copies one object to another.
func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts CopyOptsBuilder) (r CopyResult) {
h := make(map[string]string)
headers, err := opts.ToObjectCopyMap()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
url := copyURL(c, containerName, objectName)
resp, err := c.Request("COPY", url, &gophercloud.RequestOpts{
MoreHeaders: h,
OkCodes: []int{201},
})
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}
// DeleteOptsBuilder allows extensions to add additional parameters to the
// Delete request.
type DeleteOptsBuilder interface {
ToObjectDeleteQuery() (string, error)
}
// DeleteOpts is a structure that holds parameters for deleting an object.
type DeleteOpts struct {
MultipartManifest string `q:"multipart-manifest"`
}
// ToObjectDeleteQuery formats a DeleteOpts into a query string.
func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
return q.String(), err
}
// Delete is a function that deletes an object.
func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) (r DeleteResult) {
url := deleteURL(c, containerName, objectName)
if opts != nil {
query, err := opts.ToObjectDeleteQuery()
if err != nil {
r.Err = err
return
}
url += query
}
resp, err := c.Delete(url, nil)
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}
// GetOptsBuilder allows extensions to add additional parameters to the
// Get request.
type GetOptsBuilder interface {
ToObjectGetQuery() (string, error)
}
// GetOpts is a structure that holds parameters for getting an object's metadata.
type GetOpts struct {
Expires string `q:"expires"`
Signature string `q:"signature"`
}
// ToObjectGetQuery formats a GetOpts into a query string.
func (opts GetOpts) ToObjectGetQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
return q.String(), err
}
// Get is a function that retrieves the metadata of an object. To extract just the custom
// metadata, pass the GetResult response to the ExtractMetadata function.
func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) (r GetResult) {
url := getURL(c, containerName, objectName)
if opts != nil {
query, err := opts.ToObjectGetQuery()
if err != nil {
r.Err = err
return
}
url += query
}
resp, err := c.Request("HEAD", url, &gophercloud.RequestOpts{
OkCodes: []int{200, 204},
})
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}
// UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface {
ToObjectUpdateMap() (map[string]string, error)
}
// UpdateOpts is a structure that holds parameters for updating, creating, or deleting an
// object's metadata.
type UpdateOpts struct {
Metadata map[string]string
ContentDisposition string `h:"Content-Disposition"`
ContentEncoding string `h:"Content-Encoding"`
ContentType string `h:"Content-Type"`
DeleteAfter int `h:"X-Delete-After"`
DeleteAt int `h:"X-Delete-At"`
DetectContentType bool `h:"X-Detect-Content-Type"`
}
// ToObjectUpdateMap formats a UpdateOpts into a map of headers.
func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
h, err := gophercloud.BuildHeaders(opts)
if err != nil {
return nil, err
}
for k, v := range opts.Metadata {
h["X-Object-Meta-"+k] = v
}
return h, nil
}
// Update is a function that creates, updates, or deletes an object's metadata.
func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts UpdateOptsBuilder) (r UpdateResult) {
h := make(map[string]string)
if opts != nil {
headers, err := opts.ToObjectUpdateMap()
if err != nil {
r.Err = err
return
}
for k, v := range headers {
h[k] = v
}
}
url := updateURL(c, containerName, objectName)
resp, err := c.Post(url, nil, nil, &gophercloud.RequestOpts{
MoreHeaders: h,
})
if resp != nil {
r.Header = resp.Header
}
r.Err = err
return
}
// HTTPMethod represents an HTTP method string (e.g. "GET").
type HTTPMethod string
var (
// GET represents an HTTP "GET" method.
GET HTTPMethod = "GET"
// POST represents an HTTP "POST" method.
POST HTTPMethod = "POST"
)
// CreateTempURLOpts are options for creating a temporary URL for an object.
type CreateTempURLOpts struct {
// (REQUIRED) Method is the HTTP method to allow for users of the temp URL. Valid values
// are "GET" and "POST".
Method HTTPMethod
// (REQUIRED) TTL is the number of seconds the temp URL should be active.
TTL int
// (Optional) Split is the string on which to split the object URL. Since only
// the object path is used in the hash, the object URL needs to be parsed. If
// empty, the default OpenStack URL split point will be used ("/v1/").
Split string
}
// CreateTempURL is a function for creating a temporary URL for an object. It
// allows users to have "GET" or "POST" access to a particular tenant's object
// for a limited amount of time.
func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateTempURLOpts) (string, error) {
if opts.Split == "" {
opts.Split = "/v1/"
}
duration := time.Duration(opts.TTL) * time.Second
expiry := time.Now().Add(duration).Unix()
getHeader, err := accounts.Get(c, nil).Extract()
if err != nil {
return "", err
}
secretKey := []byte(getHeader.TempURLKey)
url := getURL(c, containerName, objectName)
splitPath := strings.Split(url, opts.Split)
baseURL, objectPath := splitPath[0], splitPath[1]
objectPath = opts.Split + objectPath
body := fmt.Sprintf("%s\n%d\n%s", opts.Method, expiry, objectPath)
hash := hmac.New(sha1.New, secretKey)
hash.Write([]byte(body))
hexsum := fmt.Sprintf("%x", hash.Sum(nil))
return fmt.Sprintf("%s%s?temp_url_sig=%s&temp_url_expires=%d", baseURL, objectPath, hexsum, expiry), nil
}

View File

@ -0,0 +1,441 @@
package objects
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strconv"
"strings"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
)
// Object is a structure that holds information related to a storage object.
type Object struct {
// Bytes is the total number of bytes that comprise the object.
Bytes int64 `json:"bytes"`
// ContentType is the content type of the object.
ContentType string `json:"content_type"`
// Hash represents the MD5 checksum value of the object's content.
Hash string `json:"hash"`
// LastModified is the RFC3339Milli time the object was last modified, represented
// as a string. For any given object (obj), this value may be parsed to a time.Time:
// lastModified, err := time.Parse(gophercloud.RFC3339Milli, obj.LastModified)
LastModified gophercloud.JSONRFC3339MilliNoZ `json:"last_modified"`
// Name is the unique name for the object.
Name string `json:"name"`
}
// ObjectPage is a single page of objects that is returned from a call to the
// List function.
type ObjectPage struct {
pagination.MarkerPageBase
}
// IsEmpty returns true if a ListResult contains no object names.
func (r ObjectPage) IsEmpty() (bool, error) {
names, err := ExtractNames(r)
return len(names) == 0, err
}
// LastMarker returns the last object name in a ListResult.
func (r ObjectPage) LastMarker() (string, error) {
names, err := ExtractNames(r)
if err != nil {
return "", err
}
if len(names) == 0 {
return "", nil
}
return names[len(names)-1], nil
}
// ExtractInfo is a function that takes a page of objects and returns their full information.
func ExtractInfo(r pagination.Page) ([]Object, error) {
var s []Object
err := (r.(ObjectPage)).ExtractInto(&s)
return s, err
}
// ExtractNames is a function that takes a page of objects and returns only their names.
func ExtractNames(r pagination.Page) ([]string, error) {
casted := r.(ObjectPage)
ct := casted.Header.Get("Content-Type")
switch {
case strings.HasPrefix(ct, "application/json"):
parsed, err := ExtractInfo(r)
if err != nil {
return nil, err
}
names := make([]string, 0, len(parsed))
for _, object := range parsed {
names = append(names, object.Name)
}
return names, nil
case strings.HasPrefix(ct, "text/plain"):
names := make([]string, 0, 50)
body := string(r.(ObjectPage).Body.([]uint8))
for _, name := range strings.Split(body, "\n") {
if len(name) > 0 {
names = append(names, name)
}
}
return names, nil
case strings.HasPrefix(ct, "text/html"):
return []string{}, nil
default:
return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
}
}
// DownloadHeader represents the headers returned in the response from a Download request.
type DownloadHeader struct {
AcceptRanges string `json:"Accept-Ranges"`
ContentDisposition string `json:"Content-Disposition"`
ContentEncoding string `json:"Content-Encoding"`
ContentLength int64 `json:"-"`
ContentType string `json:"Content-Type"`
Date gophercloud.JSONRFC1123 `json:"Date"`
DeleteAt gophercloud.JSONUnix `json:"X-Delete-At"`
ETag string `json:"Etag"`
LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
ObjectManifest string `json:"X-Object-Manifest"`
StaticLargeObject bool `json:"X-Static-Large-Object"`
TransID string `json:"X-Trans-Id"`
}
func (h *DownloadHeader) UnmarshalJSON(b []byte) error {
type tmp DownloadHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = DownloadHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// DownloadResult is a *http.Response that is returned from a call to the Download function.
type DownloadResult struct {
gophercloud.HeaderResult
Body io.ReadCloser
}
// Extract will return a struct of headers returned from a call to Download. To obtain
// a map of headers, call the ExtractHeader method on the DownloadResult.
func (r DownloadResult) Extract() (*DownloadHeader, error) {
var s *DownloadHeader
err := r.ExtractInto(&s)
return s, err
}
// ExtractContent is a function that takes a DownloadResult's io.Reader body
// and reads all available data into a slice of bytes. Please be aware that due
// the nature of io.Reader is forward-only - meaning that it can only be read
// once and not rewound. You can recreate a reader from the output of this
// function by using bytes.NewReader(downloadBytes)
func (r *DownloadResult) ExtractContent() ([]byte, error) {
if r.Err != nil {
return nil, r.Err
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
r.Body.Close()
return body, nil
}
// GetHeader represents the headers returned in the response from a Get request.
type GetHeader struct {
ContentDisposition string `json:"Content-Disposition"`
ContentEncoding string `json:"Content-Encoding"`
ContentLength int64 `json:"Content-Length"`
ContentType string `json:"Content-Type"`
Date gophercloud.JSONRFC1123 `json:"Date"`
DeleteAt gophercloud.JSONUnix `json:"X-Delete-At"`
ETag string `json:"Etag"`
LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
ObjectManifest string `json:"X-Object-Manifest"`
StaticLargeObject bool `json:"X-Static-Large-Object"`
TransID string `json:"X-Trans-Id"`
}
func (h *GetHeader) UnmarshalJSON(b []byte) error {
type tmp GetHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = GetHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// GetResult is a *http.Response that is returned from a call to the Get function.
type GetResult struct {
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Get. To obtain
// a map of headers, call the ExtractHeader method on the GetResult.
func (r GetResult) Extract() (*GetHeader, error) {
var s *GetHeader
err := r.ExtractInto(&s)
return s, err
}
// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
// and returns the custom metadata associated with the object.
func (r GetResult) ExtractMetadata() (map[string]string, error) {
if r.Err != nil {
return nil, r.Err
}
metadata := make(map[string]string)
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Object-Meta-") {
key := strings.TrimPrefix(k, "X-Object-Meta-")
metadata[key] = v[0]
}
}
return metadata, nil
}
// CreateHeader represents the headers returned in the response from a Create request.
type CreateHeader struct {
ContentLength int64 `json:"Content-Length"`
ContentType string `json:"Content-Type"`
Date gophercloud.JSONRFC1123 `json:"Date"`
ETag string `json:"Etag"`
LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
TransID string `json:"X-Trans-Id"`
}
func (h *CreateHeader) UnmarshalJSON(b []byte) error {
type tmp CreateHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = CreateHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// CreateResult represents the result of a create operation.
type CreateResult struct {
checksum string
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Create. To obtain
// a map of headers, call the ExtractHeader method on the CreateResult.
func (r CreateResult) Extract() (*CreateHeader, error) {
//if r.Header.Get("ETag") != fmt.Sprintf("%x", localChecksum) {
// return nil, ErrWrongChecksum{}
//}
var s *CreateHeader
err := r.ExtractInto(&s)
return s, err
}
// UpdateHeader represents the headers returned in the response from a Update request.
type UpdateHeader struct {
ContentLength int64 `json:"Content-Length"`
ContentType string `json:"Content-Type"`
Date gophercloud.JSONRFC1123 `json:"Date"`
TransID string `json:"X-Trans-Id"`
}
func (h *UpdateHeader) UnmarshalJSON(b []byte) error {
type tmp UpdateHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = UpdateHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// UpdateResult represents the result of an update operation.
type UpdateResult struct {
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Update. To obtain
// a map of headers, call the ExtractHeader method on the UpdateResult.
func (r UpdateResult) Extract() (*UpdateHeader, error) {
var s *UpdateHeader
err := r.ExtractInto(&s)
return s, err
}
// DeleteHeader represents the headers returned in the response from a Delete request.
type DeleteHeader struct {
ContentLength int64 `json:"Content-Length"`
ContentType string `json:"Content-Type"`
Date gophercloud.JSONRFC1123 `json:"Date"`
TransID string `json:"X-Trans-Id"`
}
func (h *DeleteHeader) UnmarshalJSON(b []byte) error {
type tmp DeleteHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = DeleteHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// DeleteResult represents the result of a delete operation.
type DeleteResult struct {
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Delete. To obtain
// a map of headers, call the ExtractHeader method on the DeleteResult.
func (r DeleteResult) Extract() (*DeleteHeader, error) {
var s *DeleteHeader
err := r.ExtractInto(&s)
return s, err
}
// CopyHeader represents the headers returned in the response from a Copy request.
type CopyHeader struct {
ContentLength int64 `json:"Content-Length"`
ContentType string `json:"Content-Type"`
CopiedFrom string `json:"X-Copied-From"`
CopiedFromLastModified gophercloud.JSONRFC1123 `json:"X-Copied-From-Last-Modified"`
Date gophercloud.JSONRFC1123 `json:"Date"`
ETag string `json:"Etag"`
LastModified gophercloud.JSONRFC1123 `json:"Last-Modified"`
TransID string `json:"X-Trans-Id"`
}
func (h *CopyHeader) UnmarshalJSON(b []byte) error {
type tmp CopyHeader
var hTmp *struct {
tmp
ContentLength string `json:"Content-Length"`
}
err := json.Unmarshal(b, &hTmp)
if err != nil {
return err
}
*h = CopyHeader(hTmp.tmp)
switch hTmp.ContentLength {
case "":
h.ContentLength = 0
default:
h.ContentLength, err = strconv.ParseInt(hTmp.ContentLength, 10, 64)
if err != nil {
return err
}
}
return nil
}
// CopyResult represents the result of a copy operation.
type CopyResult struct {
gophercloud.HeaderResult
}
// Extract will return a struct of headers returned from a call to Copy. To obtain
// a map of headers, call the ExtractHeader method on the CopyResult.
func (r CopyResult) Extract() (*CopyHeader, error) {
var s *CopyHeader
err := r.ExtractInto(&s)
return s, err
}

View File

@ -0,0 +1,33 @@
package objects
import (
"github.com/gophercloud/gophercloud"
)
func listURL(c *gophercloud.ServiceClient, container string) string {
return c.ServiceURL(container)
}
func copyURL(c *gophercloud.ServiceClient, container, object string) string {
return c.ServiceURL(container, object)
}
func createURL(c *gophercloud.ServiceClient, container, object string) string {
return copyURL(c, container, object)
}
func getURL(c *gophercloud.ServiceClient, container, object string) string {
return copyURL(c, container, object)
}
func deleteURL(c *gophercloud.ServiceClient, container, object string) string {
return copyURL(c, container, object)
}
func downloadURL(c *gophercloud.ServiceClient, container, object string) string {
return copyURL(c, container, object)
}
func updateURL(c *gophercloud.ServiceClient, container, object string) string {
return copyURL(c, container, object)
}

12
vendor/vendor.json vendored
View File

@ -1183,12 +1183,24 @@
"revision": "e3d6384a3714b335d075862e6eb0a681180643df", "revision": "e3d6384a3714b335d075862e6eb0a681180643df",
"revisionTime": "2016-10-25T18:03:21Z" "revisionTime": "2016-10-25T18:03:21Z"
}, },
{
"checksumSHA1": "yIerdfSMJRUnjh2EZikMhWcgwlY=",
"path": "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/accounts",
"revision": "45720eeefeeeba03b2d7da500297ec68eeee51af",
"revisionTime": "2016-10-31T15:28:56Z"
},
{ {
"checksumSHA1": "5XMyCSYDLmv/b54K3HNNNCJdnBk=", "checksumSHA1": "5XMyCSYDLmv/b54K3HNNNCJdnBk=",
"path": "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers", "path": "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers",
"revision": "e3d6384a3714b335d075862e6eb0a681180643df", "revision": "e3d6384a3714b335d075862e6eb0a681180643df",
"revisionTime": "2016-10-25T18:03:21Z" "revisionTime": "2016-10-25T18:03:21Z"
}, },
{
"checksumSHA1": "CRiIA3oRRlKRDF2ZYnZT8rTlJBU=",
"path": "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects",
"revision": "45720eeefeeeba03b2d7da500297ec68eeee51af",
"revisionTime": "2016-10-31T15:28:56Z"
},
{ {
"checksumSHA1": "TDOZnaS0TO0NirpxV1QwPerAQTY=", "checksumSHA1": "TDOZnaS0TO0NirpxV1QwPerAQTY=",
"path": "github.com/gophercloud/gophercloud/openstack/utils", "path": "github.com/gophercloud/gophercloud/openstack/utils",