schwift: github.com/majewsky/schwift Index | Files | Directories

package schwift

import "github.com/majewsky/schwift"

Package schwift is a client library for OpenStack Swift (https://github.com/openstack/swift, https://openstack.org).

Authentication with Gophercloud

Schwift does not implement authentication (neither Keystone nor Swift v1), but can be plugged into any library that does. The most common choice is Gophercloud (https://github.com/gophercloud/gophercloud).

When using Gophercloud, you usually start by obtaining a gophercloud.ServiceClient for Swift like so:

import (
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/utils/openstack/clientconfig"
)

//option 1: build a gophercloud.AuthOptions instance yourself
provider, err := openstack.AuthenticatedClient(authOptions)
client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{})

//option 2: have Gophercloud read the standard OS_* environment variables
provider, err := clientConfig.AuthenticatedClient(nil)
client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{})

//option 3: if you're using Swift's builtin authentication instead of Keystone
provider, err := openstack.NewClient("http://swift.example.com:8080")
client, err := swauth.NewObjectStorageV1(provider, swauth.AuthOpts {
	User: "project:user",
	Key:  "password",
})

Then, in all these cases, you use gopherschwift to convert the gophercloud.ServiceClient into a schwift.Account instance, from which point you have access to all of schwift's API:

import "github.com/majewsky/schwift/gopherschwift"

account, err := gopherschwift.Wrap(client)

Authentication with a different OpenStack library

If you use a different Go library to handle Keystone/Swift authentication, take the client object that it provides and wrap it into something that implements the schwift.Backend interface. Then use schwift.InitializeAccount() to obtain a schwift.Account.

Caching

When a GET or HEAD request is sent by an Account, Container or Object instance, the headers associated with that thing will be stored in that instance and not retrieved again.

obj := account.Container("foo").Object("bar")

hdr, err := obj.Headers() //sends HTTP request "HEAD <storage-url>/foo/bar"
...
hdr, err = obj.Headers()  //returns cached values immediately

If this behavior is not desired, the Invalidate() method can be used to clear caches on any Account, Container or Object instance. Some methods that modify the instance on the server call Invalidate() automatically, e.g. Object.Upload(), Update() or Delete(). This will be indicated in the method's documentation.

Error handling

When a method on an Account, Container or Object instance makes a HTTP request to Swift and Swift returns an unexpected status code, a schwift.UnexpectedStatusCodeError will be returned. Schwift provides the convenience function Is() to check the status code of these errors to detect common failure situations:

obj := account.Container("foo").Object("bar")
err := obj.Upload(bytes.NewReader(data), nil)

if schwift.Is(err, http.StatusRequestEntityTooLarge) {
	log.Print("quota exceeded for container foo!")
} else if err != nil {
	log.Fatal("unexpected error: " + err.Error())
}

The documentation for a method may indicate certain common error conditions that can be detected this way by stating that "This method fails with http.StatusXXX if ...". Because of the wide variety of failure modes in Swift, this information is not guaranteed to be exhaustive.

Index

Package Files

account.go backend.go bulk.go capabilities.go container.go container_iterator.go doc.go download.go errors.go field_metadata.go field_string.go field_time.go field_uint64.go generated.go headers.go iterator.go largeobject.go object.go object_iterator.go request.go version.go

Constants

const DefaultUserAgent = "schwift/" + Version

DefaultUserAgent is the User-Agent string that Backend implementations should use if the user does not provide their own User-Agent string.

const Version = "1.0-beta"

Version contains the version number of Schwift.

Variables

var (
    //ErrChecksumMismatch is returned by Object.Upload() when the Etag in the
    //server response does not match the uploaded data.
    ErrChecksumMismatch = errors.New("Etag on uploaded object does not match MD5 checksum of uploaded data")
    //ErrNoContainerName is returned by Request.Do() if ObjectName is given, but
    //ContainerName is empty.
    ErrNoContainerName = errors.New("missing container name")
    //ErrMalformedContainerName is returned by Request.Do() if ContainerName
    //contains slashes.
    ErrMalformedContainerName = errors.New("container name may not contain slashes")
    //ErrNotSupported is returned by bulk operations, large object operations,
    //etc. if the server does not support the requested operation.
    ErrNotSupported = errors.New("operation not supported by this Swift server")
    //ErrAccountMismatch is returned by operations on an account that accept
    //containers/objects as arguments, if some or all of the provided
    //containers/objects are located in a different account.
    ErrAccountMismatch = errors.New("some of the given objects are not in this account")
    //ErrContainerMismatch is returned by operations on a container that accept
    //objects as arguments, if some or all of the provided objects are located in
    //a different container.
    ErrContainerMismatch = errors.New("some of the given objects are not in this container")
    //ErrNotLarge is returned by Object.AsLargeObject() if the object does not
    //exist, or if it is not a large object composed out of segments.
    ErrNotLarge = errors.New("not a large object")
    //ErrSegmentInvalid is returned by LargeObject.AddSegment() if the segment
    //provided is malformed or uses features not supported by the LargeObject's
    //strategy. See documentation for LargeObject.AddSegment() for details.
    ErrSegmentInvalid = errors.New("segment invalid or incompatible with large object strategy")
)

func Is Uses

func Is(err error, code int) bool

Is checks if the given error is an UnexpectedStatusCodeError for that status code. For example:

err := container.Delete(nil)
if err != nil {
    if schwift.Is(err, http.StatusNotFound) {
        //container does not exist -> just what we wanted
        return nil
    } else {
        //report unexpected error
        return err
    }
}

It is safe to pass a nil error, in which case Is() always returns false.

type Account Uses

type Account struct {
    // contains filtered or unexported fields
}

Account represents a Swift account. Instances are usually obtained by connecting to a backend (see package-level documentation), or by traversing upwards from a container with Container.Account().

func InitializeAccount Uses

func InitializeAccount(backend Backend) (*Account, error)

InitializeAccount takes something that implements the Backend interface, and returns the Account instance corresponding to the account/project that this backend is connected to.

func (*Account) Backend Uses

func (a *Account) Backend() Backend

Backend returns the backend which is used to make requests against this account.

func (*Account) BulkDelete Uses

func (a *Account) BulkDelete(objects []*Object, containers []*Container, opts *RequestOptions) (numDeleted int, numNotFound int, deleteError error)

BulkDelete deletes a large number of objects (and containers) at once. Containers are queued at the end of the deletion, so a container can be deleted in the same call in which all objects in it are deleted.

For example, to delete all objects in a container:

var container *schwift.Container

objects, err := container.Objects().Collect()
numDeleted, numNotFound, err := container.Account().BulkDelete(objects, nil, nil)

To also delete the container:

var container *schwift.Container

objects, err := container.Objects().Collect()
numDeleted, numNotFound, err := container.Account().BulkDelete(
    objects, []*schwift.Container{container}, nil)

If the server does not support bulk-deletion, this function falls back to deleting each object and container individually, and aggregates the result.

If not nil, the error return value is *usually* an instance of BulkError.

The objects may be located in multiple containers, but they and the containers must all be located in the given account. (Otherwise, ErrAccountMismatch is returned.)

func (*Account) BulkUpload Uses

func (a *Account) BulkUpload(uploadPath string, format BulkUploadFormat, contents io.Reader, opts *RequestOptions) (int, error)

BulkUpload extracts an archive (which may contain multiple files) into a Swift account. The path of each file in the archive is appended to the uploadPath to form the FullName() of the resulting Object.

For example, when uploading an archive that contains the file "a/b/c":

//This uploads the file into the container "a" as object "b/c".
account.BulkUpload("", format, contents, nil)
//This uploads the file into the container "foo" as object "a/b/c".
account.BulkUpload("foo", format, contents, nil)
//This uploads the file into the container "foo" as object "bar/baz/a/b/c".
account.BulkUpload("foo/bar/baz", format, contents, nil)

The first return value indicates the number of files that have been created on the server side. This may be lower than the number of files in the archive if some files could not be saved individually (e.g. because a quota was exceeded in the middle of the archive extraction).

If not nil, the error return value is *usually* an instance of BulkError.

This operation returns (0, ErrNotSupported) if the server does not support bulk-uploading.

func (*Account) Capabilities Uses

func (a *Account) Capabilities() (Capabilities, error)

Capabilities queries the GET /info endpoint of the Swift server providing this account. Capabilities are cached, so the GET request will only be sent once during the first call to this method.

func (*Account) Container Uses

func (a *Account) Container(name string) *Container

Container returns a handle to the container with the given name within this account. This function does not issue any HTTP requests, and therefore cannot ensure that the container exists. Use the Exists() function to check for the container's existence, or chain this function with the EnsureExists() function like so:

container, err := account.Container("documents").EnsureExists()

func (*Account) Containers Uses

func (a *Account) Containers() *ContainerIterator

Containers returns a ContainerIterator that lists the containers in this account. The most common use case is:

containers, err := account.Containers().Collect()

You can extend this by configuring the iterator before collecting the results:

iter := account.Containers()
iter.Prefix = "test-"
containers, err := iter.Collect()

Or you can use a different iteration method:

err := account.Containers().ForeachDetailed(func (ci ContainerInfo) error {
	log.Printf("container %s contains %d objects!\n",
		ci.Container.Name(), ci.ObjectCount)
})

func (*Account) Create Uses

func (a *Account) Create(opts *RequestOptions) error

Create creates the account using a PUT request. This operation is only available to reseller admins, not to regular users.

A successful PUT request implies Invalidate() since it may change metadata.

func (*Account) Headers Uses

func (a *Account) Headers() (AccountHeaders, error)

Headers returns the AccountHeaders for this account. If the AccountHeaders has not been cached yet, a HEAD request is issued on the account.

This operation fails with http.StatusNotFound if the account does not exist.

func (*Account) Invalidate Uses

func (a *Account) Invalidate()

Invalidate clears the internal cache of this Account instance. The next call to Headers() on this instance will issue a HEAD request on the account.

func (*Account) IsEqualTo Uses

func (a *Account) IsEqualTo(other *Account) bool

IsEqualTo returns true if both Account instances refer to the same account.

func (*Account) Name Uses

func (a *Account) Name() string

Name returns the name of the account (usually the prefix "AUTH_" followed by the Keystone project ID).

func (*Account) RawCapabilities Uses

func (a *Account) RawCapabilities() ([]byte, error)

RawCapabilities queries the GET /info endpoint of the Swift server providing this account, and returns the response body. Unlike Account.Capabilities, this method does not employ any caching.

func (*Account) SwitchAccount Uses

func (a *Account) SwitchAccount(accountName string) *Account

SwitchAccount returns a handle to a different account on the same server. Note that you need reseller permissions to access accounts other than that where you originally authenticated. This method does not check whether the account actually exists.

The account name is usually the Keystone project ID with an additional "AUTH_" prefix.

func (*Account) Update Uses

func (a *Account) Update(headers AccountHeaders, opts *RequestOptions) error

Update updates the account using a POST request. The headers in the headers attribute take precedence over those in opts.Headers.

A successful POST request implies Invalidate() since it may change metadata.

type AccountHeaders Uses

type AccountHeaders struct {
    Headers
}

AccountHeaders contains the headers for a schwift.Account instance.

To read and write well-known headers, use the methods on this type. To read and write arbitary headers, use the methods on the Headers supertype.

func NewAccountHeaders Uses

func NewAccountHeaders() AccountHeaders

NewAccountHeaders creates a new AccountHeaders instance. The return value will have the Headers attribute initialized to a non-nil map.

func (AccountHeaders) BytesUsed Uses

func (h AccountHeaders) BytesUsed() FieldUint64Readonly

BytesUsed provides type-safe access to X-Account-Bytes-Used headers.

func (AccountHeaders) BytesUsedQuota Uses

func (h AccountHeaders) BytesUsedQuota() FieldUint64

BytesUsedQuota provides type-safe access to X-Account-Meta-Quota-Bytes headers.

func (AccountHeaders) ContainerCount Uses

func (h AccountHeaders) ContainerCount() FieldUint64Readonly

ContainerCount provides type-safe access to X-Account-Container-Count headers.

func (AccountHeaders) CreatedAt Uses

func (h AccountHeaders) CreatedAt() FieldUnixTimeReadonly

CreatedAt provides type-safe access to X-Timestamp headers.

func (AccountHeaders) Metadata Uses

func (h AccountHeaders) Metadata() FieldMetadata

Metadata provides type-safe access to X-Account-Meta- headers.

func (AccountHeaders) ObjectCount Uses

func (h AccountHeaders) ObjectCount() FieldUint64Readonly

ObjectCount provides type-safe access to X-Account-Object-Count headers.

func (AccountHeaders) TempURLKey Uses

func (h AccountHeaders) TempURLKey() FieldString

TempURLKey provides type-safe access to X-Account-Meta-Temp-URL-Key headers.

func (AccountHeaders) TempURLKey2 Uses

func (h AccountHeaders) TempURLKey2() FieldString

TempURLKey2 provides type-safe access to X-Account-Meta-Temp-URL-Key-2 headers.

func (AccountHeaders) Validate Uses

func (h AccountHeaders) Validate() error

Validate returns MalformedHeaderError if the value of any well-known header does not conform to its data type. This is called automatically by Schwift when preparing an AccountHeaders instance from a GET/HEAD response, so you usually do not need to do it yourself. You will get the validation error from the Account method doing the request, e.g. Headers().

type Backend Uses

type Backend interface {
    //EndpointURL returns the endpoint URL from the Keystone catalog for the
    //Swift account that this backend operates on. It should look like
    //`http://domain.tld/v1/AUTH_projectid/`. The trailing slash is required.
    EndpointURL() string
    //Clone returns a deep clone of this backend with the endpoint URL changed to
    //the given URL. This is used by Account.SwitchAccount().
    Clone(newEndpointURL string) Backend
    //Do executes the given HTTP request after adding to it the X-Auth-Token
    //header containing the backend's current Keystone (or Swift auth) token. If
    //the status code returned is 401, it shall attempt to acquire a new auth
    //token and restart the request with the new token.
    //
    //If the user has not supplied their own User-Agent string to the backend,
    //the backend should use the schwift.DefaultUserAgent constant instead.
    Do(req *http.Request) (*http.Response, error)
}

Backend is the interface between Schwift and the libraries providing authentication for it. Each instance of Backend represents a particular Swift account.

type BulkError Uses

type BulkError struct {
    //StatusCode contains the overall HTTP status code of the operation.
    StatusCode int
    //OverallError contains the fatal error that aborted the bulk operation, or a
    //summary of which recoverable errors were encountered. It may be empty.
    OverallError string
    //ObjectErrors contains errors that occurred while working on individual
    //objects or containers. It may be empty if no such errors occurred.
    ObjectErrors []BulkObjectError
}

BulkError is returned by Account.BulkUpload() when the archive was uploaded and unpacked successfully, but some (or all) objects could not be saved in Swift; and by Account.BulkDelete() when not all requested objects could be deleted.

func (BulkError) Error Uses

func (e BulkError) Error() string

Error implements the builtin/error interface. To fit into one line, it condenses the ObjectErrors into a count.

type BulkObjectError Uses

type BulkObjectError struct {
    ContainerName string
    ObjectName    string
    StatusCode    int
}

BulkObjectError is the error message for a single object in a bulk operation. It is not generated individually, only as part of BulkError.

func (BulkObjectError) Error Uses

func (e BulkObjectError) Error() string

Error implements the builtin/error interface.

type BulkUploadFormat Uses

type BulkUploadFormat string

BulkUploadFormat enumerates possible archive formats for Container.BulkUpload().

const (
    //BulkUploadTar is a plain tar archive.
    BulkUploadTar BulkUploadFormat = "tar"
    //BulkUploadTarGzip is a GZip-compressed tar archive.
    BulkUploadTarGzip BulkUploadFormat = "tar.gz"
    //BulkUploadTarBzip2 is a BZip2-compressed tar archive.
    BulkUploadTarBzip2 BulkUploadFormat = "tar.bz2"
)

type Capabilities Uses

type Capabilities struct {
    BulkDelete *struct {
        MaximumDeletesPerRequest uint `json:"max_deletes_per_request"`
        MaximumFailedDeletes     uint `json:"max_failed_deletes"`
    }   `json:"bulk_delete"`
    BulkUpload *struct {
        MaximumContainersPerExtraction uint `json:"max_containers_per_extraction"`
        MaximumFailedExtractions       uint `json:"max_failed_extractions"`
    }   `json:"bulk_upload"`
    StaticLargeObject *struct {
        MaximumManifestSegments uint `json:"max_manifest_segments"`
        MaximumManifestSize     uint `json:"max_manifest_size"`
        MinimumSegmentSize      uint `json:"min_segment_size"`
    }   `json:"slo"`
    Swift struct {
        AccountAutocreate          bool                `json:"account_autocreate"`
        AccountListingLimit        uint                `json:"account_listing_limit"`
        AllowAccountManagement     bool                `json:"allow_account_management"`
        ContainerListingLimit      uint                `json:"container_listing_limit"`
        ExtraHeaderCount           uint                `json:"extra_header_count"`
        MaximumAccountNameLength   uint                `json:"max_account_name_length"`
        MaximumContainerNameLength uint                `json:"max_container_name_length"`
        MaximumFileSize            uint                `json:"max_file_size"`
        MaximumHeaderSize          uint                `json:"max_header_size"`
        MaximumMetaCount           uint                `json:"max_meta_count"`
        MaximumMetaNameLength      uint                `json:"max_meta_name_length"`
        MaximumMetaOverallSize     uint                `json:"max_meta_overall_size"`
        MaximumMetaValueLength     uint                `json:"max_meta_value_length"`
        MaximumObjectNameLength    uint                `json:"max_object_name_length"`
        Policies                   []StoragePolicySpec `json:"policies"`
        StrictCORSMode             bool                `json:"strict_cors_mode"`
        Version                    string              `json:"version"`
    }   `json:"swift"`
    Swift3 *struct {
        AllowMultipartUploads     bool   `json:"allow_multipart_uploads"`
        MaximumBucketListing      uint   `json:"max_bucket_listing"`
        MaximumMultiDeleteObjects uint   `json:"max_multi_delete_objects"`
        MaximumPartsListing       uint   `json:"max_parts_listing"`
        MaximumUploadPartNumber   uint   `json:"max_upload_part_num"`
        Version                   string `json:"version"`
    }   `json:"swift3"`
    Symlink *struct {
        MaximumLoopCount uint `json:"symloop_max"`
    }   `json:"symlink"`
    TempAuth *struct {
        AccountACLs bool `json:"account_acls"`
    }   `json:"tempauth"`
    TempURL *struct {
        IncomingAllowHeaders  []string `json:"incoming_allow_headers"`
        IncomingRemoveHeaders []string `json:"incoming_remove_headers"`
        Methods               []string `json:"methods"`
        OutgoingAllowHeaders  []string `json:"outgoing_allow_headers"`
        OutgoingRemoveHeaders []string `json:"outgoing_remove_headers"`
    }   `json:"tempurl"`
}

Capabilities describes a subset of the capabilities that Swift can report under its /info endpoint. This struct is obtained through the Account.Capabilities() method. To query capabilities not represented in this struct, see Account.QueryCapabilities().

All direct members of struct Capabilities, except for "Swift", are pointers. If any of these is nil, it indicates that the middleware corresponding to that field is not available on this server.

type Container Uses

type Container struct {
    // contains filtered or unexported fields
}

Container represents a Swift container. Instances are usually obtained by traversing downwards from an account with Account.Container() or Account.Containers(), or upwards from an object with Object.Container().

func (*Container) Account Uses

func (c *Container) Account() *Account

Account returns a handle to the account this container is stored in.

func (*Container) Create Uses

func (c *Container) Create(opts *RequestOptions) error

Create creates the container using a PUT request. To add URL parameters, pass a non-nil *RequestOptions.

This function can be used regardless of whether the container exists or not.

A successful PUT request implies Invalidate() since it may change metadata.

func (*Container) Delete Uses

func (c *Container) Delete(opts *RequestOptions) error

Delete deletes the container using a DELETE request. To add URL parameters, pass a non-nil *RequestOptions.

This operation fails with http.StatusConflict if the container is not empty.

This operation fails with http.StatusNotFound if the container does not exist.

A successful DELETE request implies Invalidate().

func (*Container) EnsureExists Uses

func (c *Container) EnsureExists() (*Container, error)

EnsureExists issues a PUT request on this container. If the container does not exist yet, it will be created by this call. If the container exists already, this call does not change it. This function returns the same container again, because its intended use is with freshly constructed Container instances like so:

container, err := account.Container("documents").EnsureExists()

func (*Container) Exists Uses

func (c *Container) Exists() (bool, error)

Exists checks if this container exists, potentially by issuing a HEAD request if no Headers() have been cached yet.

func (*Container) Headers Uses

func (c *Container) Headers() (ContainerHeaders, error)

Headers returns the ContainerHeaders for this container. If the ContainerHeaders has not been cached yet, a HEAD request is issued on the container.

This operation fails with http.StatusNotFound if the container does not exist.

func (*Container) Invalidate Uses

func (c *Container) Invalidate()

Invalidate clears the internal cache of this Container instance. The next call to Headers() on this instance will issue a HEAD request on the container.

func (*Container) IsEqualTo Uses

func (c *Container) IsEqualTo(other *Container) bool

IsEqualTo returns true if both Container instances refer to the same container.

func (*Container) Name Uses

func (c *Container) Name() string

Name returns the container name.

func (*Container) Object Uses

func (c *Container) Object(name string) *Object

Object returns a handle to the object with the given name within this container. This function does not issue any HTTP requests, and therefore cannot ensure that the object exists. Use the Exists() function to check for the object's existence.

func (*Container) Objects Uses

func (c *Container) Objects() *ObjectIterator

Objects returns an ObjectIterator that lists the objects in this container. The most common use case is:

objects, err := container.Objects().Collect()

You can extend this by configuring the iterator before collecting the results:

iter := container.Objects()
iter.Prefix = "test-"
objects, err := iter.Collect()

Or you can use a different iteration method:

err := container.Objects().ForeachDetailed(func (info ObjectInfo) error {
    log.Printf("object %s is %d bytes large!\n",
        info.Object.Name(), info.SizeBytes)
})

func (*Container) URL Uses

func (c *Container) URL() (string, error)

URL returns the canonical URL for this container on the server. This is particularly useful when the ReadACL on the account or container is set to allow anonymous read access.

func (*Container) Update Uses

func (c *Container) Update(headers ContainerHeaders, opts *RequestOptions) error

Update updates the container using a POST request. To add URL parameters, pass a non-nil *RequestOptions.

If you are not sure whether the container exists, use Create() instead.

A successful POST request implies Invalidate() since it may change metadata.

type ContainerHeaders Uses

type ContainerHeaders struct {
    Headers
}

ContainerHeaders contains the headers for a schwift.Container instance.

To read and write well-known headers, use the methods on this type. To read and write arbitary headers, use the methods on the Headers supertype.

func NewContainerHeaders Uses

func NewContainerHeaders() ContainerHeaders

NewContainerHeaders creates a new ContainerHeaders instance. The return value will have the Headers attribute initialized to a non-nil map.

func (ContainerHeaders) BytesUsed Uses

func (h ContainerHeaders) BytesUsed() FieldUint64Readonly

BytesUsed provides type-safe access to X-Container-Bytes-Used headers.

func (ContainerHeaders) BytesUsedQuota Uses

func (h ContainerHeaders) BytesUsedQuota() FieldUint64

BytesUsedQuota provides type-safe access to X-Container-Meta-Quota-Bytes headers.

func (ContainerHeaders) CreatedAt Uses

func (h ContainerHeaders) CreatedAt() FieldUnixTimeReadonly

CreatedAt provides type-safe access to X-Timestamp headers.

func (ContainerHeaders) HistoryLocation Uses

func (h ContainerHeaders) HistoryLocation() FieldString

HistoryLocation provides type-safe access to X-History-Location headers.

func (ContainerHeaders) Metadata Uses

func (h ContainerHeaders) Metadata() FieldMetadata

Metadata provides type-safe access to X-Container-Meta- headers.

func (ContainerHeaders) ObjectCount Uses

func (h ContainerHeaders) ObjectCount() FieldUint64Readonly

ObjectCount provides type-safe access to X-Container-Object-Count headers.

func (ContainerHeaders) ObjectCountQuota Uses

func (h ContainerHeaders) ObjectCountQuota() FieldUint64

ObjectCountQuota provides type-safe access to X-Container-Meta-Quota-Count headers.

func (ContainerHeaders) ReadACL Uses

func (h ContainerHeaders) ReadACL() FieldString

ReadACL provides type-safe access to X-Container-Read headers.

func (ContainerHeaders) StoragePolicy Uses

func (h ContainerHeaders) StoragePolicy() FieldString

StoragePolicy provides type-safe access to X-Storage-Policy headers.

func (ContainerHeaders) SyncKey Uses

func (h ContainerHeaders) SyncKey() FieldString

SyncKey provides type-safe access to X-Container-Sync-Key headers.

func (ContainerHeaders) SyncTo Uses

func (h ContainerHeaders) SyncTo() FieldString

SyncTo provides type-safe access to X-Container-Sync-To headers.

func (ContainerHeaders) TempURLKey Uses

func (h ContainerHeaders) TempURLKey() FieldString

TempURLKey provides type-safe access to X-Container-Meta-Temp-URL-Key headers.

func (ContainerHeaders) TempURLKey2 Uses

func (h ContainerHeaders) TempURLKey2() FieldString

TempURLKey2 provides type-safe access to X-Container-Meta-Temp-URL-Key-2 headers.

func (ContainerHeaders) Validate Uses

func (h ContainerHeaders) Validate() error

Validate returns MalformedHeaderError if the value of any well-known header does not conform to its data type. This is called automatically by Schwift when preparing an ContainerHeaders instance from a GET/HEAD response, so you usually do not need to do it yourself. You will get the validation error from the Container method doing the request, e.g. Headers().

func (ContainerHeaders) VersionsLocation Uses

func (h ContainerHeaders) VersionsLocation() FieldString

VersionsLocation provides type-safe access to X-Versions-Location headers.

func (ContainerHeaders) WriteACL Uses

func (h ContainerHeaders) WriteACL() FieldString

WriteACL provides type-safe access to X-Container-Write headers.

type ContainerInfo Uses

type ContainerInfo struct {
    Container    *Container
    ObjectCount  uint64
    BytesUsed    uint64
    LastModified time.Time
}

ContainerInfo is a result type returned by ContainerIterator for detailed container listings. The metadata in this type is a subset of Container.Headers(), but since it is returned as part of the detailed container listing, it can be obtained without making additional HEAD requests on the container(s).

type ContainerIterator Uses

type ContainerIterator struct {
    Account *Account
    //When Prefix is set, only containers whose name starts with this string are
    //returned.
    Prefix string
    //Options may contain additional headers and query parameters for the GET request.
    Options *RequestOptions
    // contains filtered or unexported fields
}

ContainerIterator iterates over the accounts in a container. It is typically constructed with the Account.Containers() method. For example:

//either this...
iter := account.Containers()
iter.Prefix = "test-"
containers, err := iter.Collect()

//...or this
containers, err := schwift.ContainerIterator{
	Account: account,
	Prefix: "test-",
}.Collect()

When listing containers via a GET request on the account, you can choose to receive container names only (via the methods without the "Detailed" suffix), or container names plus some basic metadata fields (via the methods with the "Detailed" suffix). See struct ContainerInfo for which metadata is returned.

To obtain any other metadata, you can call Container.Headers() on the result container, but this will issue a separate HEAD request for each container.

Use the "Detailed" methods only when you use the extra metadata in struct ContainerInfo; detailed GET requests are more expensive than simple ones that return only container names.

func (*ContainerIterator) Collect Uses

func (i *ContainerIterator) Collect() ([]*Container, error)

Collect lists all container names matching this iterator. For large sets of containers that cannot be retrieved at once, Collect handles paging behind the scenes. The return value is always the complete set of containers.

func (*ContainerIterator) CollectDetailed Uses

func (i *ContainerIterator) CollectDetailed() ([]ContainerInfo, error)

CollectDetailed is like Collect, but includes basic metadata.

func (*ContainerIterator) Foreach Uses

func (i *ContainerIterator) Foreach(callback func(*Container) error) error

Foreach lists the container names matching this iterator and calls the callback once for every container. Iteration is aborted when a GET request fails, or when the callback returns a non-nil error.

func (*ContainerIterator) ForeachDetailed Uses

func (i *ContainerIterator) ForeachDetailed(callback func(ContainerInfo) error) error

ForeachDetailed is like Foreach, but includes basic metadata.

func (*ContainerIterator) NextPage Uses

func (i *ContainerIterator) NextPage(limit int) ([]*Container, error)

NextPage queries Swift for the next page of container names. If limit is >= 0, not more than that many container names will be returned at once. Note that the server also has a limit for how many containers to list in one request; the lower limit wins.

The end of the container listing is reached when an empty list is returned.

This method offers maximal flexibility, but most users will prefer the simpler interfaces offered by Collect() and Foreach().

func (*ContainerIterator) NextPageDetailed Uses

func (i *ContainerIterator) NextPageDetailed(limit int) ([]ContainerInfo, error)

NextPageDetailed is like NextPage, but includes basic metadata.

type CopyOptions Uses

type CopyOptions struct {
    //Copy only the object's content, not its metadata. New metadata can always
    //be supplied in the RequestOptions argument of Object.CopyTo().
    FreshMetadata bool
    //When the source is a symlink, copy the symlink instead of the target object.
    ShallowCopySymlinks bool
}

CopyOptions invokes advanced behavior in the Object.Copy() method.

type DeleteOptions Uses

type DeleteOptions struct {
    //When deleting a large object, also delete its segments. This will cause
    //Delete() to call into BulkDelete(), so a BulkError may be returned.
    DeleteSegments bool
}

DeleteOptions invokes advanced behavior in the Object.Delete() method.

type DownloadedObject Uses

type DownloadedObject struct {
    // contains filtered or unexported fields
}

DownloadedObject is returned by Object.Download(). It wraps the io.ReadCloser from http.Response.Body with convenience methods for collecting the contents into a byte slice or string.

var obj *swift.Object

//Do NOT do this!
reader, err := obj.Download(nil).AsReadCloser()
bytes, err := ioutil.ReadAll(reader)
err := reader.Close()
str := string(bytes)

//Do this instead:
str, err := obj.Download(nil).AsString()

Since all methods on DownloadedObject are irreversible, the idiomatic way of using DownloadedObject is to call one of its members immediately, without storing the DownloadedObject instance in a variable first.

var obj *swift.Object

//Do NOT do this!
downloaded := obj.Download(nil)
reader, err := downloaded.AsReadCloser()

//Do this instead:
reader, err := obj.Download(nil).AsReadCloser()

func (DownloadedObject) AsByteSlice Uses

func (o DownloadedObject) AsByteSlice() ([]byte, error)

AsByteSlice collects the contents of this downloaded object into a byte slice.

func (DownloadedObject) AsReadCloser Uses

func (o DownloadedObject) AsReadCloser() (io.ReadCloser, error)

AsReadCloser returns an io.ReadCloser containing the contents of the downloaded object.

func (DownloadedObject) AsString Uses

func (o DownloadedObject) AsString() (string, error)

AsString collects the contents of this downloaded object into a string.

type FieldHTTPTimeReadonly Uses

type FieldHTTPTimeReadonly struct {
    // contains filtered or unexported fields
}

FieldHTTPTimeReadonly is a helper type that provides type-safe access to a readonly Swift header whose value is a HTTP timestamp like this:

Mon, 02 Jan 2006 15:04:05 GMT

It cannot be directly constructed, but methods on the Headers types return this type. For example:

//suppose you have:
hdr, err := obj.Headers()

//you could do this:
time, err := time.Parse(time.RFC1123, hdr.Get("Last-Modified"))

//or you can just:
time := hdr.UpdatedAt().Get()

Don't worry about the missing `err` in the last line. When the header fails to parse, Object.Headers() already returns the corresponding MalformedHeaderError.

func (FieldHTTPTimeReadonly) Exists Uses

func (f FieldHTTPTimeReadonly) Exists() bool

Exists checks whether there is a value for this header.

func (FieldHTTPTimeReadonly) Get Uses

func (f FieldHTTPTimeReadonly) Get() time.Time

Get returns the value for this header, or the zero value if there is no value (or if it is not a valid timestamp).

type FieldMetadata Uses

type FieldMetadata struct {
    // contains filtered or unexported fields
}

FieldMetadata is a helper type that provides safe access to the metadata headers in a headers instance. It cannot be directly constructed, but each headers type has a method "Metadata" returning this type. For example:

hdr := NewObjectHeaders()
//the following two statements are equivalent
hdr["X-Object-Meta-Access"] = "strictly confidential"
hdr.Metadata().Set("Access", "strictly confidential")

func (FieldMetadata) Clear Uses

func (m FieldMetadata) Clear(key string)

Clear works like Headers.Clear(), but prepends the metadata prefix to the key.

func (FieldMetadata) Del Uses

func (m FieldMetadata) Del(key string)

Del works like Headers.Del(), but prepends the metadata prefix to the key.

func (FieldMetadata) Get Uses

func (m FieldMetadata) Get(key string) string

Get works like Headers.Get(), but prepends the metadata prefix to the key.

func (FieldMetadata) Set Uses

func (m FieldMetadata) Set(key, value string)

Set works like Headers.Set(), but prepends the metadata prefix to the key.

type FieldString Uses

type FieldString struct {
    // contains filtered or unexported fields
}

FieldString is a helper type that provides type-safe access to a Swift header key whose value is a string. It cannot be directly constructed, but methods on the Headers types return this type. For example:

hdr := NewAccountHeaders()
//the following two statements are equivalent:
hdr["X-Container-Read"] = ".r:*,.rlistings"
hdr.ReadACL().Set(".r:*,.rlistings")

func (FieldString) Clear Uses

func (f FieldString) Clear()

Clear sets this key to an empty string in the original headers instance, so that the key will be removed on the server during Update().

func (FieldString) Del Uses

func (f FieldString) Del()

Del removes this key from the original headers instance, so that the key will remain unchanged on the server during Update().

func (FieldString) Exists Uses

func (f FieldString) Exists() bool

Exists checks whether there is a value for this header.

func (FieldString) Get Uses

func (f FieldString) Get() string

Get returns the value for this header, or the empty string if there is no value.

func (FieldString) Set Uses

func (f FieldString) Set(value string)

Set writes a new value for this header into the corresponding headers instance.

type FieldUint64 Uses

type FieldUint64 struct {
    // contains filtered or unexported fields
}

FieldUint64 is a helper type that provides type-safe access to a Swift header whose value is an unsigned integer. It cannot be directly constructed, but methods on the Headers types return this type. For example:

hdr := NewAccountHeaders()
//the following two statements are equivalent:
hdr["X-Account-Meta-Quota-Bytes"] = "1048576"
hdr.BytesUsedQuota().Set(1 << 20)

func (FieldUint64) Clear Uses

func (f FieldUint64) Clear()

Clear sets this key to an empty string in the original headers instance, so that the key will be removed on the server during Update().

func (FieldUint64) Del Uses

func (f FieldUint64) Del()

Del removes this key from the original headers instance, so that the key will remain unchanged on the server during Update().

func (FieldUint64) Exists Uses

func (f FieldUint64) Exists() bool

Exists checks whether there is a value for this header.

func (FieldUint64) Get Uses

func (f FieldUint64) Get() uint64

Get returns the value for this header, or 0 if there is no value (or if it is not a valid uint64).

func (FieldUint64) Set Uses

func (f FieldUint64) Set(value uint64)

Set writes a new value for this header into the corresponding headers instance.

type FieldUint64Readonly Uses

type FieldUint64Readonly struct {
    // contains filtered or unexported fields
}

FieldUint64Readonly is a readonly variant of FieldUint64. It is used for fields that cannot be set by the client.

func (FieldUint64Readonly) Exists Uses

func (f FieldUint64Readonly) Exists() bool

Exists checks whether there is a value for this header.

func (FieldUint64Readonly) Get Uses

func (f FieldUint64Readonly) Get() uint64

Get returns the value for this header, or 0 if there is no value (or if it is not a valid uint64).

type FieldUnixTime Uses

type FieldUnixTime struct {
    // contains filtered or unexported fields
}

FieldUnixTime is a helper type that provides type-safe access to a Swift header whose value is a UNIX timestamp. It cannot be directly constructed, but methods on the Headers types return this type. For example:

//suppose you have:
hdr, err := obj.Headers()

//you could do all this:
sec, err := strconv.ParseFloat(hdr.Get("X-Delete-At"), 64)
time := time.Unix(0, int64(1e9 * sec))

//or you can just:
time := hdr.ExpiresAt().Get()

Don't worry about the missing `err` in the last line. When the header fails to parse, Object.Headers() already returns the corresponding MalformedHeaderError.

func (FieldUnixTime) Clear Uses

func (f FieldUnixTime) Clear()

Clear sets this key to an empty string in the original headers instance, so that the key will be removed on the server during Update().

func (FieldUnixTime) Del Uses

func (f FieldUnixTime) Del()

Del removes this key from the original headers instance, so that the key will remain unchanged on the server during Update().

func (FieldUnixTime) Exists Uses

func (f FieldUnixTime) Exists() bool

Exists checks whether there is a value for this header.

func (FieldUnixTime) Get Uses

func (f FieldUnixTime) Get() time.Time

Get returns the value for this header, or the zero value if there is no value (or if it is not a valid timestamp).

func (FieldUnixTime) Set Uses

func (f FieldUnixTime) Set(value time.Time)

Set writes a new value for this header into the corresponding headers instance.

type FieldUnixTimeReadonly Uses

type FieldUnixTimeReadonly struct {
    // contains filtered or unexported fields
}

FieldUnixTimeReadonly is a readonly variant of FieldUnixTime. It is used for fields that cannot be set by the client.

func (FieldUnixTimeReadonly) Exists Uses

func (f FieldUnixTimeReadonly) Exists() bool

Exists checks whether there is a value for this header.

func (FieldUnixTimeReadonly) Get Uses

func (f FieldUnixTimeReadonly) Get() time.Time

Get returns the value for this header, or the zero value if there is no value (or if it is not a valid timestamp).

type Headers Uses

type Headers map[string]string

Headers represents a set of request headers or response headers.

Users will typically use one of the subtypes (AccountHeaders, ContainerHeaders, ObjectHeaders) instead, which provide type-safe access to well-known headers. The http.Header-like interface on this type can be used read and write arbitary headers. For example, the following calls are equivalent:

h := make(AccountHeaders)
h.Headers.Set("X-Account-Meta-Quota-Bytes", "1048576")
h.BytesUsedQuota().Set(1048576)

func (Headers) Clear Uses

func (h Headers) Clear(key string)

Clear sets the value for the specified header to the empty string. When the Headers instance is then sent to the server with Update(), the server will delete the value for that header; cf. Del().

func (Headers) Del Uses

func (h Headers) Del(key string)

Del deletes a key from the Headers instance. When the Headers instance is then sent to the server with Update(), a key which has been deleted with Del() will remain unchanged on the server.

For most writable attributes, a key which has been deleted with Del() will remain unchanged on the server. To remove the key on the server, use Clear() instead.

For object metadata (but not other object attributes), deleting a key will cause that key to be deleted on the server. Del() is identical to Clear() in this case.

func (Headers) Get Uses

func (h Headers) Get(key string) string

Get returns the value for the specified header.

func (Headers) Set Uses

func (h Headers) Set(key, value string)

Set sets a new value for the specified header. Any existing value will be overwritten.

func (Headers) ToHTTP Uses

func (h Headers) ToHTTP() http.Header

ToHTTP converts this Headers instance into the equivalent http.Header instance. The return value is guaranteed to be non-nil.

func (Headers) ToOpts Uses

func (h Headers) ToOpts() *RequestOptions

ToOpts wraps this Headers instance into a RequestOpts instance, so that it can be passed to Schwift's various request methods.

hdr := NewObjectHeaders()
hdr.ContentType().Set("image/png")
hdr.Metadata().Set("color", "blue")
obj.Upload(content, nil, hdr.ToOpts())

type LargeObject Uses

type LargeObject struct {
    // contains filtered or unexported fields
}

LargeObject is a wrapper for type Object that performs operations specific to large objects, i.e. those objects which are uploaded in segments rather than all at once. It can be constructed with the Object.AsLargeObject() and Object.AsNewLargeObject() methods.

The following example shows how to upload a large file from the filesystem to Swift (error handling elided for brevity):

file, err := os.Open(sourcePath)
segmentContainer, err := account.Container("segments").EnsureExists()

lo, err := o.AsNewLargeObject(schwift.SegmentingOptions {
    SegmentContainer: segmentContainer,
    //use defaults for everything else
}, &schwift.TruncateOptions {
    //if there's already a large object here, clean it up
    DeleteSegments: true,
})

err = lo.Append(contents, 1<<30) // 1<30 bytes = 1 GiB per segment
err = lo.WriteManifest(nil)

Append() has a more low-level counterpart, AddSegment(). Both methods can be freely intermixed. AddSegment() is useful when you want to control the segments' metadata or use advanced features like range segments or data segments; see documentation over there.

Writing to a large object must always be concluded by a call to WriteManifest() to link the new segments to the large object on the server side.

func (*LargeObject) AddSegment Uses

func (lo *LargeObject) AddSegment(segment SegmentInfo) error

AddSegment appends a segment to this object. The segment must already have been uploaded.

WARNING: This is a low-level function. Most callers will want to use Append(). You will only need to add segments manually when you want to control the segments' metadata, or when using advanced features such as range-limited segments or data segments.

This method returns ErrAccountMismatch if the segment is not located in a container in the same account.

For dynamic large objects, this method returns ErrContainerMismatch if the segment is not located in the correct container below the correct prefix.

This method returns ErrSegmentInvalid if:

- a range is specified in the SegmentInfo, but it is invalid or the LargeObject is a dynamic large object (DLOs do not support ranges), or

- the SegmentInfo's Data attribute is set and any other attribute is also set (segments cannot be backed by objects and be data segments at the same time), or

- the SegmentInfo's Data attribute is set, but the LargeObject is a dynamic large objects (DLOs do not support data segments).

func (*LargeObject) Append Uses

func (lo *LargeObject) Append(contents io.Reader, segmentSizeBytes int64, opts *RequestOptions) error

Append uploads the contents of the given io.Reader as segment objects of the given segment size. (The last segment will be shorter than the segment size unless the reader yields an exact multiple of the segment size.) The reader is consumed until EOF, or until an error occurs.

If you do not have an io.Reader, but you have a []byte or string instance containing the data, wrap it in a *bytes.Reader instance like so:

var buffer []byte
lo.Append(bytes.NewReader(buffer), segmentSizeBytes)

//or...
var buffer string
lo.Append(bytes.NewReader([]byte(buffer)), segmentSizeBytes)

If segmentSizeBytes is zero, Append() defaults to the maximum file size reported by Account.Capabilities().

Calls to Append() and its low-level counterpart, AddSegment(), can be freely intermixed. AddSegment() is useful when you want to control the segments' metadata or use advanced features like range segments or data segments; see documentation over there.

This function uploads segment objects, so it may return any error that Object.Upload() returns, see documentation over there.

func (*LargeObject) NextSegmentObject Uses

func (lo *LargeObject) NextSegmentObject() *Object

NextSegmentObject suggests where to upload the next segment.

WARNING: This is a low-level function. Most callers will want to use Append(). You will only need to upload segments manually when you want to control the segments' metadata.

If the name of the current final segment ends with a counter, that counter is incremented, otherwise a counter is appended to its name. When looking for a counter in an existing segment name, the regex /[0-9]+$/ is used. For example, given:

segments := lo.segments()
lastSegmentName := segments[len(segments)-1].Name()
nextSegmentName := lo.NextSegmentObject().Name()

If lastSegmentName is "segments/archive/segment0001", then nextSegmentName is "segments/archive/segment0002". If lastSegmentName is "segments/archive/first", then nextSegmentName is "segments/archive/first0000000000000001".

However, the last segment's name will only be considered if it lies within lo.segmentContainer below lo.segmentPrefix. If that is not the case, the name of the last segment that does will be used instead.

If there are no segments yet, or if all segments are located outside the lo.segmentContainer and lo.segmentPrefix, the first segment name is chosen as lo.segmentPrefix + "0000000000000001".

func (*LargeObject) Object Uses

func (lo *LargeObject) Object() *Object

Object returns the location of this large object (where its manifest is stored).

func (*LargeObject) SegmentContainer Uses

func (lo *LargeObject) SegmentContainer() *Container

SegmentContainer returns the container in which this object's segments are stored. For static large objects, some segments may also be located in different containers.

func (*LargeObject) SegmentObjects Uses

func (lo *LargeObject) SegmentObjects() []*Object

SegmentObjects returns a list of all segment objects referenced by this large object. Note that, in general,

len(lo.SegmentObjects()) <= len(lo.Segments())

since one object may be backing multiple segments, and data segments are not backed by any object at all. No guarantee is made about the order in which objects appear in this list.

func (*LargeObject) SegmentPrefix Uses

func (lo *LargeObject) SegmentPrefix() string

SegmentPrefix returns the prefix shared by the names of all segments of this object. For static large objects, some segments may not be located in this prefix.

func (*LargeObject) Segments Uses

func (lo *LargeObject) Segments() ([]SegmentInfo, error)

Segments returns a list of all segments for this object, in order.

func (*LargeObject) Strategy Uses

func (lo *LargeObject) Strategy() LargeObjectStrategy

Strategy returns the LargeObjectStrategy used by this object.

func (*LargeObject) Truncate Uses

func (lo *LargeObject) Truncate(opts *TruncateOptions) error

Truncate removes all segments from a large object's manifest. The manifest is not written by this call, so WriteManifest() usually needs to be called afterwards.

func (*LargeObject) WriteManifest Uses

func (lo *LargeObject) WriteManifest(opts *RequestOptions) error

WriteManifest creates this large object by writing a manifest to its location using a PUT request.

For dynamic large objects, this method does not generate a PUT request if the object already exists and has the correct manifest (i.e. SegmentContainer and SegmentPrefix have not been changed).

type LargeObjectStrategy Uses

type LargeObjectStrategy int

LargeObjectStrategy enumerates segmenting strategies supported by Swift.

const (
    //StaticLargeObject is the default LargeObjectStrategy used by Schwift.
    StaticLargeObject LargeObjectStrategy = iota + 1
    //DynamicLargeObject is an older LargeObjectStrategy that is not recommended
    //for new applications because of eventual consistency problems and missing
    //support for several newer features (e.g. data segments, range specifications).
    DynamicLargeObject
)

A value of 0 for LargeObjectStrategy will instruct Schwift to choose a strategy itself. Right now, Schwift always chooses StaticLargeObject, but this behavior may change in future versions of Schwift, esp. if new strategies become available. The choice may also start to depend on the capabilities advertised by the server.

type MalformedHeaderError Uses

type MalformedHeaderError struct {
    Key        string
    ParseError error
}

MalformedHeaderError is generated when a response from Swift contains a malformed header.

func (MalformedHeaderError) Error Uses

func (e MalformedHeaderError) Error() string

Error implements the builtin/error interface.

type Object Uses

type Object struct {
    // contains filtered or unexported fields
}

Object represents a Swift object. Instances are usually obtained by traversing downwards from a container with Container.Object() or Container.Objects().

func (*Object) AsLargeObject Uses

func (o *Object) AsLargeObject() (*LargeObject, error)

AsLargeObject opens an existing large object. If the given object does not exist, or if it is not a large object, ErrNotLarge will be returned. In this case, Object.AsNewLargeObject() needs to be used instead.

func (*Object) AsNewLargeObject Uses

func (o *Object) AsNewLargeObject(sopts SegmentingOptions, topts *TruncateOptions) (*LargeObject, error)

AsNewLargeObject opens an object as a large object. SegmentingOptions are always required, see the documentation on type SegmentingOptions for details.

This function can be used regardless of whether the object exists or not. If the object exists and is a large object, this function behaves like Object.AsLargeObject() followed by Truncate(), except that segmenting options are initialized from the method's SegmentingOptions argument rather than from the existing manifest.

func (*Object) Container Uses

func (o *Object) Container() *Container

Container returns a handle to the container this object is stored in.

func (*Object) CopyTo Uses

func (o *Object) CopyTo(target *Object, opts *CopyOptions, ropts *RequestOptions) error

CopyTo copies the object on the server side using a COPY request.

A successful COPY implies target.Invalidate() since it may change the target's metadata.

func (*Object) Delete Uses

func (o *Object) Delete(opts *DeleteOptions, ropts *RequestOptions) error

Delete deletes the object using a DELETE request. To add URL parameters, pass a non-nil *RequestOptions.

This operation fails with http.StatusNotFound if the object does not exist.

A successful DELETE request implies Invalidate().

func (*Object) Download Uses

func (o *Object) Download(opts *RequestOptions) DownloadedObject

Download retrieves the object's contents using a GET request. This returns a helper object which allows you to select whether you want an io.ReadCloser for reading the object contents progressively, or whether you want the object contents collected into a byte slice or string.

reader, err := object.Download(nil).AsReadCloser()

buf, err := object.Download(nil).AsByteSlice()

str, err := object.Download(nil).AsString()

See documentation on type DownloadedObject for details.

func (*Object) Exists Uses

func (o *Object) Exists() (bool, error)

Exists checks if this object exists, potentially by issuing a HEAD request if no Headers() have been cached yet.

func (*Object) FullName Uses

func (o *Object) FullName() string

FullName returns the container name and object name joined together with a slash. This identifier is used by Swift in several places (large object manifests, symlink targets, etc.) to refer to an object within an account. For example:

obj := account.Container("docs").Object("2018-02-10/invoice.pdf")
obj.Name()     //returns      "2018-02-10/invoice.pdf"
obj.FullName() //returns "docs/2018-02-10/invoice.pdf"

func (*Object) Headers Uses

func (o *Object) Headers() (ObjectHeaders, error)

Headers returns the ObjectHeaders for this object. If the ObjectHeaders has not been cached yet, a HEAD request is issued on the object.

For symlinks, this operation returns the metadata for the target object. Use Object.SymlinkHeaders() to obtain the metadata for the symlink instead.

This operation fails with http.StatusNotFound if the object does not exist.

func (*Object) Invalidate Uses

func (o *Object) Invalidate()

Invalidate clears the internal cache of this Object instance. The next call to Headers() on this instance will issue a HEAD request on the object.

func (*Object) IsEqualTo Uses

func (o *Object) IsEqualTo(other *Object) bool

IsEqualTo returns true if both Object instances refer to the same object.

func (*Object) Name Uses

func (o *Object) Name() string

Name returns the object name. This does not parse the name in any way; if you want only the basename portion of the object name, use package path from the standard library in conjunction with this function. For example:

obj := account.Container("docs").Object("2018-02-10/invoice.pdf")
obj.Name()            //returns "2018-02-10/invoice.pdf"
path.Base(obj.Name()) //returns            "invoice.pdf"

func (*Object) SymlinkHeaders Uses

func (o *Object) SymlinkHeaders() (headers ObjectHeaders, target *Object, err error)

SymlinkHeaders is similar to Headers, but if the object is a symlink, it returns the metadata of the symlink rather than the metadata of the target. It also returns a reference to the target object.

If this object is not a symlink, Object.SymlinkHeaders() returns the same ObjectHeaders as Object.Headers(), and a nil target object.

In a nutshell, if Object.Headers() is like os.Stat(), then Object.SymlinkHeaders() is like os.Lstat().

If you do not know whether a given object is a symlink or not, it's a good idea to call Object.SymlinkHeaders() first: If the object turns out not to be a symlink, the cache for Object.Headers() has already been populated.

This operation fails with http.StatusNotFound if the object does not exist.

func (*Object) SymlinkTo Uses

func (o *Object) SymlinkTo(target *Object, opts *SymlinkOptions, ropts *RequestOptions) error

SymlinkTo creates the object as a symbolic link to another object using a PUT request. Like Object.Upload(), this method works regardless of whether the object already exists or not. Existing object contents will be overwritten by this operation.

A successful PUT request implies Invalidate() since it may change metadata.

func (*Object) TempURL Uses

func (o *Object) TempURL(key, method string, expires time.Time) (string, error)

TempURL is like Object.URL, but includes a token with a limited lifetime (as specified by the `expires` argument) that permits anonymous access to this object using the given HTTP method. This works only when the tempurl middleware is set up on the server, and if the given `key` matches one of the tempurl keys for this object's container or account.

For example, if the ReadACL both on the account and container do not permit anonymous read access (which is the default behavior):

var o *schwift.Object
...
resp, err := http.Get(o.URL())
//After this, resp.StatusCode == 401 (Unauthorized)
//because anonymous access is forbidden.

//But if the container or account has a tempurl key...
key := "supersecretkey"
hdr := NewContainerHeaders()
hdr.TempURLKey().Set(key)
c := o.Container()
err := c.Update(hdr, nil)

//...we can use it to generate temporary URLs.
url := o.TempURL(key, "GET", time.Now().Add(10 * time.Minute))
resp, err := http.Get(url)
//This time, resp.StatusCode == 200 because the URL includes a token.

func (*Object) URL Uses

func (o *Object) URL() (string, error)

URL returns the canonical URL for the object on the server. This is particularly useful when the ReadACL on the account or container is set to allow anonymous read access.

func (*Object) Update Uses

func (o *Object) Update(headers ObjectHeaders, opts *RequestOptions) error

Update updates the object's headers using a POST request. To add URL parameters, pass a non-nil *RequestOptions.

This operation fails with http.StatusNotFound if the object does not exist.

A successful POST request implies Invalidate() since it may change metadata.

func (*Object) Upload Uses

func (o *Object) Upload(content io.Reader, opts *UploadOptions, ropts *RequestOptions) error

Upload creates the object using a PUT request.

If you do not have an io.Reader, but you have a []byte or string instance containing the object, wrap it in a *bytes.Reader instance like so:

var buffer []byte
o.Upload(bytes.NewReader(buffer), opts)

//or...
var buffer string
o.Upload(bytes.NewReader([]byte(buffer)), opts)

If you have neither an io.Reader nor a []byte or string, but you have a function that generates the object's content into an io.Writer, use UploadWithWriter instead.

If the object is very large and you want to upload it in segments, use LargeObject.Append() instead. See documentation on type LargeObject for details.

If content is a *bytes.Reader or a *bytes.Buffer instance, the Content-Length and Etag request headers will be computed automatically. Otherwise, it is highly recommended that the caller set these headers (if possible) to allow the server to check the integrity of the uploaded file.

If Etag and/or Content-Length is supplied and the content does not match these parameters, http.StatusUnprocessableEntity is returned. If Etag is not supplied and cannot be computed in advance, Upload() will compute the Etag as data is read from the io.Reader, and compare the result to the Etag returned by Swift, returning ErrChecksumMismatch in case of mismatch. The object will have been uploaded at that point, so you will usually want to Delete() it.

This function can be used regardless of whether the object exists or not.

A successful PUT request implies Invalidate() since it may change metadata.

func (*Object) UploadWithWriter Uses

func (o *Object) UploadWithWriter(opts *UploadOptions, ropts *RequestOptions, callback func(io.Writer) error) error

UploadWithWriter is a variant of Upload that can be used when the object's content is generated by some function or package that takes an io.Writer instead of supplying an io.Reader. For example:

func greeting(target io.Writer, name string) error {
    _, err := fmt.Fprintf(target, "Hello %s!\n", name)
    return err
}

obj := container.Object("greeting-for-susan-and-jeffrey")
err := obj.UploadWithWriter(nil, func(w io.Writer) error {
    err := greeting(w, "Susan")
    if err == nil {
        err = greeting(w, "Jeffrey")
    }
    return err
})

If you do not need an io.Writer, always use Upload instead.

TODO rename to UploadViaWriter

type ObjectHeaders Uses

type ObjectHeaders struct {
    Headers
}

ObjectHeaders contains the headers for a schwift.Object instance.

To read and write well-known headers, use the methods on this type. To read and write arbitary headers, use the methods on the Headers supertype.

func NewObjectHeaders Uses

func NewObjectHeaders() ObjectHeaders

NewObjectHeaders creates a new ObjectHeaders instance. The return value will have the Headers attribute initialized to a non-nil map.

func (ObjectHeaders) ContentDisposition Uses

func (h ObjectHeaders) ContentDisposition() FieldString

ContentDisposition provides type-safe access to Content-Disposition headers.

func (ObjectHeaders) ContentEncoding Uses

func (h ObjectHeaders) ContentEncoding() FieldString

ContentEncoding provides type-safe access to Content-Encoding headers.

func (ObjectHeaders) ContentType Uses

func (h ObjectHeaders) ContentType() FieldString

ContentType provides type-safe access to Content-Type headers.

func (ObjectHeaders) CreatedAt Uses

func (h ObjectHeaders) CreatedAt() FieldUnixTimeReadonly

CreatedAt provides type-safe access to X-Timestamp headers.

func (ObjectHeaders) Etag Uses

func (h ObjectHeaders) Etag() FieldString

Etag provides type-safe access to Etag headers.

func (ObjectHeaders) ExpiresAt Uses

func (h ObjectHeaders) ExpiresAt() FieldUnixTime

ExpiresAt provides type-safe access to X-Delete-At headers.

func (ObjectHeaders) IsDynamicLargeObject Uses

func (h ObjectHeaders) IsDynamicLargeObject() bool

IsDynamicLargeObject returns true if this set of headers belongs to a Dynamic Large Object (DLO).

func (ObjectHeaders) IsLargeObject Uses

func (h ObjectHeaders) IsLargeObject() bool

IsLargeObject returns true if this set of headers belongs to a large object (either an SLO or a DLO).

func (ObjectHeaders) IsStaticLargeObject Uses

func (h ObjectHeaders) IsStaticLargeObject() bool

IsStaticLargeObject returns true if this set of headers belongs to a Static Large Object (SLO).

func (ObjectHeaders) Metadata Uses

func (h ObjectHeaders) Metadata() FieldMetadata

Metadata provides type-safe access to X-Object-Meta- headers.

func (ObjectHeaders) SizeBytes Uses

func (h ObjectHeaders) SizeBytes() FieldUint64

SizeBytes provides type-safe access to Content-Length headers.

func (ObjectHeaders) SymlinkTarget Uses

func (h ObjectHeaders) SymlinkTarget() FieldString

SymlinkTarget provides type-safe access to X-Symlink-Target headers.

func (ObjectHeaders) SymlinkTargetAccount Uses

func (h ObjectHeaders) SymlinkTargetAccount() FieldString

SymlinkTargetAccount provides type-safe access to X-Symlink-Target-Account headers.

func (ObjectHeaders) UpdatedAt Uses

func (h ObjectHeaders) UpdatedAt() FieldHTTPTimeReadonly

UpdatedAt provides type-safe access to Last-Modified headers.

func (ObjectHeaders) Validate Uses

func (h ObjectHeaders) Validate() error

Validate returns MalformedHeaderError if the value of any well-known header does not conform to its data type. This is called automatically by Schwift when preparing an ObjectHeaders instance from a GET/HEAD response, so you usually do not need to do it yourself. You will get the validation error from the Object method doing the request, e.g. Headers().

type ObjectInfo Uses

type ObjectInfo struct {
    Object       *Object
    SizeBytes    uint64
    ContentType  string
    Etag         string
    LastModified time.Time
    //SymlinkTarget is only set for symlinks.
    SymlinkTarget *Object
    //If the ObjectInfo refers to an actual object, then SubDirectory is empty.
    //If the ObjectInfo refers to a pseudo-directory, then SubDirectory contains
    //the path of the pseudo-directory and all other fields are nil/zero/empty.
    //Pseudo-directories will only be reported for ObjectIterator.Delimiter != "".
    SubDirectory string
}

ObjectInfo is a result type returned by ObjectIterator for detailed object listings. The metadata in this type is a subset of Object.Headers(), but since it is returned as part of the detailed object listing, it can be obtained without making additional HEAD requests on the object(s).

type ObjectIterator Uses

type ObjectIterator struct {
    Container *Container
    //When Prefix is set, only objects whose name starts with this string are
    //returned.
    Prefix string
    //When Delimiter is set, objects whose name contains this string (after the
    //prefix, if any) will be condensed into pseudo-directories in the result.
    //See documentation for Swift for details.
    Delimiter string
    //Options may contain additional headers and query parameters for the GET request.
    Options *RequestOptions
    // contains filtered or unexported fields
}

ObjectIterator iterates over the objects in a container. It is typically constructed with the Container.Objects() method. For example:

//either this...
iter := container.Objects()
iter.Prefix = "test-"
objects, err := iter.Collect()

//...or this
objects, err := schwift.ObjectIterator{
	Container: container,
	Prefix: "test-",
}.Collect()

When listing objects via a GET request on the container, you can choose to receive object names only (via the methods without the "Detailed" suffix), or object names plus some basic metadata fields (via the methods with the "Detailed" suffix). See struct ObjectInfo for which metadata is returned.

To obtain any other metadata, you can call Object.Headers() on the result object, but this will issue a separate HEAD request for each object.

Use the "Detailed" methods only when you use the extra metadata in struct ObjectInfo; detailed GET requests are more expensive than simple ones that return only object names.

Note that, when Delimiter is set, instances of *Object that you receive from the iterator may refer to a pseudo-directory instead of an actual object, in which case Exists() will return false.

func (*ObjectIterator) Collect Uses

func (i *ObjectIterator) Collect() ([]*Object, error)

Collect lists all object names matching this iterator. For large sets of objects that cannot be retrieved at once, Collect handles paging behind the scenes. The return value is always the complete set of objects.

func (*ObjectIterator) CollectDetailed Uses

func (i *ObjectIterator) CollectDetailed() ([]ObjectInfo, error)

CollectDetailed is like Collect, but includes basic metadata.

func (*ObjectIterator) Foreach Uses

func (i *ObjectIterator) Foreach(callback func(*Object) error) error

Foreach lists the object names matching this iterator and calls the callback once for every object. Iteration is aborted when a GET request fails, or when the callback returns a non-nil error.

func (*ObjectIterator) ForeachDetailed Uses

func (i *ObjectIterator) ForeachDetailed(callback func(ObjectInfo) error) error

ForeachDetailed is like Foreach, but includes basic metadata.

func (*ObjectIterator) NextPage Uses

func (i *ObjectIterator) NextPage(limit int) ([]*Object, error)

NextPage queries Swift for the next page of object names. If limit is >= 0, not more than that many object names will be returned at once. Note that the server also has a limit for how many objects to list in one request; the lower limit wins.

The end of the object listing is reached when an empty list is returned.

This method offers maximal flexibility, but most users will prefer the simpler interfaces offered by Collect() and Foreach().

func (*ObjectIterator) NextPageDetailed Uses

func (i *ObjectIterator) NextPageDetailed(limit int) ([]ObjectInfo, error)

NextPageDetailed is like NextPage, but includes basic metadata.

type Request Uses

type Request struct {
    Method        string //"GET", "HEAD", "PUT", "POST" or "DELETE"
    ContainerName string //empty for requests on accounts
    ObjectName    string //empty for requests on accounts/containers
    Options       *RequestOptions
    Body          io.Reader
    //ExpectStatusCodes can be left empty to disable this check, otherwise
    //schwift.UnexpectedStatusCodeError may be returned.
    ExpectStatusCodes []int
    //DrainResponseBody can be set if the caller is not interested in the
    //response body. This is implied for Response.StatusCode == 204.
    DrainResponseBody bool
}

Request contains the parameters that can be set in a request to the Swift API.

func (Request) Do Uses

func (r Request) Do(backend Backend) (*http.Response, error)

Do executes this request on the given Backend.

func (Request) URL Uses

func (r Request) URL(backend Backend, values url.Values) (string, error)

URL returns the full URL for this request.

type RequestOptions Uses

type RequestOptions struct {
    Headers Headers
    Values  url.Values
    Context context.Context
}

RequestOptions is used to pass additional headers and values to a request.

When preparing a RequestOptions instance with additional headers, the preferred way is to create an AccountHeaders, ContainerHeaders and ObjectHeaders instance and use the type-safe API on these types. Then use the ToOpts() method on that instance. For example:

hdr := NewObjectHeaders()
hdr.ContentType().Set("image/png")
hdr.Metadata().Set("color", "blue")
opts := hdr.ToOpts() //type *schwift.RequestOptions

type SegmentInfo Uses

type SegmentInfo struct {
    Object      *Object
    SizeBytes   uint64
    Etag        string
    RangeLength uint64
    RangeOffset int64
    //Static Large Objects support data segments that are not backed by actual
    //objects. For those kinds of segments, only the Data attribute is set and
    //all other attributes are set to their default values (esp. .Object == nil).
    //
    //Data segments can only be used for small chunks of data because the SLO
    //manifest (the list of all SegmentInfo encoded as JSON) is severely limited
    //in size (usually to 8 MiB).
    Data []byte
}

SegmentInfo describes a segment of a large object.

For .RangeLength == 0, the segment consists of all the bytes in the backing object, after skipping the first .RangeOffset bytes. The default (.RangeOffset == 0) is to include the entire contents of the backing object.

For .RangeLength > 0, the segment consists of that many bytes from the backing object, again after skipping the first .RangeOffset bytes.

However, for .RangeOffset < 0, the segment consists of .RangeLength many bytes from the *end* of the backing object. (The concrete value for .RangeOffset is disregarded.) .RangeLength must be non-zero in this case.

Sorry that specifying a range is that involved. I was just following orders ^W RFC 7233, section 3.1 here.

type SegmentingOptions Uses

type SegmentingOptions struct {
    Strategy         LargeObjectStrategy
    SegmentContainer *Container
    SegmentPrefix    string
}

SegmentingOptions describes how an object is segmented. It is passed to Object.AsNewLargeObject().

If Strategy is not set, a reasonable strategy is chosen; see documentation on LargeObjectStrategy for details.

SegmentContainer must not be nil. A value of nil will cause Schwift to panic. If the SegmentContainer is not in the same account as the large object, ErrAccountMismatch will be returned by Schwift.

If SegmentPrefix is empty, a reasonable default will be computed by Object.AsNewLargeObject(), using the format "<object-name>/<strategy>/<timestamp>", where strategy is either "slo" or "dlo".

type StoragePolicySpec Uses

type StoragePolicySpec struct {
    Name    string `json:"name"`
    Aliases string `json:"aliases"`
    Default bool   `json:"default"`
}

StoragePolicySpec is a subtype that appears in struct Capabilities.

type SymlinkOptions Uses

type SymlinkOptions struct {
    //When overwriting a large object, delete its segments. This will cause
    //SymlinkTo() to call into BulkDelete(), so a BulkError may be returned.
    DeleteSegments bool
}

SymlinkOptions invokes advanced behavior in the Object.SymlinkTo() method.

type TruncateOptions Uses

type TruncateOptions struct {
    //When truncating a large object's manifest, delete its segments.
    //This will cause Truncate() to call into BulkDelete(), so a BulkError may be
    //returned. If this is false, the segments will not be deleted even though
    //they may not be referenced by any large object anymore.
    DeleteSegments bool
}

TruncateOptions contains options that can be passed to LargeObject.Truncate() and Object.AsNewLargeObject().

type UnexpectedStatusCodeError Uses

type UnexpectedStatusCodeError struct {
    ExpectedStatusCodes []int
    ActualResponse      *http.Response
    ResponseBody        []byte
}

UnexpectedStatusCodeError is generated when a request to Swift does not yield a response with the expected successful status code. The actual status code can be checked with the Is() function; see documentation over there.

func (UnexpectedStatusCodeError) Error Uses

func (e UnexpectedStatusCodeError) Error() string

Error implements the builtin/error interface.

type UploadOptions Uses

type UploadOptions struct {
    //When overwriting a large object, delete its segments. This will cause
    //Upload() to call into BulkDelete(), so a BulkError may be returned.
    DeleteSegments bool
}

UploadOptions invokes advanced behavior in the Object.Upload() method.

Directories

PathSynopsis
capabilitiesPackage capabilities contains feature switches that Schwift's unit tests can set to exercise certain fallback code paths in Schwift that they could not trigger otherwise.
gopherschwiftPackage gopherschwift contains a Gophercloud backend for Schwift.
utilCommand gocovcat combines multiple go cover runs, and prints the result on stdout.

Package schwift imports 24 packages (graph) and is imported by 2 packages. Updated 2018-09-14. Refresh now. Tools for package owners.