Update Object Storage API Reference to point to wadl in api-site

The point of this change is to ensure that
these two docs are in sync and are complete with regards
to the descriptions of each method and their request
and response parameters:
http://api.openstack.org/api-ref-objectstorage.html
(API Reference page for Object Storage)
http://docs.openstack.org/api/openstack-object-storage/1.0/content/
(API Reference (or spec) for Object Storage)
In addition, the current documents don’t describe ACLs, FormPOST, TempURLs,
StaticWeb, Bulk Upload, Bulk Delete, the OPTIONS operation
(though this is implicit in CORS support) and maybe a couple of other things.
Also, validate all code examples.

Co-Author: Donagh McCabe

Closes-Bug: #1187119
Closes-Bug: #1214139

Change-Id: I94054b046a94260ba8825bdb42439adfcaf9fdce
author: diane fleming
This commit is contained in:
Diane Fleming
2013-12-31 14:05:11 -06:00
parent af2df10d8f
commit 56d0785df7
34 changed files with 2884 additions and 2216 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,30 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book [ <!DOCTYPE book [
<!-- Some useful entities borrowed from HTML --> <!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
<!ENTITY CHECK '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Check_mark_23x20_02.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
<!ENTITY ARROW '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Arrow_east.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
]> ]>
<book xmlns="http://docbook.org/ns/docbook" <book xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
@@ -230,7 +206,7 @@
</info> </info>
<!-- Chapters are referred from the book file through these include statements. You can add additional chapters using these types of statements. --> <!-- Chapters are referred from the book file through these include statements. You can add additional chapters using these types of statements. -->
<xi:include href="preface.xml"/> <xi:include href="preface.xml"/>
<xi:include href="ch_object-api-general.xml"/> <xi:include href="ch_object-api-concepts.xml"/>
<xi:include href="ch_object-api-storage-services.xml"/> <xi:include href="ch_object-api-operations.xml"/>
<xi:include href="ch_object-api-troubleshooting-examples.xml"/> <xi:include href="ch_object-api-examples.xml"/>
</book> </book>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="ch_object-storage-dev-general-api">
<title>Object Storage API concepts and features</title>
<para>For an introduction to OpenStack Object Storage, see <link
xlink:href="http://docs.openstack.org/admin-guide-cloud/content/ch_admin-openstack-object-storage.html"
>Object Storage</link> in the <citetitle>OpenStack Cloud
Administrator Guide</citetitle>.</para>
<xi:include href="section_object_api_overview.xml"/>
<xi:include href="section_object_api_authentication.xml"/>
<xi:include href="section_object_api_response_formats.xml"/>
<xi:include href="section_object_api_versioning.xml"/>
<xi:include href="section_large_object_creation.xml"/>
<xi:include href="section_expire_objects.xml"/>
<xi:include href="section_object_api_pseudo_hier_folders.xml"/>
<xi:include href="section_object_api_large_lists.xml"/>
<xi:include href="section_cors_headers.xml"/>
<xi:include href="section_file_compression.xml"/>
<xi:include href="section_browser_bypass.xml"/>
<xi:include href="section_object_api_archive_auto_extract.xml"/>
<xi:include href="section_object_api_bulk.xml"/>
</chapter>

View File

@@ -0,0 +1,893 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter [
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
]>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="examples">
<?dbhtml stop-chunking?>
<title>Object Storage API examples</title>
<para>This section introduces the cURL command language and
demonstrates how to use cURL commands to make Object Storage
API calls.</para>
<xi:include href="section_curl_how_curl_works.xml"/>
<section xml:id="auth_examples">
<title>Authenticate</title>
<para>The following examples show you how to authenticate with
the Identity Service or Tempauth.</para>
<section xml:id="get_auth_token_keystone">
<title>Authenticate with the Identity Service</title>
<para>This section provides a overview of the
authentication process. For request and response
details, see <link
xlink:href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_.html"
>Authenticate</link> in the <citetitle>OpenStack
Identity Service API v2.0
Reference</citetitle>.</para>
<procedure>
<title>To authentication with the Identity
Service</title>
<step>
<para>Send your credentials and a tenant ID or
tenant name to the Identity Service.</para>
<para>The response includes an authentication
token and service catalog.</para>
</step>
<step>
<para>Select the service catalog entry where
<literal>type</literal> is
<literal>object-store</literal>. Use the
<literal>publicURL</literal> endpoint,
which contains a URL with the full path to the
Object Storage account. The URL has the
format,
<uri>https://<replaceable>hostname</replaceable>/v1/<replaceable>account</replaceable></uri>.</para>
</step>
</procedure>
</section>
<section xml:id="get_auth_token_tempauth">
<title>Authenticate with Tempauth</title>
<procedure>
<title>To authenticate with Tempauth</title>
<step>
<para>Supply your user name and API access key in
headers, as follows:</para>
<itemizedlist>
<listitem>
<para><literal>X-Auth-User</literal>
header. Specify your Object Storage
user name.</para>
</listitem>
<listitem>
<para>
<literal>X-Auth-Key</literal> header.
Specify your access key..</para>
</listitem>
</itemizedlist>
<para>The following example shows a sample
request:</para>
<screen><userinput>GET /v1/auth HTTP/1.1
Host: swift.yourcloud.com
X-Auth-User: jdoe
X-Auth-Key: jdoepassword</userinput></screen>
</step>
<step>
<para>When authentication succeeds, you receive a
<returnvalue>204</returnvalue>
<errortext>No Content</errortext> status code.
Any
<returnvalue>2<replaceable>nn</replaceable></returnvalue>
response indicates success.</para>
<para>The <literal>X-Auth-Token</literal> response
header contains the authentication token. The
<literal>X-Storage-Url</literal> response
header contains a URL that includes a full
path to the Object Storage account. The URL
has the format,
<uri>https://<replaceable>hostname</replaceable>/v1/<replaceable>account</replaceable></uri>.</para>
<para>The following example shows a sample
response:</para>
<screen><computeroutput>HTTP/1.1 204 No Content
Date: Mon, 12 Nov 2010 15:32:21
Server: Apache
X-Storage-Url: https://swift.yourcloud.com/v1/AUTH_123456789_12345
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Length: 0
Content-Type: text/plain; charset=UTF-8</computeroutput></screen>
</step>
</procedure>
</section>
</section>
<section xml:id="accounts">
<title>Account services</title>
<section xml:id="determining-storage-usage">
<title>Determine storage usage</title>
<para>You can send a &HEAD; request to the storage service
to determine how much data you have stored in the
system and the number of containers that you are
using.</para>
<para>Use the <code>-X</code> switch to specify the HTTP
method. Use the <code>-i</code> switch to send the
HTTP response headers to terminal output
(stdout).</para>
<para>Also, you must include the authentication token in
the <literal>X-Auth-Token</literal> header.</para>
<screen><prompt>#</prompt> <userinput>curl X HEAD -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343</userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Date: Thu, 09 Jul 2009 15:38:14 GMT
Server: Apache
X-Account-Container-Count: 22
X-Account-Bytes-Used: 9891628380
Content-Type: text/plain</computeroutput></screen>
<para>The <literal>X-Account-Container-Count</literal>
response header shows the number of containers in this
storage account. The
<literal>X-Account-Bytes-Used</literal> response
header shows the total bytes stored for the entire
account.</para>
</section>
<section xml:id="listing-and-creating-storage-containers">
<title>List containers</title>
<para>To list containers and return the output in JSON
format:</para>
<screen><prompt>#</prompt> <userinput>curl -i http://23.253.72.207:8080/v1/$account?format=json \
-X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 127
Accept-Ranges: bytes
X-Timestamp: 1389453423.35964
X-Account-Bytes-Used: 0
X-Account-Container-Count: 3
Content-Type: application/json; charset=utf-8
X-Account-Object-Count: 0
X-Trans-Id: tx903fa2ee82ea4709bc1a1-0052d301b1
Date: Sun, 12 Jan 2014 20:57:21 GMT</computeroutput></screen>
<programlisting language="json">[
{
"count":0,
"bytes":0,
"name":"diane"
},
{
"count":0,
"bytes":0,
"name":"joe"
},
{
"count":0,
"bytes":0,
"name":"sarah"
}
]</programlisting>
<para>To list containers and return the output in XML
format:</para>
<screen><prompt>#</prompt> <userinput>curl -i http://23.253.72.207:8080/v1/$account?format=xml \
-X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 324
Accept-Ranges: bytes
X-Timestamp: 1389453423.35964
X-Account-Bytes-Used: 0
X-Account-Container-Count: 3
Content-Type: application/xml; charset=utf-8
X-Account-Object-Count: 0
X-Trans-Id: txfa1780ad82394ae289994-0052d302ee
Date: Sun, 12 Jan 2014 21:02:38 GMT</computeroutput></screen>
<programlisting language="xml"><xi:include parse="text" href="samples/container-get-details-resp.xml"/></programlisting>
</section>
</section>
<section xml:id="containers">
<title>Container services</title>
<section xml:id="special-metadata-acls">
<title>Special metadata: container ACLs</title>
<para>A particularly important metadata element for
containers is X-Container-Read, which establishes the
ACL permissions on who can read objects in the
container. Prior to being set, the ACL logic default
to only be accessible to someone with a valid
X-Auth-Token for the account in question. Doing a
simple listing of a container shows us the absence of
X-Container-Read in this default situation:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</userinput>
<computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx3aa52e951fc64b63bc1fda27902b9bd3
Content-Length: 0
Date: Tue, 15 Nov 2011 03:29:22 GMT</computeroutput></screen>
<para>Now set the <literal>X-Container-Read</literal>
header. For a full explanation of valid values, see
<link
xlink:href="http://swift.openstack.org/misc.html#acls"
>
http://swift.openstack.org/misc.html#acls</link>.
Enable read access and listing access to
anybody:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-H "X-Container-Read: .r:*,.rlistings" \
https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</userinput><computeroutput>HTTP/1.1 202 Accepted
Content-Length: 58
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txf2befb56b1854a50995f710f2db48089
Date: Tue, 15 Nov 2011 03:33:16 GMT
202 Accepted
The request is accepted for processing.</computeroutput></screen>
<para>To see the metadata change, do a listing
again:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</userinput>
<computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: txb40eb86d949345f7bc66b01e8b63c3a5
Content-Length: 0
Date: Tue, 15 Nov 2011 03:33:36 GMT</computeroutput></screen>
<para>The side effect of giving anybody read access is
that any object in the container is now accessible
from a browser simply by entering the X-Storage-URL
used throughout the session and append the object
name. For example:</para>
<para>https://storage.swiftdrive.com/v1/CF_xer7_343/jerry/cereal.jpg</para>
<para>would be the URL of an object named "cereal.jpg" in
the container "jerry" that has been made publicly
accessible using this method.</para>
</section>
<section xml:id="create_containers">
<title>Create a container</title>
<para>So, you take the X-Auth-Token obtained from the
authentication operation, pass it as a header value,
execute the operation against the URL obtained from
the authentication operation, and force the GET verb
with the -X switch. What you get back tells you there
aren't any containers.</para>
<para>Next, let's create a container and then do the
listing again:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/george</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 18
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txb25576385284476d9fa6c73835f21650
Date: Mon, 07 Nov 2011 17:44:20 GMT
201 Created</computeroutput></screen>
<para>Append the container name to the URL and force the
&PUT; verb. That creates a container, which you see
when you do a listing:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 1
Accept-Ranges: bytes
Content-Length: 7
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txaedd6b080626453399c9f5febbddb73b
Date: Mon, 07 Nov 2011 17:44:23 GMT
george</computeroutput></screen>
<para>You may have noticed the account metadata that comes
back from the listing call. As you'd guess, it'll tell
you how many objects you have, how much space you are
using, and how many containers you are using.</para>
</section>
<section xml:id="large_list_containers_example">
<title>Page through large lists of containers</title>
<para>For a list of five container names, if you specify a
<parameter>limit</parameter> of two, two items are
returned. You can assume there are more names to list,
so make another request with a
<parameter>marker</parameter> of the last item
returned.</para>
<para>For example, assume the following list of container
names:</para>
<literallayout class="monospaced">apples
bananas
kiwis
oranges
pears</literallayout>
<procedure>
<title>To page through large lists of
containers</title>
<step>
<para>Use a <parameter>limit</parameter> of
two:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>?limit=2
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>apples
bananas</computeroutput></screen>
<para>Because two container names are returned,
there are more names to list.</para>
</step>
<step>
<para>Make another request with a
<parameter>marker</parameter> parameter
set to the name of the last item
returned:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>?limit=2&amp;marker=bananas
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>kiwis
oranges</computeroutput></screen>
<para>Again, two items are returned, and there
might be more.</para>
</step>
<step>
<para>Make another request with a
<parameter>marker</parameter> of the last
item returned:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>?limit=2&amp;marker=oranges
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>pears</computeroutput></screen>
<para>You now receive a one-item response, which
is fewer than the <parameter>limit</parameter>
number of names. This indicates that this is
the end of the list.</para>
</step>
<step>
<para>Use the <code>end_marker</code> parameter to
limit the result set to object names that are
less than the <code>end_marker</code>
parameter value:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>/?end_marker=oranges
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>apples
bananas
kiwis</computeroutput></screen>
</step>
</procedure>
</section>
<section xml:id="retrieve-copy-retrieve-objects">
<title>Get, copy, and delete objects</title>
<para>Now, retrieve an object that you previously
uploaded. First, remove the local copy:</para>
<screen><prompt>#</prompt> <userinput>ls -l</userinput>
<computeroutput>total 504
-rw-r--r--@ 1 petecj2 staff 44765 Nov 7 14:49 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
<screen><prompt>#</prompt> <interfacename>rm JingleRocky.jpg</interfacename>
<prompt>#</prompt> <userinput>ls -l</userinput>
<computeroutput>total 416
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput> </screen>
<para>Be sure not to use -i switch here because you want
the raw data, which you pipe to a file:</para>
<screen><prompt>#</prompt> <userinput>curl X GET \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg > JingleRocky.jpg</userinput>
<computeroutput>$ ls -l
total 504
-rw-r--r-- 1 petecj2 staff 44765 Nov 7 15:11 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
<para>Next, Object Storage provides a facility to copy
objects from one container to another entirely on the
server side. To do this, you do a &PUT; with the
destination container and new object name while
passing a special X-Copy-From header and a
Content-Length of zero:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-H "X-Copy-From: /dogs/JingleRocky.jpg" \
-H "Content-Length: 0" \
https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/JingleRocky.jpg</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
X-Copied-From: dogs/JingleRocky.jpg
Last-Modified: Mon, 07 Nov 2011 23:23:53 GMT
X-Trans-Id: tx244cd14df1b94d8c91ec5dcf8c5f9da4
Date: Mon, 07 Nov 2011 23:23:54 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
<para>You can then confirm the new location of the object.
To do this, you do a GET with the destination
container to see the listing of the object:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 1
X-Container-Bytes-Used: 44765
Accept-Ranges: bytes
Content-Length: 16
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx46986b4a09b34790924fd43842b2b0dd
Date: Mon, 07 Nov 2011 23:24:05 GMT
JingleRocky.jpg</computeroutput></screen>
<para>To delete an object from its container, simply use
the DELETE verb:</para>
<screen><prompt>#</prompt> <userinput>curl X DELETE -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/JingleRocky.jpg</userinput>
<computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txd45f04422b034e6f8447de400b78cbf3
Date: Mon, 07 Nov 2011 23:32:39 GMT</computeroutput></screen>
<para>Confirming the deletion by doing a container
listing:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/</userinput>
<computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: txc9b43bf4d896405eb9a88ca468bf7b2d
Content-Length: 0
Date: Mon, 07 Nov 2011 23:32:41 GMT</computeroutput></screen>
</section>
<section xml:id="large_list_objects_example">
<title>Page through large lists of objects</title>
<para>For a list of five object names, if you specify a
<parameter>limit</parameter> of two, two items are
returned. You can assume there are more names to list,
so make another request with a
<parameter>marker</parameter> of the last item
returned.</para>
<para>For example, assume the following list of
objects:</para>
<literallayout class="monospaced">gala
grannysmith
honeycrisp
jonagold
reddelicious</literallayout>
<procedure>
<title>To page through large lists of objects</title>
<step>
<para>Use a <parameter>limit</parameter> of
two:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>/&lt;container>?limit=2
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>gala
grannysmith</computeroutput></screen>
<para>Because two object names are returned, there
are more names to list.</para>
</step>
<step>
<para>Make another request with a
<parameter>marker</parameter> parameter
set to the name of the last item
returned:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>/&lt;container>?limit=2&amp;marker=grannysmith
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>honeycrisp
jonagold</computeroutput></screen>
<para>Again, two items are returned, and there
might be more.</para>
</step>
<step>
<para>Make another request with a
<parameter>marker</parameter> of the last
item returned:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>/&lt;container>?limit=2&amp;marker=jonagold
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>reddelicious</computeroutput></screen>
<para>The list contains one name, which is fewer
than the <parameter>limit</parameter> number
of names. This indicates that this is the end
of the list.</para>
</step>
<step>
<para>Use the <code>end_marker</code> parameter to
limit the result set to object names that are
less than the <code>end_marker</code>
parameter value:</para>
<screen><userinput>GET /&lt;api version>/&lt;account>/&lt;container>?end_marker=jonagold
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb</userinput></screen>
<screen><computeroutput>gala
grannysmith
honeycrisp</computeroutput></screen>
</step>
</procedure>
</section>
<section xml:id="container-metadata-and-delete-containers">
<title>Get container metadata and delete
containers</title>
<para>You can get at container metadata directly simply by
appending the name of the container to a HEAD
request:</para>
<screen><prompt>#</prompt> <userinput>curl X HEAD -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</userinput>
<computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx3dd984f9482341dd97546e9d49d65e90
Content-Length: 0
Date: Mon, 07 Nov 2011 20:39:41 GMT</computeroutput> </screen>
<para>Not very exciting without any objects in the
container, but you get the idea. While you cannot
update or delete container metadata, you can delete a
container:</para>
<screen><prompt>#</prompt> <userinput>curl X DELETE -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/george</userinput>
<computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx3fa3857f266f44319d9b8f4bf7ce7fc8
Date: Mon, 07 Nov 2011 20:42:58 GMT</computeroutput></screen>
<para>Then let's confirm the delete by listing the
containers again:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 4
Accept-Ranges: bytes
Content-Length: 24
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx2475741852b849ce9403e382fe3f8015
Date: Mon, 07 Nov 2011 20:43:08 GMT
cosmo
dogs
elaine
jerry</computeroutput></screen>
</section>
</section>
<section xml:id="objects">
<title>Object services</title>
<section xml:id="creating-objects">
<title>Create objects</title>
<para>Enough with containers already, let's start to
upload some objects. Suppose you had a local directory
full of dog pictures:</para>
<screen><prompt>#</prompt> <userinput>ls -l</userinput>
<computeroutput>total 504
-rw-r--r--@ 1 petecj2 staff 44765 Nov 7 14:49 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
<para>To put one of them in a container called "dogs" with
cURL, you'd do this:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-T JingleRocky.jpg \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
Last-Modified: Mon, 07 Nov 2011 22:51:29 GMT
X-Trans-Id: txd131cc897c78403daf5fad010d4d7152
Date: Mon, 07 Nov 2011 22:51:30 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
<para>The name of the object comes from whatever you
append to the URL path beyond the container name. The
-T switch lets you name a file to push with the
operation as the request body. Confirm the upload by
checking the container again:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 1
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 44765
Accept-Ranges: bytes
Content-Length: 16
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx83be89d4e1a34eacbfeebcdfc7a7f2e7
Date: Mon, 07 Nov 2011 22:56:25 GMT
JingleRocky.jpg</computeroutput></screen>
<para>Notice that the container metadata now reflects the
number of objects and the bytes match what you saw
when you did the directory listing. After uploading
the other two similarly, you get a full object
listing:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i -H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 3
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 252732
Accept-Ranges: bytes
Content-Length: 53
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txae17dfa78da64117aaf07585a1b02115
Date: Mon, 07 Nov 2011 23:00:56 GMT
JingleRocky.jpg
RockyAndBuster.jpg
SittingBuster.jpg</computeroutput></screen>
</section>
<section xml:id="create_static_large_objects">
<title>Create static large objects</title>
<para>Creation of a static large object is done in several
steps. First, divide the content into pieces and
upload each piece into a segment object. Then, create
a manifest object. In this example, you place the
segment objects into the "segments" container and the
manifest object into the "images" container. You are
not required to do this, but using a dedicated
container for segment objects is convenient.</para>
<para>Assuming you have already divided the image into
three files, you can upload them. You have removed
non-essential response headers so you can see the
important details.</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i -H "X-Auth-Token: 12345" -T ./piece1 https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-one</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 4000000
Etag: f7365c1419b4f349592c00bd0cfb9b9a</computeroutput></screen>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i -H "X-Auth-Token: 12345" -T ./piece2 https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-two</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 2000000
Etag: ad81e97b10e870613aecb5ced52adbaa</computeroutput></screen>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i -H "X-Auth-Token: 12345" -T ./piece3 https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-three</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 1000
Etag: 00b046c9d74c3e8f93b320c5e5fdc2c3</computeroutput></screen>
<para>At this stage, you can create the manifest listing.
Notice that the size and ETag are copied from the
previous uploads. Create a file called
<code>manifest.json</code> with the following
content:</para>
<programlisting language="json">
[
{
"path": "segments/terrier-jpg-one",
"etag": "f7365c1419b4f349592c00bd0cfb9b9a",
"size_bytes": 4000000
},
{
"path": "segments/terrier-jpg-two",
"etag": "ad81e97b10e870613aecb5ced52adbaa",
"size_bytes": 2000000
},
"path": "segments/terrier-jpg-three",
"etag": "00b046c9d74c3e8f93b320c5e5fdc2c3",
"size_bytes": 1000
{
}
]</programlisting>
<para>The final operation is to upload this content into a
manifest object. To indicate that this is a manifest
object, you need to specify the
<code>?multipart-manifest=put</code> query
string.</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i -H "X-Auth-Token: 12345" -T ./manifest.json https://storage.swiftdrive.com/v1/CF_xer7_343/images/terrier-jpg?multipart-manifest=put</userinput></screen>
<para>Now, examine the static large object. Notice that
the size is the total size of all the segments.</para>
<screen><prompt>#</prompt> <userinput>curl X HEAD -i -H "X-Auth-Token: 12345" https://storage.swiftdrive.com/v1/CF_xer7_343/images/terrier-jpg</userinput>
<computeroutput>HTTP/1.1 200 OK
Content-Length: 6001000
Etag: "0c922c37f915efb1c9b97e6328b3e660"
</computeroutput></screen>
</section>
<section xml:id="object-metadata">
<title>Object metadata</title>
<para>Objects can have whatever metadata keys/values you
choose. Simply POST an HTTP Header to the object in
the form of X-Object-Meta-&lt;key>: &lt;value>. Like
this:</para>
<screen><prompt>#</prompt> <userinput>curl X POST -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-H "X-Object-Meta-Breed: Terrier pit bull mix"" \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</userinput>
<computeroutput>&lt;html>
&lt;head>
&lt;title>202 Accepted&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>202 Accepted&lt;/h1>
The request is accepted for processing.&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
<para>And then read the object metadata with a HEAD on the
object path:</para>
<screen><prompt>#</prompt> <userinput>curl X HEAD -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</userinput>
<computeroutput>
HTTP/1.1 200 OK
X-Object-Meta-Breed: Terrier pit bull mix
Last-Modified: Tue, 08 Nov 2011 01:26:49 GMT
Etag: f7d40eceffdd9c2ecab226105737b2a6
Accept-Ranges: bytes
Content-Length: 44765
Content-Type: image/jpeg
X-Trans-Id: txa8bff9ad7ef844829103c1f9b8c20781
Date: Tue, 08 Nov 2011 01:29:35 GMT
</computeroutput></screen>
</section>
</section>
<!-- <section xml:id="folders-directories">
<title>Pseudo-hierarchical folders/directories</title>
<para>In most storage systems, you
have the ability to create custom hierarchies of files so
that you can better organize them. On its surface, Object
Storage only gives you one level of hierarchy in the form
of containers. However, it turns out that you can get
creative with naming your objects to give yourself the
same effect as having hierarchical containers.</para>
<para>Let's start with a fresh container without any objects
in it:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 18
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txc78254a41b374b6ea10590d90874f769
Date: Wed, 16 Nov 2011 00:06:22 GMT
201 Created
</computeroutput></screen>
<para>Now list the new container:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos</userinput>
<computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx49112200f7934c2bab1de3ae103c368e
Content-Length: 0
Date: Wed, 16 Nov 2011 00:06:26 GMT
</computeroutput></screen>
<para>Next, add an object but prefix the name with the
hierarchy desired:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-T JingleRocky.jpg \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos/terriers/JingleRocky.jpg</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
Last-Modified: Wed, 16 Nov 2011 00:09:18 GMT
X-Trans-Id: txe34fdf2704f044e3a7102256386b1cb7
Date: Wed, 16 Nov 2011 00:09:19 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html>
</computeroutput></screen>
<para>Do it again with a different object and prefix:</para>
<screen><prompt>#</prompt> <userinput>curl X &PUT; -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
-T SittingBuster.jpg \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos/chihuahuas/SittingBuster.jpg</userinput>
<computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: e692e744c7180ee368166a24f1a2fa9b
Last-Modified: Wed, 16 Nov 2011 00:52:25 GMT
X-Trans-Id: txe229d03af5ea4d2ea1071def213c3f02
Date: Wed, 16 Nov 2011 00:52:25 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html>
</computeroutput></screen>
<para>Now list the container, revealing the prefixes:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 54
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx8544a17e8b1e4da693145fb5f2e6db43
Date: Wed, 16 Nov 2011 00:53:43 GMT
chihuahuas/SittingBuster.jpg
terriers/JingleRocky.jpg
</computeroutput></screen>
<para>If you want to perform hierarchical listings with the
prefixes in place, you can use the "path" query string
variable:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos?path=terriers</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 25
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx3f1b9575d4de4a7d97ba3f9ad81923cc
Date: Wed, 16 Nov 2011 00:55:12 GMT
terriers/JingleRocky.jpg
</computeroutput></screen>
<para>If you wanted to see what prefixes were in place, you
can use the "delimiter" query string variable to
distinguish prefix paths from object names:</para>
<screen><prompt>#</prompt> <userinput>curl X GET -i \
-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae" \
https://storage.swiftdrive.com/v1/CF_xer7_343/photos?delimiter=/</userinput>
<computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 22
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx7222a3dd73fe44b888db4e58cc647d1e
Date: Wed, 16 Nov 2011 00:57:40 GMT
chihuahuas/
terriers/</computeroutput></screen>
<para>Using these in combination allows you to discover
directories within a particular path and then further
drill down based on the results.</para>
</section>-->
<xi:include href="section_object-api-create-website.xml"/>
</chapter>

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="api-operations" role="api-reference">
<title>Object Storage API operations</title>
<para>Manages the accounts, containers, and objects in the Object
Storage system.</para>
<para>For a complete description of HTTP 1.1 header definitions, see
<link
xlink:href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14"
>Header Field Definitions</link>.</para>
<section xml:id="run_curl_commands">
<title>Environment variables required to run examples</title>
<para>To run the cURL command examples for the Object Storage API
requests, set these environment variables:</para>
<itemizedlist>
<listitem>
<para><literal>publicURL</literal>. The public URL that is the
HTTP endpoint from where you can access Object Storage. It
includes the Object Storage API version number and your
account name. For example,
<code>https://23.253.72.207/v1/my_account</code>.</para>
</listitem>
<listitem>
<para><literal>token</literal>. The authentication token for
Object Storage.</para>
</listitem>
</itemizedlist>
<para>To obtain these values, run the <command>swift stat
-v</command> command. </para>
<para>As shown in this example, the public URL appears in the
<literal>StorageURL</literal> field, and the token appears in
the <literal>Auth Token</literal> field:</para>
<programlisting>StorageURL: https://23.253.72.207/v1/my_account
Auth Token: {token}
Account: my_account
Containers: 2
Objects: 3
Bytes: 47
Meta Book: MobyDick
X-Timestamp: 1389453423.35964
X-Trans-Id: txee55498935404a2caad89-0052dd3b77
Content-Type: text/plain; charset=utf-8
Accept-Ranges: bytes</programlisting>
</section>
<section xml:id="storage_account_services">
<title>Accounts</title>
<para>Lists containers for a specified account. Creates, updates,
and deletes account metadata. Shows account metadata.</para>
<wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<wadl:resource
href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#account">
<wadl:method href="#showAccountDetails"/>
<wadl:method href="#updateAccountMeta"/>
<wadl:method href="#showAccountMeta"/>
</wadl:resource>
</wadl:resources>
</section>
<section xml:id="storage_container_services">
<title>Containers</title>
<para>Lists objects in a specified container. Creates, shows
details for, and deletes containers. Creates, updates, shows,
and deletes container metadata.</para>
<wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<wadl:resource
href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#container">
<wadl:method href="#showContainerDetails"/>
<wadl:method href="#createContainer"/>
<wadl:method href="#deleteContainer"/>
<wadl:method href="#updateContainerMeta"/>
<wadl:method href="#showContainerMeta"/>
</wadl:resource>
</wadl:resources>
</section>
<section xml:id="storage_object_services">
<title>Objects</title>
<para>Creates, replaces, shows details for, and deletes objects.
Copies objects with another object with a new or different name.
Updates object metadata.</para>
<wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<wadl:resource
href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#object">
<wadl:method href="#getObject"/>
<wadl:method href="#createOrReplaceObject"/>
<wadl:method href="#copyObject"/>
<wadl:method href="#deleteObject"/>
<wadl:method href="#showObjectMeta"/>
<wadl:method href="#updateObjectMeta"/>
</wadl:resource>
</wadl:resources>
</section>
</chapter>

View File

@@ -1,82 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY COPY '<command xmlns="http://docbook.org/ns/docbook">COPY</command>'>
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
<!ENTITY CHECK '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Check_mark_23x20_02.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
<!ENTITY ARROW '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Arrow_east.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
]>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="ch_object-storage-dev-api-storage">
<title>API Operations for Storage Services</title>
<para>Use the ReST API to interact with the storage component of
OpenStack Object Storage. All requests are directed to the host
and URL described in the <code>X-Storage-Url</code> HTTP header
obtained during successful authentication.</para>
<para>Review the following requirements for using storage
services:</para>
<itemizedlist>
<listitem>
<para>Container names cannot exceed 256 bytes and cannot contain
the <literal>/</literal> character.</para>
</listitem>
<listitem>
<para>Object names cannot exceed 1024 bytes, and have no
character restrictions.</para>
</listitem>
<listitem>
<para>Object and container names must be UTF-8 encoded and then
URL-encoded to interact with the ReST API.</para>
</listitem>
</itemizedlist>
<para><!--<info>Added paragraph to forecast info structure -\- dsh -2012-03-09 </info>-->The
following sections describe the actions that you can perform in
the storage system.</para>
<itemizedlist>
<listitem>
<para><xref linkend="storage-account-services"/>. Actions that
you can perform at the account level of the storage system.
</para>
</listitem>
<listitem>
<para><xref linkend="storage-container-services"/>. Actions that
you can perform on containers.</para>
</listitem>
<listitem>
<para><xref linkend="Create_Static_Website-dle4000"/>. How to
use your swift account to create a static website.</para>
</listitem>
<listitem>
<para><xref linkend="storage-object-services"/>. Actions that
you can perform on objects.</para>
</listitem>
</itemizedlist>
<xi:include href="section_object-api-storage_account_svc.xml"/>
<xi:include href="section_object-api-storage-container-svc.xml"/>
<xi:include href="section_object-api-create-website.xml"/>
<xi:include href="section_object-api-storage-object-svc.xml"/>
</chapter>

View File

@@ -1,993 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
<!ENTITY CHECK '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Check_mark_23x20_02.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
<!ENTITY ARROW '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Arrow_east.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
]>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="ch_object-storage-dev-troubleshooting">
<title>Troubleshooting and Examples</title>
<para>This section introduces a command-line utility, cURL, and
demonstrates interacting with the ReST interfaces through that
utility.</para>
<section xml:id="using-curl-cli">
<title>Using cURL</title>
<para>cURL is a command-line tool which is available on most
UNIX®-like environments and Mac OS X® and can be
downloaded for Windows®. For more information on cURL,
visit <link xlink:href="http://curl.haxx.se/"
>http://curl.haxx.se/</link>.</para>
<para>cURL allows you to transmit and receive HTTP requests
and responses from the command-line or from within a shell
script. This makes it possible to work with the ReST API
directly without using one of the client APIs.</para>
<para>The following cURL command-line options will be
used</para>
<variablelist>
<title>cURL Command-Line Options</title>
<varlistentry>
<term><option>-X METHOD</option></term>
<listitem>
<para>Specify the HTTP method to request (&HEAD;,
&GET;, etc.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-i</option></term>
<listitem>
<para>Dump HTTP response headers to stdout.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-H HEADER</option></term>
<listitem>
<para>Specify an HTTP header in the
request.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="authentication-examples-curl">
<title>Authentication</title>
<para>To use the ReST API, you must obtain a authorization
token, which you pass to each request in the
<code>X-Auth-Token</code> header. The following
example demonstrates how to use cURL to obtain the
authorization token and the URL of the storage
system.</para>
<example>
<title>cURL Authenticate</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>-i</option> \
<option>-H "X-Auth-Key: jdoesecretpassword"</option> \
<option>-H "X-Auth-User: jdoe"</option> \
<uri>https://auth.api.yourcloud.com/v1.0</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Date: Thu, 09 Jul 2009 15:31:39 GMT
Server: Apache/2.2.3
X-Storage-Url: https://storage.swiftdrive.com/v1/CF_xer7_343
X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae
Content-Length: 0
Connection: close
Content-Type: application/octet-stream</computeroutput></screen>
</example>
<para>The storage URL and authentication token are returned in
the headers of the response. After authentication, you can
use cURL to perform &HEAD;, &GET;, &DELETE;, &POST; and
&PUT; requests on the storage service.</para>
</section>
<section xml:id="determining-storage-useage">
<title>Determining Storage Usage</title>
<para>A &HEAD; request can be sent to the storage service to
determine how much data you have stored in the system and
the number of containers you are using. Use the
<code>-X</code> switch to specify the correct HTTP
method and the <code>-i</code> to dump the HTTP response
headers to terminal output (stdout).</para>
<example>
<title>cURL Get Storage Space</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X HEAD</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Date: Thu, 09 Jul 2009 15:38:14 GMT
Server: Apache
X-Account-Container-Count: 22
X-Account-Bytes-Used: 9891628380
Content-Type: text/plain</computeroutput></screen>
</example>
<para>The HTTP request must include a header to specify the
authentication token. The HTTP headers in the response
indicate the number of containers in this storage account
and the total bytes stored for the entire account.</para>
</section>
<section xml:id="listing-and-creating-storage-containers">
<title>Listing and Creating Containers</title>
<para>The simplest operation for Object Storage is to simply
list the containers you have, which when you don't have
any containers yet isn't terribly exciting:</para>
<example>
<title>cURL List Storage Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 0
Accept-Ranges: bytes
X-Trans-Id: txe8ca5138ac8643ec84070543a0c9c91e
Content-Length: 0
Date: Mon, 07 Nov 2011 17:07:01 GMT</computeroutput></screen>
</example>
<para>So, you take the X-Auth-Token obtained from the
authentication operation, pass it as a header value,
execute the operation against the URL obtained from the
authentication operation, and force the GET verb with the
-X switch. What you get back tells you there aren't any
containers.</para>
<para>Next, let's create a container and then do the listing
again:</para>
<example>
<title>cURL Create Storage Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/george</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 18
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txb25576385284476d9fa6c73835f21650
Date: Mon, 07 Nov 2011 17:44:20 GMT
201 Created</computeroutput></screen>
</example>
<para>Append the container name to the URL and force the PUT
verb. That creates a container, which we can now see when
we do a listing:</para>
<example>
<title>cURL List Storage Container After a
Creation</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 1
Accept-Ranges: bytes
Content-Length: 7
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txaedd6b080626453399c9f5febbddb73b
Date: Mon, 07 Nov 2011 17:44:23 GMT
george</computeroutput></screen>
</example>
<para>You may have noticed the account metadata that comes
back from the listing call. As you'd guess, it'll tell you
how many objects you have, how much space you are using,
and how many containers you are using.</para>
</section>
<section xml:id="paging-containers">
<title>Paging Lists of Containers</title>
<para>If you have a large number of containers, it is
sometimes more convenient to page through them than
getting some big long list of them. If I create more
containers and then do a regular listing, here's what it
looks like with five containers:</para>
<example>
<title>cURL List Storage Container (long list)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 5
Accept-Ranges: bytes
Content-Length: 31
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txb28795cc25b04f0dbce408dfa5a3cfc9
Date: Mon, 07 Nov 2011 19:03:06 GMT
cosmo
dogs
elaine
george
jerry</computeroutput></screen>
</example>
<para>Suppose I want a page size of 2, all I do is append a
""?limit=2"" to my URL:</para>
<example>
<title>cURL List Storage Container with Paging (first
page)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343?limit=2</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 5
Accept-Ranges: bytes
Content-Length: 11
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx940ee02c1a65451e96a2a2532e3a7ce7
Date: Mon, 07 Nov 2011 19:05:30 GMT
cosmo
dogs</computeroutput></screen>
</example>
<para>Not surprisingly, I only get two containers. To get the
next page, you tell the system which item you last saw
with the "marker=" specifier:</para>
<example>
<title>cURL List Storage Container with Paging (later
pages)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343?marker=dogs\&amp;limit=2</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 5
Accept-Ranges: bytes
Content-Length: 14
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx2a69f7ec38c34078a185c5875a4c0e34
Date: Mon, 07 Nov 2011 19:15:00 GMT
elaine
george</computeroutput></screen>
</example>
<para>Notice that I had to use \&amp; so that my bash shell
didn't try to interpret the &amp; as wanting to run
something in its own thread. With that in place, you get
the next page of items that appear after the
marker.</para>
</section>
<section xml:id="serialized-output">
<title>Serialized Output</title>
<para>In other situations, like if you are working on a
language binding on top of the REST API, you might want
more structured data back from the method calls. By
appending a "format=" and then choosing either json or
xml, you can get that structured data back you've been
dreaming about.</para>
<example>
<title>cURL List Storage Container (JSON output)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343?format=json</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 5
Accept-Ranges: bytes
Content-Length: 187
Content-Type: application/json; charset=utf-8
X-Trans-Id: txd408573a51d2423c848cba191fbede9b
Date: Mon, 07 Nov 2011 19:17:33 GMT
[{"name":"cosmo", "count":0,"bytes":0},
{"name":"dogs","count":0,"bytes":0},
{"name":"elaine","count":0,"bytes":0},
{"name":"george","count":0,"bytes":0},
{"name":"jerry","count":0,"bytes":0}]</computeroutput></screen>
</example>
<example>
<title>cURL List Storage Container (XML output)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343?format=xml</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 5
Accept-Ranges: bytes
Content-Length: 479
Content-Type: application/xml; charset=utf-8
X-Trans-Id: tx5e5685a15d0b406799b6a425b1150e4c
Date: Mon, 07 Nov 2011 19:17:38 GMT
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;account name="AUTH_a23f73d2-abfb-4656-af94-32ddec35dab8">
&lt;container>&lt;name>cosmo&lt;/name>&lt;count>0&lt;/count>&lt;bytes>0&lt;/bytes>&lt;/container>
&lt;container>&lt;name>dogs&lt;/name>&lt;count>0&lt;/count>&lt;bytes>0&lt;/bytes>&lt;/container>
&lt;container>&lt;name>elaine&lt;/name>&lt;count>0&lt;/count>&lt;bytes>0&lt;/bytes>&lt;/container>
&lt;container>&lt;name>george&lt;/name>&lt;count>0&lt;/count>&lt;bytes>0&lt;/bytes>&lt;/container>
&lt;container>&lt;name>jerry&lt;/name>&lt;count>0&lt;/count>&lt;bytes>0&lt;/bytes>&lt;/container>
&lt;/account></computeroutput></screen>
</example>
<para>The remainder of the examples in this document will use
the standard, non-serialized output but all operations
accept the format argument. You might notice that when you
use one of the formats, you get more information about the
containers. That's the per-container metadata, which is
covered in the next section.</para>
</section>
<section xml:id="container-metadata-and-delete-containers">
<title>Container Metadata and Deleting Containers</title>
<para>You can get at container metadata directly simply by
appending the name of the container to a HEAD
request:</para>
<example>
<title>cURL List Container Metadata</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X HEAD</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx3dd984f9482341dd97546e9d49d65e90
Content-Length: 0
Date: Mon, 07 Nov 2011 20:39:41 GMT</computeroutput></screen>
</example>
<para>Not very exciting without any objects in the container,
but you get the idea. While you cannot update or delete
container metadata, you can delete a container:</para>
<example>
<title>cURL Delete Storage Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X DELETE</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/george</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx3fa3857f266f44319d9b8f4bf7ce7fc8
Date: Mon, 07 Nov 2011 20:42:58 GMT</computeroutput></screen>
</example>
<para>Then let's confirm the delete by listing the containers
again:</para>
<example>
<title>cURL List Containers After a Delete</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Account-Object-Count: 0
X-Account-Bytes-Used: 0
X-Account-Container-Count: 4
Accept-Ranges: bytes
Content-Length: 24
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx2475741852b849ce9403e382fe3f8015
Date: Mon, 07 Nov 2011 20:43:08 GMT
cosmo
dogs
elaine
jerry</computeroutput></screen>
</example>
</section>
<section xml:id="special-metadata-acls">
<title>Special Metadata: Container ACLs</title>
<para>A particularly important metadata element for containers
is X-Container-Read, which establishes the ACL permissions
on who can read objects in the container. Prior to being
set, the ACL logic default to only be accessible to
someone with a valid X-Auth-Token for the account in
question. Doing a simple listing of a container shows us
the absence of X-Container-Read in this default
situation:</para>
<example>
<title>cURL List Container Showing Lack of ACL</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx3aa52e951fc64b63bc1fda27902b9bd3
Content-Length: 0
Date: Tue, 15 Nov 2011 03:29:22 GMT</computeroutput></screen>
</example>
<para>Now we'll set the X-Container-Read. For a full
explanation of valid values, see:
http://swift.openstack.org/misc.html#acls but for our
simple needs, we'll enable read access and listing access
to anybody:</para>
<example>
<title>cURL Setting an ACL on a Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-H "X-Container-Read: .r:*,.rlistings"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 202 Accepted
Content-Length: 58
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txf2befb56b1854a50995f710f2db48089
Date: Tue, 15 Nov 2011 03:33:16 GMT
202 Accepted
The request is accepted for processing.</computeroutput></screen>
</example>
<para>To see the metadata change, do a listing again:</para>
<example>
<title>cURL List Container Showing with an ACL</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/jerry</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: txb40eb86d949345f7bc66b01e8b63c3a5
Content-Length: 0
Date: Tue, 15 Nov 2011 03:33:36 GMT</computeroutput></screen>
</example>
<para>The side effect of giving anybody read access is that
any object in the container is now accessible from a
browser simply by entering the X-Storage-URL used
throughout the session and append the object name. For
example:</para>
<para>https://storage.swiftdrive.com/v1/CF_xer7_343/jerry/cereal.jpg</para>
<para>would be the URL of an object named "cereal.jpg" in the
container "jerry" that has been made publicly accessible
using this method.</para>
</section>
<section xml:id="creating-objects">
<title>Creating Objects</title>
<para>Enough with containers already, let's start to upload
some objects. Suppose you had a local directory full of
dog pictures:</para>
<example>
<title>Sample File Listing</title>
<screen><prompt>$</prompt> <userinput>ls -l</userinput>
<computeroutput>
total 504
-rw-r--r--@ 1 petecj2 staff 44765 Nov 7 14:49 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
</example>
<para>In order to put one of them in a container called "dogs"
with cURL, you'd do this:</para>
<example>
<title>Creating and Uploading an Object to a
Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-T JingleRocky.jpg</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
Last-Modified: Mon, 07 Nov 2011 22:51:29 GMT
X-Trans-Id: txd131cc897c78403daf5fad010d4d7152
Date: Mon, 07 Nov 2011 22:51:30 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
</example>
<para>The object gets named from whatever we append to the URL
path beyond the container name and the -T switch lets us
name a file to push with the operation as the request
body. We can confirm the upload by checking the container
again:</para>
<example>
<title>cURL List Container Showing Newly Uploaded
Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 1
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 44765
Accept-Ranges: bytes
Content-Length: 16
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx83be89d4e1a34eacbfeebcdfc7a7f2e7
Date: Mon, 07 Nov 2011 22:56:25 GMT
JingleRocky.jpg</computeroutput></screen>
</example>
<para>Notice that the container metadata now reflects the
number of objects and the bytes match what we saw when we
did the directory listing. After uploading the other two
similarly, we get a full object listing:</para>
<example>
<title>cURL List Container Showing Multiple Newly Uploaded
Objects</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 3
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 252732
Accept-Ranges: bytes
Content-Length: 53
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txae17dfa78da64117aaf07585a1b02115
Date: Mon, 07 Nov 2011 23:00:56 GMT
JingleRocky.jpg
RockyAndBuster.jpg
SittingBuster.jpg</computeroutput></screen>
</example>
</section>
<section xml:id="create_static_large_objects">
<title>Creating Static Large Objects</title>
<para>Creation of a static large object is done in several
steps. First we divide the content into pieces and upload
each piece into a segment object. Then we create a
manifest object. In this example, we will place the
segment objects into the "segments" container and the
manifest object into the "images" container. We are not
required to do this, but using a dedicated container for
segment objects is convenient.</para>
<para>Assuming we've already divided our image into three
files, let's upload them. We have removed non-essential
response headers so you can see the important
details.</para>
<example>
<title>Uploading first segment</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> <option>-H "X-Auth-Token: 12345"</option> <option>-T ./piece1</option>
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-one</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 4000000
Etag: f7365c1419b4f349592c00bd0cfb9b9a</computeroutput></screen>
</example>
<example>
<title>Uploading second segment</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> <option>-H "X-Auth-Token: 12345"</option> <option>-T ./piece2</option>
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-two</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 2000000
Etag: ad81e97b10e870613aecb5ced52adbaa</computeroutput></screen>
</example>
<example>
<title>Uploading final segment</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> <option>-H "X-Auth-Token: 12345"</option> <option>-T ./piece3</option>
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/segments/terrier-jpg-three</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 1000
Etag: 00b046c9d74c3e8f93b320c5e5fdc2c3</computeroutput></screen>
</example>
<para>At this stage we are ready to create the manifest
listing. Notice that the size and ETag are copied from
uploads above. Lets use an editor to create a file called
<code>manifest.json</code> with the following
content:</para>
<example>
<title>Manifest List Example</title>
<screen><computeroutput> [
{
"path": "segments/terrier-jpg-one",
"etag": "f7365c1419b4f349592c00bd0cfb9b9a",
"size_bytes": 4000000
},
{
"path": "segments/terrier-jpg-two",
"etag": "ad81e97b10e870613aecb5ced52adbaa",
"size_bytes": 2000000
},
"path": "segments/terrier-jpg-three",
"etag": "00b046c9d74c3e8f93b320c5e5fdc2c3",
"size_bytes": 1000
{
}
]</computeroutput></screen>
</example>
<para>The final operation is to upload this content into a
manifest object. To indicate that this is a manifest
object, you need to specify the
<code>?multipart-manifest=put</code> query
string.</para>
<example>
<title>Uploading manifest object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> <option>-H "X-Auth-Token: 12345"</option> <option>-T ./manifest.json</option>
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/images/terrier-jpg?multipart-manifest=put</uri></userinput></screen>
</example>
<para>We can now examine our static large object. Notice that
the size is the total size of all the segments.</para>
<example>
<title>Examining a manifest object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X HEAD</option> <option>-i</option> <option>-H "X-Auth-Token: 12345"</option>
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/images/terrier-jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 6001000
Etag: "0c922c37f915efb1c9b97e6328b3e660"</computeroutput></screen>
</example>
</section>
<section xml:id="paging-objects">
<title>Paging Lists of Objects</title>
<para>Exactly like listing containers, objects can be listed
in pages at a time using markers to denote pages. From the
previous example with 3 objects in the container "dogs",
the list can be paged with the "limit" query string
variable:</para>
<example>
<title>cURL List Objects (first page)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs?limit=2</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 3
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 252732
Accept-Ranges: bytes
Content-Length: 35
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx5e00fa9fa895423198bc814cb0c6162d
Date: Tue, 15 Nov 2011 03:53:51 GMT
JingleRocky.jpg
RockyAndBuster.jpg</computeroutput></screen>
</example>
<para>And the second page fetched with:</para>
<example>
<title>cURL List Objects with Paging (later pages)</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs?marker=RockyAndBuster.jpg\&amp;limit=2</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 3
X-Container-Read: .r:*,.rlistings
X-Container-Bytes-Used: 252732
Accept-Ranges: bytes
Content-Length: 18
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txe1287a7179dc4dfd98610850a0fff157
Date: Tue, 15 Nov 2011 03:54:21 GMT
SittingBuster.jpg</computeroutput></screen>
</example>
</section>
<section xml:id="retrieve-copy-retrieve-objects">
<title>Retrieve, Copy, and Delete Objects</title>
<para>Now we'll retrieve an object previously uploaded. First,
we'll remove the local copy:</para>
<example>
<title>Removing Local Copies</title>
<screen><prompt>$</prompt> <userinput>ls -l</userinput>
<computeroutput>
total 504
-rw-r--r--@ 1 petecj2 staff 44765 Nov 7 14:49 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg
$ rm JingleRocky.jpg
$ ls -l
total 416
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
</example>
<para>Be sure not to use -i switch here since what we want is
the raw data, which we'll then pipe to a file:</para>
<example>
<title>cURL Retrieve an Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg > JingleRocky.jpg</uri></userinput></screen>
<screen><prompt>$</prompt> <userinput>ls -l</userinput>
<computeroutput>
total 504
-rw-r--r-- 1 petecj2 staff 44765 Nov 7 15:11 JingleRocky.jpg
-rw-r--r--@ 1 petecj2 staff 100864 Nov 7 14:47 RockyAndBuster.jpg
-rw-r--r--@ 1 petecj2 staff 107103 Nov 7 14:47 SittingBuster.jpg</computeroutput></screen>
</example>
<para>Next, Object Storage provides a facility to copy objects
from one container to another entirely on the server side.
To do this, you do a PUT with the destination container
and new object name while passing a special X-Copy-From
header and a Content-Length of zero:</para>
<example>
<title>cURL Server-side Copy an Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-H "X-Copy-From: /dogs/JingleRocky.jpg"</option> \
<option>-H "Content-Length: 0"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
X-Copied-From: dogs/JingleRocky.jpg
Last-Modified: Mon, 07 Nov 2011 23:23:53 GMT
X-Trans-Id: tx244cd14df1b94d8c91ec5dcf8c5f9da4
Date: Mon, 07 Nov 2011 23:23:54 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
</example>
<para>You can then confirm the new location of the object. To
do this, you do a GET with the destination container to
see the listing of the object:</para>
<example>
<title>cURL Confirming the Server-side Copy an
Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 1
X-Container-Bytes-Used: 44765
Accept-Ranges: bytes
Content-Length: 16
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx46986b4a09b34790924fd43842b2b0dd
Date: Mon, 07 Nov 2011 23:24:05 GMT
JingleRocky.jpg</computeroutput></screen>
</example>
<para>To delete an object from its container, simply use the
DELETE verb:</para>
<example>
<title>cURL Delete an Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X DELETE</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txd45f04422b034e6f8447de400b78cbf3
Date: Mon, 07 Nov 2011 23:32:39 GMT</computeroutput></screen>
</example>
<para>Confirming the deletion by doing a container
listing:</para>
<example>
<title>cURL Confirming the Delete an Object</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/elaine/</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: txc9b43bf4d896405eb9a88ca468bf7b2d
Content-Length: 0
Date: Mon, 07 Nov 2011 23:32:41 GMT</computeroutput></screen>
</example>
</section>
<section xml:id="object-metadata">
<title>Object Metadata</title>
<para>Objects can have whatever metadata keys/values you
choose. Simply POST an HTTP Header to the object in the
form of X-Object-Meta-&lt;key>: &lt;value>. Like
this:</para>
<example>
<title>cURL Set Object Metadata</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X POST</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-H "X-Object-Meta-Breed: Terrier pit bull mix""</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput> &lt;html>
&lt;head>
&lt;title>202 Accepted&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>202 Accepted&lt;/h1>
The request is accepted for processing.&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
</example>
<para>And then read the object metadata with a HEAD on the
object path:</para>
<example>
<title>cURL Reading Object Metadata</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X HEAD</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/dogs/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput> HTTP/1.1 200 OK
X-Object-Meta-Breed: Terrier pit bull mix
Last-Modified: Tue, 08 Nov 2011 01:26:49 GMT
Etag: f7d40eceffdd9c2ecab226105737b2a6
Accept-Ranges: bytes
Content-Length: 44765
Content-Type: image/jpeg
X-Trans-Id: txa8bff9ad7ef844829103c1f9b8c20781
Date: Tue, 08 Nov 2011 01:29:35 GMT</computeroutput></screen>
</example>
</section>
<section xml:id="folders-directories">
<title>Pseudo-Hierarchical Folders/Directories</title>
<para>For the last section, we come to the most confusing
concept in Object Storage. In most storage systems, you
have the ability to create custom hierarchies of files so
that you can better organize them. On its surface, Object
Storage only gives you one level of hierarchy in the form
of containers. However, it turns out that you can get
creative with naming your objects to give yourself the
same effect as having hierarchical containers.</para>
<para>Let's start with a fresh container without any objects
in it:</para>
<example>
<title>cURL Create New Container for Folders</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 18
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txc78254a41b374b6ea10590d90874f769
Date: Wed, 16 Nov 2011 00:06:22 GMT
201 Created</computeroutput></screen>
</example>
<para>Now list the new container:</para>
<example>
<title>cURL Listing the New Container</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
X-Container-Object-Count: 0
X-Container-Bytes-Used: 0
Accept-Ranges: bytes
X-Trans-Id: tx49112200f7934c2bab1de3ae103c368e
Content-Length: 0
Date: Wed, 16 Nov 2011 00:06:26 GMT</computeroutput></screen>
</example>
<para>Next, add an object but prefix the name with the
hierarchy desired:</para>
<example>
<title>cURL Upload an Object with a Prefix</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-T JingleRocky.jpg</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos/terriers/JingleRocky.jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: f7d40eceffdd9c2ecab226105737b2a6
Last-Modified: Wed, 16 Nov 2011 00:09:18 GMT
X-Trans-Id: txe34fdf2704f044e3a7102256386b1cb7
Date: Wed, 16 Nov 2011 00:09:19 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
</example>
<para>Do it again with a different object and prefix:</para>
<example>
<title>cURL Upload a Different Object with a Different
Prefix</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X PUT</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<option>-T SittingBuster.jpg</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos/chihuahuas/SittingBuster.jpg</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 118
Content-Type: text/html; charset=UTF-8
Etag: e692e744c7180ee368166a24f1a2fa9b
Last-Modified: Wed, 16 Nov 2011 00:52:25 GMT
X-Trans-Id: txe229d03af5ea4d2ea1071def213c3f02
Date: Wed, 16 Nov 2011 00:52:25 GMT
&lt;html>
&lt;head>
&lt;title>201 Created&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>201 Created&lt;/h1>
&lt;br />&lt;br />
&lt;/body>
&lt;/html></computeroutput></screen>
</example>
<para>Now list the container, revealing the prefixes:</para>
<example>
<title>cURL Listing a Container with Object Prefix</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 54
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx8544a17e8b1e4da693145fb5f2e6db43
Date: Wed, 16 Nov 2011 00:53:43 GMT
chihuahuas/SittingBuster.jpg
terriers/JingleRocky.jpg</computeroutput></screen>
</example>
<para>If you want to perform hierarchical listings, with the
prefixes in place, you can use the "path" query string
variable:</para>
<example>
<title>cURL Listing a Container with a Path</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos?path=terriers</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 25
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx3f1b9575d4de4a7d97ba3f9ad81923cc
Date: Wed, 16 Nov 2011 00:55:12 GMT
terriers/JingleRocky.jpg</computeroutput></screen>
</example>
<para>If you wanted to see what prefixes were in place, you
can use the "delimiter" query string variable to
distinguish prefix paths from object names:</para>
<example>
<title>cURL Listing a Container with a Delimiter</title>
<screen><prompt>$</prompt> <userinput><command>curl</command> <option>X GET</option> <option>-i</option> \
<option>-H "X-Auth-Token: fc81aaa6-98a1-9ab0-94ba-aba9a89aa9ae"</option> \
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/photos?delimiter=/</uri></userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
X-Container-Object-Count: 2
X-Container-Bytes-Used: 151868
Accept-Ranges: bytes
Content-Length: 22
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx7222a3dd73fe44b888db4e58cc647d1e
Date: Wed, 16 Nov 2011 00:57:40 GMT
chihuahuas/
terriers/</computeroutput></screen>
</example>
<para>Using these in combination allows you to discover
directories within a particular path and then further
drill down based on the results.</para>
</section>
</chapter>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<delete>
<number_deleted>2</number_deleted>
<number_not_found>4</number_not_found>
<errors>
<object>
<name>/v1/12345678912345/mycontainer</name>
<status>409 Conflict</status>
</object>
</errors>
</delete>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<delete>
<number_deleted>2</number_deleted>
<number_not_found>4</number_not_found>
<errors>
<object>
<name>/v1/12345678912345/mycontainer</name>
<status>409 Conflict</status>
</object>
</errors>
</delete>

View File

@@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<account name="MichaelBarton"> <?xml version="1.0" encoding="UTF-8"?>
<account name="AUTH_73f0aa26640f4971864919d0eb0f0880">
<container> <container>
<name>test_container_1</name> <name>diane</name>
<count>2</count> <count>0</count>
<bytes>78</bytes> <bytes>0</bytes>
</container> </container>
<container> <container>
<name>test_container_2</name> <name>joe</name>
<count>1</count> <count>0</count>
<bytes>17</bytes> <bytes>0</bytes>
</container>
<container>
<name>sarah</name>
<count>0</count>
<bytes>0</bytes>
</container> </container>
</account> </account>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<account name="MichaelBarton">
<container>
<name>test_container_1</name>
<count>2</count>
<bytes>78</bytes>
</container>
<container>
<name>test_container_2</name>
<count>1</count>
<bytes>17</bytes>
</container>
</account>

View File

@@ -1,5 +1 @@
PUT /<api version>/<account>/<container>/<object> HTTP/1.1 curl -i $publicURL/marktwain/goodbye -X PUT -H "X-Auth-Token: $token" -H "X-Delete-At: 1390581073" -H "Content-Length: 14" -H "Content-Type: application/octet-stream"
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Type: image/jpeg
X-Delete-At: 1339429105

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<server xmlns="http://docs.openstack.org/compute/api/v1.1"
imageRef="3afe97b2-26dc-49c5-a2cc-a2fc8d80c001" flavorRef="2"
name="api-test-server-xml2">
<metadata>
<meta key="My Server Name">API Test Server XML</meta>
</metadata>
<personality>
<file path="/etc/banner.txt">
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==</file>
</personality>
<networks>
<uuid>0ef47ac7-6797-4e01-8a47-ed26ec3aaa56</uuid>
<uuid>00000000-0000-0000-0000-000000000000</uuid>
<uuid>11111111-1111-1111-1111-111111111111</uuid>
</networks>
</server>

View File

@@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<server
xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns="http://docs.openstack.org/compute/api/v1.1"
id="ed5c7754-29b6-45fa-96cb-ab64958c8c0a" adminPass="Dd5pNZtpVVQ3"
OS-DCF:diskConfig="AUTO">
<metadata/>
<atom:link
href="https://dfw.servers.api.rackspacecloud.com/v2/010101/servers/ed5c7754-29b6-45fa-96cb-ab64958c8c0a"
rel="self"/>
<atom:link
href="https://dfw.servers.api.rackspacecloud.com/010101/servers/ed5c7754-29b6-45fa-96cb-ab64958c8c0a"
rel="bookmark"/>
</server>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="content-disposition">
<title>Override browser default behavior</title>
<para>To override the default behavior for a browser, use the
<literal>Content-Disposition</literal> header to specify
the override behavior and assign this header to an object. For
example, this header might specify that the browser use a
download program to save this file rather than show the file,
which is the default.</para>
<example>
<title>Override browser default behavior request: HTTP</title>
<para>This example assigns an attachment type to the
<literal>Content-Disposition</literal> header. This
attachment type indicates that the file is to be
downloaded as <literal>goodbye.txt</literal>:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/marktwain/goodbye -X POST -H "X-Auth-Token: $token" -H "Content-Length: 14" -H "Content-Type: application/octet-stream" -H "Content-Disposition: attachment; filename=goodbye.txt"</userinput></screen>
<screen><computeroutput>HTTP/1.1 202 Accepted
Content-Length: 76
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txa9b5e57d7f354d7ea9f57-0052e17e13
Date: Thu, 23 Jan 2014 20:39:47 GMT
&lt;html>&lt;h1>Accepted&lt;/h1>&lt;p>The request is accepted for processing.&lt;/p>&lt;/html></computeroutput></screen>
</example>
</section>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="cors-headers">
<title>Assign CORS headers to requests</title>
<para>Cross-Origin Resource Sharing (CORS) is a specification that
defines how browsers and servers communicate across origins by
using HTTP headers, such as those assigned by Object Storage
API requests. The Object
Storage API supports these headers. For more information, see <link
xlink:href="http://www.w3.org/TR/access-control/"
>www.w3.org/TR/access-control/</link>. </para>
<itemizedlist>
<listitem>
<para>Access-Control-Allow-Credentials</para>
</listitem>
<listitem>
<para>Access-Control-Allow-Methods</para>
</listitem>
<listitem>
<para>Access-Control-Allow-Origin</para>
</listitem>
<listitem>
<para>Access-Control-Expose-Headers</para>
</listitem>
<listitem>
<para>Access-Control-Max-Age</para>
</listitem>
<listitem>
<para>Access-Control-Request-Headers</para>
</listitem>
<listitem>
<para>Access-Control-Request-Method</para>
</listitem>
<listitem>
<para>Origin</para>
</listitem>
</itemizedlist>
<para>You can assign these headers to only objects.</para>
<example>
<title>Assign CORS header request: HTTP</title>
<para>This example assigns the file origin to the <literal>Origin</literal> header, which
ensures that the file originated from a reputable source:</para>
<literallayout class="monospaced"><xi:include href="samples/object-assign-cors-header-req.txt" parse="text"/></literallayout>
</example>
</section>

View File

@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!ENTITY plusmn "&#xB1;">
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
<!ENTITY CHECK '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="figures/Check_mark_23x20_02.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
<!ENTITY ARROW '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="figures/Arrow_east.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="curl">
<title>How cURL commands work</title>
<para>cURL is a command-line tool that you can use to interact
with REST interfaces. cURL lets you to
transmit and receive HTTP requests and
responses from the command line or a shell script, which
enables you to work with the API directly. It is available for
Linux distributions, Mac OS X, and Windows. For information
about cURL, see <link xlink:href="http://curl.haxx.se/"
>http://curl.haxx.se/</link>.</para>
<para>To use XML requests and responses, see <xref
linkend="curl_summary_xml"/>.</para>
<para>To run the cURL request examples shown in this guide, copy
each example from the HTML version of this guide directly to
the command line or a script.</para>
<para>This example cURL command shows account details and lists
containers in the account.</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL?format=json \
-X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 96
X-Account-Object-Count: 1
X-Timestamp: 1389453423.35964
X-Account-Meta-Subject: Literature
X-Account-Bytes-Used: 14
X-Account-Container-Count: 2
Content-Type: application/json; charset=utf-8
Accept-Ranges: bytes
X-Trans-Id: tx274a77a8975c4a66aeb24-0052d95365
Date: Fri, 17 Jan 2014 15:59:33 GMT</computeroutput>
</screen>
<para>The response, in JSON
format, is:</para>
<programlisting language="json">[
{
"count":0,
"bytes":0,
"name":"janeausten"
},
{
"count":1,
"bytes":14,
"name":"marktwain"
}
]</programlisting>
<note>
<para>The carriage returns in the cURL request examples are
escaped with a backslash (<literal>\</literal>) character.
The escape character allows continuation of the command
across multiple lines. However, do not include the escape
character in the JSON or XML request body within the cURL
command.</para>
</note>
<para>The cURL examples in this guide use the following
command-line options:</para>
<table xml:id="curl_options" rules="all" width="75%">
<caption>cURL command-line options</caption>
<thead>
<tr>
<th>Option</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<option>-d</option>
</td>
<td>
<para>Sends the specified data in a &POST; request
to the HTTP server. Use this option to send a
JSON or XML request body to the server.</para>
</td>
</tr>
<tr>
<td>
<option>-H</option>
</td>
<td>
<para>Specifies an extra HTTP header in the
request. You can specify any number of extra
headers. Precede each header with the
<option>-H</option> option.</para>
</td>
</tr>
<tr>
<td>
<option>-i</option>
</td>
<td>
<para>Includes the HTTP header in the
output.</para>
</td>
</tr>
<tr>
<td>
<option>-s</option>
</td>
<td>
<para>Silent or quiet mode. Does not show progress
or error messages. Makes cURL mute.</para>
</td>
</tr>
<tr>
<td>
<option>-T</option>
</td>
<td>
<para>Transfers the specified local file to the
remote URL.</para>
</td>
</tr>
<tr>
<td>
<option>-X</option>
</td>
<td>
<para>Specifies the request method to use when
communicating with the HTTP server. The
specified request is used instead of the
default method, which is &GET;.</para>
</td>
</tr>
</tbody>
</table>
<note xml:id="json_tool">
<title>json.tool</title>
<para>For commands that return a response, you can append the
following code to the command to call the json.tool to
pretty-print output:</para>
<programlisting language="bash" role="gutter: false">| python -m json.tool</programlisting>
<para>To use the json.tool, import the json module. For
information about the json.tool, see <link
xlink:href="http://docs.python.org/2/library/json.html"
>json — JSON encoder and decoder</link>.</para>
<para>If you run a Python version older than 2.6, import the
simplejson module and use the simplejson.tool. For
information about the simple.json tool, see <link
xlink:href="http://simplejson.googlecode.com/svn/tags/simplejson-2.0.9/docs/index.html"
>simplejson — JSON encoder and decoder</link>.</para>
<para>If you do not want to pretty-print JSON output, omit
this code.</para>
</note>
<section xml:id="curl_summary_xml">
<title>XML requests and responses</title>
<para>To request an XML response, append the <literal>format=xml</literal>
query parameter to the request.</para>
<para>If the request requires a request body, specify it in
XML format.</para>
<para>This example cURL command shows account information and
list containers in the account, and asks for the response in XML:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL?format=xml \
-X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 262
X-Account-Object-Count: 1
X-Timestamp: 1389453423.35964
X-Account-Meta-Subject: Literature
X-Account-Bytes-Used: 14
X-Account-Container-Count: 2
Content-Type: application/xml; charset=utf-8
Accept-Ranges: bytes
X-Trans-Id: tx69f60bc9f7634a01988e6-0052d9544b
Date: Fri, 17 Jan 2014 16:03:23 GMT</computeroutput></screen>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;account name="my_account">
&lt;container>
&lt;name>janeausten&lt;/name>
&lt;count>0&lt;/count>
&lt;bytes>0&lt;/bytes>
&lt;/container>
&lt;container>
&lt;name>marktwain&lt;/name>
&lt;count>1&lt;/count>
&lt;bytes>14&lt;/bytes>
&lt;/container>
&lt;/account</programlisting>
</section>
</section>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="expire-objects">
<title>Schedule objects for deletion</title>
<para>Scheduling an object for deletion is helpful for objects
that you do not want to permanently store, such as log files,
recurring full backups of a dataset, or documents or images
that become outdated at a specified future time.</para>
<para>To schedule an object for deletion, include one of these
headers with the &PUT; or &POST; request on the object:</para>
<itemizedlist>
<listitem>
<para><literal>X-Delete-After</literal></para>
<para>Takes an integer number of seconds and calculates
the amount of time from now that you want the object
to be deleted. The proxy server that receives the
request converts this header into an
<literal>X-Delete-At</literal> header and
calculates the deletion time by using its current time
plus the value given in seconds.</para>
</listitem>
<listitem>
<para><literal>X-Delete-At</literal></para>
<para>Requires a UNIX Epoch timestamp, in integer form.
For example, <literal>1348691905</literal> represents
<literal>Wed, 26 Sep 2012 20:38:25 GMT</literal>.
By setting the header to a specific Epoch time, you
indicate when you want the object to expire, not be
served, and be deleted completely from the object
store.</para>
</listitem>
</itemizedlist>
<para>Use the &POST; method to assign expiration
headers to existing objects that you want expire.</para>
<simplesect>
<title>Delete object at request: HTTP</title>
<para>In the example, the <code>X-Delete-At</code> header is
assigned a UNIX Epoch timestamp in integer form for
Mon, 11 Jun 2012 15:38:25 GMT. Use <link
xlink:href="http://www.epochconverter.com/"
>http://www.epochconverter.com/</link> for example
timestamps and a batch converter.</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/marktwain/goodbye -X PUT -H "X-Auth-Token: $token" -H "X-Delete-At: 1390581073" -H "Content-Length: 14" -H "Content-Type: application/octet-stream"</userinput></screen>
</simplesect>
<simplesect>
<title>Delete object after request: HTTP</title>
<para>In this example, the <code>X-Delete-After</code> header
is assigned a value in seconds, equivalent to 10 days.
After this time, the object expires.</para>
<literallayout class="monospaced"><xi:include href="samples/object-delete-after-req.txt" parse="text"/></literallayout>
</simplesect>
</section>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="file-compression">
<title>Compress files</title>
<para>Use the <literal>Content-Encoding</literal> header to
compress a file without losing the identity of the underlying
media type of the file, such as a video.</para>
<example>
<title>Content-Encoding header request: HTTP</title>
<para>This example assigns an attachment type to the
<literal>Content-Encoding</literal> header that
indicates how the file is downloaded:</para>
<programlisting><xi:include href="samples/content-encoding-header-req.txt" parse="text"/></programlisting>
</example>
</section>

View File

@@ -0,0 +1,372 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE section [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY COPY '<command xmlns="http://docbook.org/ns/docbook">COPY</command>'>
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="large-object-creation">
<title>Large objects</title>
<para>By default, the content of an object cannot be greater than
5 GB. However, you can use segment objects and manifest
objects to store more content.</para>
<section xml:id="segment-objects">
<title>Segment objects</title>
<para>You can divide your content into segments, and upload
each segment into its own segment object. Segment objects
do not have any special features. You create, update,
download, and delete segment objects just as you would
normal objects.</para>
</section>
<section xml:id="manifest-objects">
<title>Manifest objects</title>
<para>A manifest object points to segment objects. When you
download a manifest object, Object Storage concatenates
the contents of the segment objects and returns this in
the response body of the request. </para>
<para>This behavior extends to the response headers returned
by &GET; and &HEAD; requests. The
<literal>Content-Length</literal> response header
value is the total size of all segment objects. Object
Storage calculates the <literal>ETag</literal> response
header value by taking the <literal>ETag</literal> value
of each segment, concatenating them together, and
returning the MD5 checksum of the result.</para>
<note>
<para>If you make a &COPY; request by using a manifest
object as the source, the new object is a normal, and
not a segment, object. If the total size of the source
segment objects exceeds 5 GB, the &COPY; request
fails. However, you can make a duplicate of the
manifest object and this new object can be larger than
5 GB.</para>
</note>
<para>The manifest object types are:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Static large
objects</emphasis>. The manifest object
content is an ordered list of the names of the
segment objects in JSON format.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Dynamic large
objects</emphasis>. The manifest object has no
content. </para>
<para>However, it has
<literal>X-Object-Manifest</literal> metadata
header. The value of this header is
<literal>&lt;container>/&lt;prefix></literal>,
where <literal>&lt;container></literal> is the
name of the container where the segment objects
are stored, and <literal>&lt;prefix></literal> is
a string that all segment objects have in
common.</para>
</listitem>
</itemizedlist>
<para>While both types of manifest objects have similar
behavior, the following table describes their
differences:</para>
<table rules="all">
<caption>Static and dynamic large objects</caption>
<thead>
<tr>
<th>Object type</th>
<th>End-to-end integrity</th>
<th>Upload order</th>
<th>Removal or addition of segment objects</th>
<th>Segment object size and number</th>
<th>Segment object container name</th>
<th>Manifest Object Metadata</th>
<th>Making a copy of the manifest object</th>
</tr>
</thead>
<tbody>
<tr>
<td>Static large object</td>
<td>Assured. The list of segments includes the MD5
checksum (ETag) of each segment. You cannot
upload the manifest object if the ETag in the
list differs from the segment object already
uploaded. If a segment is somehow lost, an
attempt to download the manifest object will
result in an error.</td>
<td>The segment objects must be uploaded before
the manifest object.</td>
<td>You cannot add or remove segment objects from
the manifest. However, you can create a
completely new manifest object of the same
name with a different manifest list.</td>
<td>Segment objects must be at least 1MB in size
(by default). The final segment object can be
any size. At most 1000 segments are supported
(by default).</td>
<td>The manifest list includes the container name
of each object, i.e., segment objects may be
in different containers.</td>
<td>The object has
<code>X-Static-Large-Object</code> set to
<code>true</code>. You do not set this
metadata directly. Instead the system sets it
when you &PUT; a static manifest object.</td>
<td><para></para></td>
</tr>
<tr>
<td>Dynamic large object</td>
<td>Not guaranteed. The eventual consistency model
means that although you may have uploaded a
segment object, it may not appear in the
container listing until later. If you download
the manifest before it appears in the
container, it will not form part of the
content returned in response to a &GET;
request.</td>
<td>You can upload manifest and segment objects in
any order. You are recommended to upload the
manifest object after the segments in case a
premature download of the manifest occurs.
However, this is not enforced.</td>
<td>You can upload new segment objects or remove
existing segments. The names must simply match
the <code>&lt;prefix></code> supplied in
<code>X-Object-Manifest</code>.</td>
<td>Segment objects can be of any size.</td>
<td>All segment objects must be in the same
container</td>
<td>The <code>X-Object-Manifest</code> value is
the <code>&lt;container>/&lt;prefix></code>
indicating where the segment objects are
located. You supply this request header in the
&PUT; operation</td>
<td>The &COPY; operation does not create a
manifest object. To duplicate a manifest
object, use the &GET; operation to read the
value of <code>X-Object-Manifest</code> and
use this value in the
<code>X-Object-Manifest</code> request
header in a &PUT; operation. This creates a
new manifest object that shares the same set
of segment objects as the original manifest
object.</td>
</tr>
</tbody>
</table>
<section xml:id="dynamic-large-object-creation">
<title>Dynamic large objects</title>
<para>You must segment objects that are larger than 5 GB
before you can upload them. You then upload the
segment objects like you would any other object and
create a dynamic large manifest object. The manifest
object tells Object Storage how to find the segment
objects that comprise the large object. The segments
remain individually addressable, but retrieving the
manifest object streams all the segments concatenated.
There is no limit to the number of segments that can
be a part of a single large object.</para>
<para>To ensure the download works correctly, you must
upload all the object segments to the same container
and ensure that each object name is prefixed in such a
way that it sorts in the order in which it should be
concatenated. You also create and upload a manifest
file. The manifest file is a zero-byte file with the
extra X-Object-Manifest:
&lt;container&gt;/&lt;prefix&gt; header, where
&lt;container&gt; is the container the object segments
are in and &lt;prefix&gt; is the common prefix for all
the segments. The container and common prefix must be
UTF-8 encoded and URL-encoded in the X-Object-Manifest
header.</para>
<para>It is best to upload all the segments first and then
create or update the manifest. With this method, the
full object will not be available for downloading
until the upload is complete. Also, you can upload a
new set of segments to a second location and then
update the manifest to point to this new location.
During the upload of the new segments, the original
manifest will still be available to download the first
set of segments.</para>
<example>
<title>Upload segment of large object request:
HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-segment-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload segment of large object response:
HTTP</title>
<literallayout class="monospaced">s</literallayout>
</example>
<para>No response body is returned. A status code of 2xx
(between 200 and 299, inclusive) indicates a
successful write; status 411 (Length Required) denotes
a missing <code>Content-Length</code> or
<code>Content-Type</code> header in the request.
If the MD5 checksum of the data written to the storage
system does NOT match the (optionally) supplied ETag
value, a 422 (Unprocessable Entity) response is
returned.</para>
<para>You can continue uploading segments like this
example shows, prior to uploading the manifest.</para>
<example>
<title>Upload next segment of large object request:
HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-next-segment-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload next segment of large object response:
HTTP</title>
<literallayout class="monospaced">w</literallayout>
</example>
<para>Next, upload the manifest you created that indicates
the container the object segments reside within. Note
that uploading additional segments after the manifest
is created will cause the concatenated object to be
that much larger but you do not need to recreate the
manifest file for subsequent additional
segments.</para>
<example>
<title>Upload manifest request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload manifest response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-resp.txt" parse="text"/></literallayout>
</example>
<para>The response's Content-Type for a &GET; or &HEAD; on
the manifest will be the same as the Content-Type set
during the PUT request that created the manifest. You
can easily change the Content-Type by reissuing the
&PUT; request.</para>
</section>
<section xml:id="static-large-objects">
<title>Static large objects</title>
<procedure>
<title>To create a static large object</title>
<step>
<para>Divide your content into pieces and create
(upload) a segment object to contain each
piece. You must record the <code>ETag</code>
response header returned by the&PUT;
operation. Alternatively, you can calculate
the MD5 checksum of the segment prior to
uploading and include this in the
<code>ETag</code> request header. This
ensures that the upload cannot corrupt your
data.</para>
</step>
<step>
<para>List the name of each segment object along
with its size and MD5 checksum in order.
Create a manifest object. You indicate that
this is a manifest object by including the
<code>?multipart-manifest=put</code> query
string at the end of the manifest object
name.</para>
</step>
</procedure>
<para>The body of the &PUT; request on the manifest object
comprises a json list, where each element contains the
following:</para>
<itemizedlist>
<listitem>
<para><code>path</code> - this is the container
and object name in the following format:
<code>&lt;container-name>/&lt;object-name></code></para>
</listitem>
<listitem>
<para><code>etag</code> - this is the MD5 checksum
of the content of the segment object. This
must match the <code>ETag</code> of that
object.</para>
</listitem>
<listitem>
<para><code>size_bytes</code> - this is the size
of the segment object. This must match the
<code>Content-Length</code> of that
object</para>
</listitem>
</itemizedlist>
<example>
<title>Static large object manifest list</title>
<para>This is an example containing three segment
objects. In this example, you can use several
containers and the object names do not have to
conform to a specific pattern, in contrast to
dynamic large objects.</para>
<literallayout class="monospaced"><xi:include href="samples/slo-manifest-example.txt" parse="text"/></literallayout>
</example>
<para>The <code>Content-Length</code> request header must
contain the length of the json content. Not the length
of the segment objects. However, after the &PUT;
operation completes, the <code>Content-Length</code>
metadata is set to the total length of all the object
segments. A similar situation applies to the
<code>ETag</code>. If used in the &PUT; operation,
it must contain the MD5 checksum of the json content.
The <code>ETag</code> metadata value is then set to be
the MD5 checksum of the concatenated <code>ETag</code>
values of the object segments. You may also set the
<code>Content-Type</code> request header and
custom object metadata.</para>
<para>When the &PUT; operation sees the
<code>?multipart-manifest=put</code> query string,
it reads the request body and verifies that each
segment object exists and that the sizes and ETags
match. If there is a mismatch, the &PUT;operation will
fail.</para>
<para>If everything matches, the manifest object is
created. The <code>X-Static-Large-Object</code>
metadata is set to <code>true</code> indicating that
this is a static object manifest.</para>
<para>Normally when you perform a &GET; operation on the
manifest object, the response body contains the
concatenated content of the segment objects. To
download the manifest list, use the query string
<code>?multipart-manifest=get</code>. The
resulting list will not be identically formatted as
the manifest you originally used in the &PUT;
operation.</para>
<para>If you use the &DELETE; operation on a manifest
object, the manifest object is deleted. The segment
objects are not affected. However, if you add the
query parameter
<code>?multipart-manifest=delete</code>, the
segment objects are deleted and if all are
successfully deleted, the manifest object is also
deleted.</para>
<para>To change the manifest, use a &PUT; operation with
the <code>?multipart-manifest=put</code> query string.
This will create a <emphasis>new</emphasis> manifest
object. You may also update the object metadata in the
usual way.</para>
</section>
</section>
</section>

View File

@@ -31,7 +31,7 @@ format="SVG" scale="60"/>
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="Create_Static_Website-dle4000"> xml:id="Create_Static_Website-dle4000">
<title>Create Static Website</title> <title>Create static website</title>
<para>You can use your swift account to create a static website. <para>You can use your swift account to create a static website.
This mode is normally only active for anonymous requests. To This mode is normally only active for anonymous requests. To
use it with authenticated requests, set the header use it with authenticated requests, set the header
@@ -100,9 +100,10 @@ format="SVG" scale="60"/>
<para>You can create and set custom error pages for visitors <para>You can create and set custom error pages for visitors
to your website; currently, only 401 (Unauthorized) and to your website; currently, only 401 (Unauthorized) and
404 (Not Found) errors are supported. To do this, set the 404 (Not Found) errors are supported. To do this, set the
metadata header, <code>X-Container-Meta-Web-Error</code>.</para> metadata header,
<code>X-Container-Meta-Web-Error</code>.</para>
<para>Error pages are served with the &lt;status&gt; code <para>Error pages are served with the &lt;status&gt; code
prepended to the name of the error page you set. For pre-pended to the name of the error page you set. For
instance, if you set instance, if you set
<code>X-Container-Meta-Web-Error</code> to <code>X-Container-Meta-Web-Error</code> to
<code>error.html</code>, 401 errors will display the <code>error.html</code>, 401 errors will display the

View File

@@ -29,7 +29,7 @@ format="SVG" scale="60"/>
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="doc_history"> xml:id="doc_history">
<title>Document Change History</title> <title>Document change history</title>
<para>This version of the document replaces and obsoletes <para>This version of the document replaces and obsoletes
all previous versions. The following table describes the latest changes:</para> all previous versions. The following table describes the latest changes:</para>
<?rax revhistory?> <?rax revhistory?>

View File

@@ -31,8 +31,21 @@ format="SVG" scale="60"/>
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="storage-container-services"> xml:id="storage-container-services">
<title>Storage Container Services</title> <title>Storage container services</title>
<para>You can perform the following operations for <para>Lists objects, creates and delete containers, and gets, creates, updates, or deletes container
metadata.</para>
<wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<wadl:resource
href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#container">
<wadl:method href="#listObjects"/>
<wadl:method href="#createcontainer"/>
<wadl:method href="#deletecontainer"/>
<wadl:method href="#retrievecontainermeta"/>
<wadl:method href="#updateacontainermeta"/>
<wadl:method href="#deletecontainermeta"/>
</wadl:resource>
</wadl:resources>
<!-- <para>You can perform the following operations for
containers:</para> containers:</para>
<informaltable rules="all"> <informaltable rules="all">
<thead> <thead>
@@ -191,172 +204,7 @@ format="SVG" scale="60"/>
<title>List Objects HTTP Response</title> <title>List Objects HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/object-list-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-list-resp.txt" parse="text"/></literallayout>
</example> </example>
<section xml:id="serialized-list-output">
<title>Serialized List Output</title>
<para>If a <code>format=xml</code> or
<code>format=json</code> argument is appended to
the storage account URL, the service will serve
extended object information serialized in the chosen
format. Other than the <code>?format=xml|json</code>
parameter, it will return the same status/errors
codes. The sample responses below are formatted for
readability.</para>
<example>
<title>Get Objects Details HTTP and JSON
Request</title>
<literallayout class="monospaced"><xi:include href="samples/objects-get-details-http-json-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Get Objects Details HTTP and JSON Response</title>
<literallayout class="monospaced"><xi:include href="samples/objects-get-details-http-json-resp.txt" parse="text"/></literallayout>
<programlisting language="json"><xi:include href="samples/objects-get-details-resp.json" parse="text"/></programlisting>
</example>
<example>
<title>Objects Details Request: XML</title>
<literallayout class="monospaced"><xi:include href="samples/objects-get-details-http-xml-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Objects Details Request: XML</title>
<literallayout class="monospaced"><xi:include href="samples/objects-get-details-http-xml-resp.txt" parse="text"/></literallayout>
<programlisting language="xml"><xi:include href="samples/objects-get-details-resp.xml" parse="text"/></programlisting>
</example>
</section>
<section xml:id="list-large-number-of-objects">
<title>Controlling a Large List of Objects</title>
<para>The system returns a maximum of 10,000 object names
per request. To retrieve subsequent object names,
another request must be made with the 'marker'
parameter. The marker indicates where the last list
left off and the system returns object names greater
than this marker, up to 10,000 again. Note that the
marker value should be URL encoded prior to sending
the HTTP request.</para>
<para>If 10,000 is larger than desired, a 'limit'
parameter may be given.</para>
<para>If the number of object names returned equals the
limit given (or 10,000 if no limit is given), it can
be assumed there are more object names to be listed.
If the container name list is exactly divisible by the
limit, the last request has no content.</para>
<example>
<title>List Large Number of Objects</title>
<para>For an example, let's use a listing of five
object names:</para>
<literallayout class="monospaced">gala
grannysmith
honeycrisp
jonagold
reddelicious</literallayout>
<para>We'll use a limit of two to show how things
work:</para>
<literallayout class="monospaced"><xi:include href="samples/objects-list-req.txt" parse="text"/></literallayout>
<para>Because we received two items back, we can
assume there are more object names to list. So, we
make another request with a marker of the last
item returned:</para>
<literallayout class="monospaced"><xi:include href="samples/objects-list-marker-req.txt" parse="text"/></literallayout>
<para>Again we have two items returned; there might be
more:</para>
<literallayout class="monospaced"><xi:include href="samples/objects-list-marker2-req.txt" parse="text"/></literallayout>
<para>Now we received less than the limit number of
object names, indicating that we have the complete
list.</para>
<para>By using <code>end_marker</code> we can limit
the result set to object names less than the given
value.</para>
<literallayout class="monospaced"><xi:include href="samples/objects-list-end-marker-req.txt" parse="text"/></literallayout>
</example>
</section>
<section xml:id="pseudo-hierarchical-folders-directories">
<title>Pseudo-Hierarchical Folders and Directories</title>
<!-- reworked this section / as path and its elements / are not supported - dsh - 02-16-12 -->
<para>Although you cannot nest directories in OpenStack
Object Storage, you can simulate a hierarchical
structure within a single container by adding forward
slash characters (<literal>/</literal>) in the object
name. To navigate the pseudo-directory structure, you
may use the <code>delimiter</code> query parameter.
See the below examples for an illustration.</para>
<note>
<para>In the example below, the objects reside in a
container called <code>backups</code>. Within that
container, the objects are organized in a
pseudo-directory called <code>photos</code>. Keep
in mind that the container name is not displayed
in the example, but that it is a part of the
object URLs. For instance, the URL of the picture
<code>me.jpg</code> is
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/backups/photos/me.jpg</uri>.
</para>
</note>
<example>
<title>List Pseudo-Hierarchical Folders/Directories
Request</title>
<para>To display a list of all the objects in the
storage container, use &GET; without a
<code>delimiter</code> or <code>prefix</code>.</para>
<literallayout class="monospaced">GET /v1/AccountString/backups</literallayout>
<para>The system returns status code 2xx (between 200
and 299, inclusive) and the requested list of the
objects.</para>
<literallayout class="monospaced">photos/animals/cats/persian.jpg
photos/animals/cats/siamese.jpg
photos/animals/dogs/corgi.jpg
photos/animals/dogs/poodle.jpg
photos/animals/dogs/terrier.jpg
photos/me.jpg
photos/plants/fern.jpg
photos/plants/rose.jpg</literallayout>
<para>
<!-- The JIRA ticket / doc-97 subsumed / to this location - dsh - 02-03-12 -->Use
the delimiter parameter to limit the displayed
results. Any character may be used as a delimiter.
However, to use <code>delimiter</code> with
pseudo-directories, use the parameter slash
(<literal>/</literal>).</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?delimiter=/</literallayout>
<para>The system returns status code 2xx (between 200
and 299, inclusive) and the requested matching
objects. Because we use the slash, only the
pseudo-directory <code>photos/</code> displays. Keep
in mind that the returned values from a slash
<code>delimiter</code> query are not real objects.
They have a content-type of
<literal>application/directory</literal> and are in
the <literal>subdir</literal> section of json and xml
results.</para>
<literallayout class="monospaced">photos/</literallayout>
<para>Use the <code>prefix</code> parameter with the
<code>delimiter</code> parameter to view the
objects inside a pseudo-directory, including
further nested pseudo-directories.</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?prefix=photos/&#38;delimiter=/</literallayout>
<para>The system returns status code 2xx (between 200
and 299, inclusive) and the objects and
pseudo-directories within the top level
pseudo-directory.</para>
<literallayout class="monospaced">photos/animals/
photos/me.jpg
photos/plants/ </literallayout>
<para>You can create an unlimited number of nested
pseudo-directories. To navigate through them, use
a longer <code>prefix</code> parameter coupled
with the <code>delimiter</code> parameter. In the
sample output below, there is a pseudo-directory
called <code>dogs</code> within the
pseudo-directory <code>animals</code>. In order to
navigate directly to the files contained within
<code>dogs</code>, enter the below command.</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?prefix=photos/animals/dogs/&#38;delimiter=/ </literallayout>
<para>The system returns status code 2xx (between 200
and 299, inclusive) and the objects and
pseudo-directories within the nested pseudo-directory.
</para>
<literallayout class="monospaced">photos/animals/dogs/corgi.jpg
photos/animals/dogs/poodle.jpg
photos/animals/dogs/terrier.jpg</literallayout>
</example>
</section>
</section> </section>
<section xml:id="create-container"> <section xml:id="create-container">
<title>Create Container</title> <title>Create Container</title>
@@ -489,11 +337,11 @@ photos/animals/dogs/terrier.jpg</literallayout>
<example> <example>
<title>View Container Metadata HTTP Response</title> <title>View Container Metadata HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/container-view-metadata-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/container-view-metadata-resp.txt" parse="text"/></literallayout>
</example> </example>-->
<!-- Note: using POST with null value should delete a metadata header, but <!-- Note: using POST with null value should delete a metadata header, but
this method is not functional with all tools, so we are leaving it out for now. this method is not functional with all tools, so we are leaving it out for now.
A future patch may come where using "-" (dash) for the value will delete it. dsh - 2012-0309 --> A future patch may come where using "-" (dash) for the value will delete it. dsh - 2012-0309 -->
</section> <!-- </section>
<section xml:id="delete-container-metadata"> <section xml:id="delete-container-metadata">
<title>Delete Container Metadata</title> <title>Delete Container Metadata</title>
<para>To delete a metadata header send an empty value for that <para>To delete a metadata header send an empty value for that
@@ -514,5 +362,5 @@ photos/animals/dogs/terrier.jpg</literallayout>
<para>No response body is returned. A status code of 2xx <para>No response body is returned. A status code of 2xx
(between 200 and 299, inclusive) indicates success.</para> (between 200 and 299, inclusive) indicates success.</para>
</example> </example>
</section> </section>-->
</section> </section>

View File

@@ -16,7 +16,9 @@
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="storage-object-services"> xml:id="storage-object-services">
<title>Storage Object Services</title> <title>Storage object services</title>
<para>Creates, updates, gets details for, and deletes objects.
Gets and updates object metadata.</para>
<para>An object represents the data and metadata for the files <para>An object represents the data and metadata for the files
stored in the system. Through the ReST interface, you can stored in the system. Through the ReST interface, you can
include metadata for an object by adding custom HTTP headers include metadata for an object by adding custom HTTP headers
@@ -27,7 +29,19 @@
Then, you can download the segments as a single concatenated Then, you can download the segments as a single concatenated
object. You can use HTTP requests to work with the segments object. You can use HTTP requests to work with the segments
and manifests directly.</para> and manifests directly.</para>
<informaltable rules="all"> <wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<wadl:resource
href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#object">
<wadl:method href="#listObjects"/>
<wadl:method href="#retrieveobject"/>
<wadl:method href="#createobject"/>
<wadl:method href="#deleteobject"/>
<wadl:method href="#copyobject"/>
<wadl:method href="#retrieveobjectmeta"/>
<wadl:method href="#updateaobjmeta"/>
</wadl:resource>
</wadl:resources>
<!-- <informaltable rules="all">
<thead> <thead>
<tr> <tr>
<td colspan="1">Verb</td> <td colspan="1">Verb</td>
@@ -205,7 +219,7 @@
</tbody> </tbody>
</informaltable> </informaltable>
<example> <example>
<title>Get Object Details HTTP Request</title> <title>Get Object Details request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-req.txt" parse="text"/></literallayout>
</example> </example>
<para>The object data is returned in the response body. Object <para>The object data is returned in the response body. Object
@@ -214,27 +228,27 @@
inclusive) indicates success; status 404 (Not Found) is inclusive) indicates success; status 404 (Not Found) is
returned if no such object exists.</para> returned if no such object exists.</para>
<example> <example>
<title>Get Object Details HTTP Response</title> <title>Get Object Details response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-resp.txt" parse="text"/></literallayout>
</example> </example>
<para>These examples include an object that contains 10 bytes <para>These examples include an object that contains 10 bytes
of data: <literal>0123456789</literal>.</para> of data: <literal>0123456789</literal>.</para>
<example> <example>
<title>Get Object Details HTTP Request Using Range</title> <title>Get Object Details request: HTTP Using Range</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-range-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-range-req.txt" parse="text"/></literallayout>
</example> </example>
<example> <example>
<title>Get Object Details HTTP Response When Using <title>Get Object Details response: HTTP When Using
Range</title> Range</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-range-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-range-resp.txt" parse="text"/></literallayout>
</example> </example>
<example> <example>
<title>Get Object Details HTTP Request Using Multiple <title>Get Object Details request: HTTP Using Multiple
Ranges</title> Ranges</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-ranges-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-ranges-req.txt" parse="text"/></literallayout>
</example> </example>
<example> <example>
<title>Get Object Details HTTP Response When Using <title>Get Object Details response: HTTP When Using
Multiple Ranges</title> Multiple Ranges</title>
<literallayout class="monospaced"><xi:include href="samples/object-get-ranges-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-get-ranges-resp.txt" parse="text"/></literallayout>
</example> </example>
@@ -256,7 +270,7 @@
object at the specified time and shortly after the object at the specified time and shortly after the
expiration date, it removes the object from the storage expiration date, it removes the object from the storage
system.</para> system.</para>
<para>The HTTP response will include the MD5 checksum of the <para>The response: HTTP will include the MD5 checksum of the
data written to the storage system. If you do not send the data written to the storage system. If you do not send the
ETag in the request, you should compare the value returned ETag in the request, you should compare the value returned
with your content's MD5 locally to perform the end-to-end with your content's MD5 locally to perform the end-to-end
@@ -273,7 +287,7 @@
<literal>allowed_headers</literal> option in the <literal>allowed_headers</literal> option in the
object-server configuration.</para> object-server configuration.</para>
<example> <example>
<title>Create or Update Object HTTP Request</title> <title>Create or Update Object request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-create-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-create-req.txt" parse="text"/></literallayout>
<literallayout class="monospaced">[ ... ]</literallayout> <literallayout class="monospaced">[ ... ]</literallayout>
</example> </example>
@@ -285,7 +299,7 @@
does NOT match the (optionally) supplied ETag value, a 422 does NOT match the (optionally) supplied ETag value, a 422
(Unprocessable Entity) response is returned.</para> (Unprocessable Entity) response is returned.</para>
<example> <example>
<title>Create or Update Object HTTP Response</title> <title>Create or Update Object response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-create-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-create-resp.txt" parse="text"/></literallayout>
</example> </example>
<section xml:id="chunked-transfer-encoding"> <section xml:id="chunked-transfer-encoding">
@@ -308,8 +322,7 @@
you have files that are larger than 5GB see <xref you have files that are larger than 5GB see <xref
linkend="large-object-creation"/>.</para> linkend="large-object-creation"/>.</para>
<example> <example>
<title>Upload Unspecified Quantity of Content HTTP <title>Upload Unspecified Quantity of Contentrequest: HTTP</title>
Request</title>
<literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-req.txt" parse="text"/></literallayout>
</example> </example>
<example> <example>
@@ -318,593 +331,14 @@
<literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/chunked-transfer-encoding-resp.txt" parse="text"/></literallayout>
</example> </example>
</section> </section>
</section> </section>-->
<section xml:id="large-object-creation"> <!-- large object creation -->
<title>Create Large Objects</title> <!-- cors headers -->
<para>The content of an object cannot be larger than 5GB (by <!-- file compression -->
default). However, you can store larger content using two <!-- browser bypass -->
types of objects:</para> <!-- expire object -->
<itemizedlist> <!-- object versioning -->
<listitem> <!-- <section xml:id="copy-object">
<para>Divide your content into pieces and upload each
piece into its own object. These objects are known
as segment objects.</para>
</listitem>
<listitem>
<para>Create a manifest object. A manifest object
"points to" the segment objects.</para>
</listitem>
</itemizedlist>
<para>Segment objects do not have any special features and can
be created, updated, downloaded and deleted as described
elsewhere in this document. However, a manifest object is
special -- when you download, the system concatenates the
contents of the segment objects and returns this in the
response body of the request. This behavior extends to the
response headers returned by &GET; and &HEAD; operations.
The Content-Length is the total size of all segment
objects and the ETag is calculated by taking the ETag
value of each segment, concatenating them together and
then returning the MD5 checksum of the result.</para>
<note>
<para>If you use the &COPY; operation using a manifest
object as the source, the new object is a "normal"
object (not segmented). If the total size of the
source segment objects exceeds 5 GB, the &COPY;
operation fails. However, as explained later, you can
make a duplicate of the manifest object. This new
object can be larger than 5 GB.</para>
</note>
<para>The manifest object type are:</para>
<itemizedlist>
<listitem>
<para>Static large objects. The manifest object
content is an ordered list of the names of the
segment objects in json format.</para>
</listitem>
<listitem>
<para>Dynamic large objects. The manifest object has
no content. However, it has
<code>X-Object-Manifest</code> metadata. The
value of this is
<code>&lt;container>/&lt;prefix></code>, where
<code>&lt;container></code> is the name of the
container where the segment objects are stored and
<code>&lt;prefix></code> is a string that all
the segment objects have in common.</para>
</listitem>
</itemizedlist>
<para>While both types of manifest objects have similar
behavior, there are differences as explained in the
following table.</para>
<table rules="all">
<caption>Comparison of Static and Dynamic Large
Objects</caption>
<thead>
<tr>
<th>Feature</th>
<th>Static Large Object</th>
<th>Dynamic Large Object</th>
</tr>
</thead>
<tbody>
<tr>
<td>End-to-end integrity</td>
<td>Assured. The list of segments includes the MD5
checksum (ETag) of each segment. You cannot
upload the manifest object if the ETag in the
list differs from the segment object already
uploaded. If a segment is somehow lost, an
attempt to download the manifest object will
result in an error.</td>
<td>Not guaranteed. The eventual consistency model
means that although you may have uploaded a
segment object, it may not appear in the
container listing until later. If you download
the manifest before it appears in the
container, it will not form part of the
content returned in response to a &GET;
request.</td>
</tr>
<tr>
<td>Upload order</td>
<td>The segment objects must be uploaded before
the manifest object.</td>
<td>You can upload manifest and segment objects in
any order. You are recommended to upload the
manifest object after the segments in case a
premature download of the manifest occurs.
However, this is not enforced.</td>
</tr>
<tr>
<td>Removal or addition of segment objects</td>
<td>You cannot add or remove segment objects from
the manifest. However, you can create a
completely new manifest object of the same
name with a different manifest list.</td>
<td>You can upload new segment objects or remove
existing segments --- the names must simply
match the <code>&lt;prefix></code> supplied in
<code>X-Object-Manifest</code>.</td>
</tr>
<tr>
<td>Segment object size and number</td>
<td>Segment objects must be at least 1MB in size
(by default). The final segment object can be
any size. At most 1000 segments are supported
(by default).</td>
<td>Segment objects can be of any size.</td>
</tr>
<tr>
<td>Segment object container name</td>
<td>The manifest list includes the container name
of each object, i.e., segment objects may be
in different containers.</td>
<td>All segment objects must be in the same
container</td>
</tr>
<tr>
<td>Manifest Object Metadata</td>
<td>The object has
<code>X-Static-Large-Object</code> set to
<code>true</code>. You do not set this
metadata directly. Instead the system sets it
when you &PUT; a static manifest object.</td>
<td>The <code>X-Object-Manifest</code> value is
the <code>&lt;container>/&lt;prefix></code>
indicating where the segment objects are
located. You supply this request header in the
&PUT; operation</td>
</tr>
<tr>
<td>Making a copy of the manifest object</td>
<td>To make a copy of the manifest object, include
the <code>?multipart-manifest=get</code> query
string with the &COPY; operation. The new
object contains the same manifest as the
original. The segment objects are not copied.
Instead, both the original and new manifest
objects share the same set of segment
objects.</td>
<td>The &COPY; operation does not create a
manifest object. To duplicate a manifest
object, use the &GET; operation to read the
value of <code>X-Object-Manifest</code> and
use this value in the
<code>X-Object-Manifest</code> request
header in a &PUT; operation. This creates a
new manifest object that shares the same set
of segment objects as the original manifest
object.</td>
</tr>
</tbody>
</table>
<section xml:id="dynamic-large-object-creation">
<title>Dynamic Large Objects</title>
<para>Objects that are larger than 5GB must be segmented,
prior to upload. You then upload the segments like you
would any other object and create a dynamic large
manifest object telling OpenStack Object Storage how
to find the segments of the large object. The segments
remain individually addressable, but retrieving the
manifest object streams all the segments concatenated.
There is no limit to the number of segments that can
be a part of a single large object.</para>
<para>To ensure the download works correctly, you must
upload all the object segments to the same container
and ensure that each object name is prefixed in such a
way that it sorts in the order in which it should be
concatenated. You also create and upload a manifest
file. The manifest file is a zero-byte file with the
extra X-Object-Manifest:
&lt;container&gt;/&lt;prefix&gt; header, where
&lt;container&gt; is the container the object segments
are in and &lt;prefix&gt; is the common prefix for all
the segments. The container and common prefix must be
UTF-8 encoded and URL-encoded in the X-Object-Manifest
header.</para>
<para>It is best to upload all the segments first and then
create or update the manifest. With this method, the
full object will not be available for downloading
until the upload is complete. Also, you can upload a
new set of segments to a second location and then
update the manifest to point to this new location.
During the upload of the new segments, the original
manifest will still be available to download the first
set of segments.</para>
<example>
<title>Upload Segment of Large Object HTTP
Request</title>
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-segment-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload Segment of Large Object HTTP
Response</title>
<literallayout class="monospaced">s</literallayout>
</example>
<para>No response body is returned. A status code of 2xx
(between 200 and 299, inclusive) indicates a
successful write; status 411 (Length Required) denotes
a missing <code>Content-Length</code> or
<code>Content-Type</code> header in the request.
If the MD5 checksum of the data written to the storage
system does NOT match the (optionally) supplied ETag
value, a 422 (Unprocessable Entity) response is
returned.</para>
<para>You can continue uploading segments like this
example shows, prior to uploading the manifest.</para>
<example>
<title>Upload Next Segment of Large Object HTTP
Request</title>
<literallayout class="monospaced"><xi:include href="samples/large-object-upload-next-segment-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload Next Segment of Large Object HTTP
Response</title>
<literallayout class="monospaced">w</literallayout>
</example>
<para>Next, upload the manifest you created that indicates
the container the object segments reside within. Note
that uploading additional segments after the manifest
is created will cause the concatenated object to be
that much larger but you do not need to recreate the
manifest file for subsequent additional
segments.</para>
<example>
<title>Upload Manifest HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Upload Manifest HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/upload-manifest-resp.txt" parse="text"/></literallayout>
</example>
<para>The response's Content-Type for a &GET; or &HEAD; on
the manifest will be the same as the Content-Type set
during the PUT request that created the manifest. You
can easily change the Content-Type by reissuing the
&PUT; request.</para>
</section>
<section xml:id="static-large-objects">
<title>Static Large Objects</title>
<para>To create a static large object:</para>
<orderedlist>
<listitem>
<para>Divide your content into pieces and create
(upload) a segment object to contain each
piece. You must record the <code>ETag</code>
response header returned by the&PUT;
operation. Alternatively, you can calculate
the MD5 checksum of the segment prior to
uploading and include this in the
<code>ETag</code> request header. This
ensures that the upload cannot corrupt your
data.</para>
</listitem>
<listitem>
<para>List the name of each segment object along
with its size and MD5 checksum in order.
Create a manifest object. You indicate that
this is a manifest object by including the
<code>?multipart-manifest=put</code> query
string at the end of the manifest object
name.</para>
</listitem>
</orderedlist>
<para>The body of the &PUT; request on the manifest object
comprises a json list, where each element contains the
following:</para>
<itemizedlist>
<listitem>
<para><code>path</code> - this is the container
and object name in the following format:
<code>&lt;container-name>/&lt;object-name></code></para>
</listitem>
<listitem>
<para><code>etag</code> - this is the MD5 checksum
of the content of the segment object. This
must match the <code>ETag</code> of that
object.</para>
</listitem>
<listitem>
<para><code>size_bytes</code> - this is the size
of the segment object. This must match the
<code>Content-Length</code> of that
object</para>
</listitem>
</itemizedlist>
<example>
<title>Static Large Object Manifest List</title>
<para>This is an example containing three segment
objects. In this example, you can use several
containers and the object names do not have to
conform to a specific pattern, in contrast to
dynamic large objects.</para>
<literallayout class="monospaced"><xi:include href="samples/slo-manifest-example.txt" parse="text"/></literallayout>
</example>
<para>The <code>Content-Length</code> request header must
contain the length of the json content -- not the
length of the segment objects. However, after the
&PUT; operation completes, the
<code>Content-Length</code> metadata is set to the
total length of all the object segments. A similar
situation applies to the <code>ETag</code>. If used in
the &PUT; operation, it must contain the MD5 checksum
of the json content. The <code>ETag</code> metadata
value is then set to be the MD5 checksum of the
concatenated <code>ETag</code> values of the object
segments. You may also set the
<code>Content-Type</code> request header and
custom object metadata.</para>
<para>When the &PUT; operation sees the
<code>?multipart-manifest=put</code> query string,
it reads the request body and verifies that each
segment object exists and that the sizes and ETags
match. If there is a mismatch, the &PUT;operation will
fail.</para>
<para>If everything matches, the manifest object is
created. The <code>X-Static-Large-Object</code>
metadata is set to <code>true</code> indicating that
this is a static object manifest.</para>
<para>Normally when you perform a &GET; operation on the
manifest object, the response body contains the
concatenated content of the segment objects. To
download the manifest list, use the query string
<code>?multipart-manifest=get</code>. The
resulting list will not be identically formatted as
the manifest you originally used in the &PUT;
operation.</para>
<para>If you use the &DELETE; operation on a manifest
object, the manifest object is deleted -- the segment
objects are not affected. However, if you add the
query parameter
<code>?multipart-manifest=delete</code>, the
segment objects are deleted and if all are
successfully deleted, the manifest object is also
deleted.</para>
<para>To change the manifest, use a &PUT; operation with
the <code>?multipart-manifest=put</code> query string.
This will create a <emphasis>new</emphasis> manifest
object. You may also update the object metadata in the
usual way.</para>
</section>
</section>
<section xml:id="assigning-cors-headers-to-requests">
<title>Assigning CORS Headers to Requests</title>
<para>CORS is a specification that stands for Cross-Origin
Resource Sharing. It defines how browsers and servers
communicate across origins using HTTP headers, such as
those assigned by Object Storage API requests. These
headers are supported with the Object Storage API. You can
read more about the definition of the Access-Control-
response headers and Origin response header at <link
xlink:href="http://www.w3.org/TR/access-control/"
>www.w3.org/TR/access-control/</link>.<itemizedlist>
<listitem>
<para>Access-Control-Allow-Credentials</para>
</listitem>
<listitem>
<para>Access-Control-Allow-Methods</para>
</listitem>
<listitem>
<para>Access-Control-Allow-Origin</para>
</listitem>
<listitem>
<para>Access-Control-Expose-Headers</para>
</listitem>
<listitem>
<para>Access-Control-Max-Age</para>
</listitem>
<listitem>
<para>Access-Control-Request-Headers</para>
</listitem>
<listitem>
<para>Access-Control-Request-Method</para>
</listitem>
<listitem>
<para>Origin</para>
</listitem>
</itemizedlist></para>
<para>You can assign these headers to objects only.</para>
<example>
<title>Assign CORS Header HTTP Request</title>
<para>In the example, the origin header is assigned that
indicates where the file came from. This allows you to
provide security that requests to your Object Storage
repository are indeed from the correct
origination:</para>
<literallayout class="monospaced"><xi:include href="samples/object-assign-cors-header-req.txt" parse="text"/></literallayout>
</example>
</section>
<section
xml:id="enabling-file-compression-with-content-encoding-header">
<title>Enabling File Compression with the Content-Encoding
Header</title>
<para>The Content-Encoding header allows a file to be
compressed without losing the identity of the underlying
media type of the file, for example, a video.</para>
<example>
<title>Content-Encoding Header HTTP Request</title>
<para>In the example, the content-encoding header is
assigned with an attachment type that indicates how
the file should be downloaded:</para>
<literallayout class="monospaced"><xi:include href="samples/content-encoding-header-req.txt" parse="text"/></literallayout>
</example>
</section>
<section
xml:id="enabling-browser-bypass-with-content-disposition-header">
<title>Enabling Browser Bypass with the Content-Disposition
Header</title>
<para>When an object is assigned the Content-Disposition
header you can override a browser's default behavior for a
file so that the download program saves the file rather
than displaying it using default browser settings.</para>
<example>
<title>Content-Disposition Header HTTP Request</title>
<para>In the example, the content-encoding header is
assigned with an attachment type that indicates how
the file should be downloaded.</para>
<literallayout class="monospaced"><xi:include href="samples/content-disposition-header-req.txt" parse="text"/></literallayout>
</example>
</section>
<section xml:id="Expiring_Objects-e1e3228">
<title>Expiring Objects with the X-Delete-After and
X-Delete-At Headers</title>
<para>When an object is assigned either an
<code>X-Delete-After</code> or
<code>X-Delete-At</code> header when doing a &PUT; or
&POST; on the object, it is scheduled for deletion. This
feature is helpful for objects you do not want to
permanently store, such as log files, recurring full
backups of a dataset, or documents or images you know will
be outdated at a future time.</para>
<para>The <code>X-Delete-At</code> header requires a Unix
Epoch timestamp, in integer form; for example: 1348691905
represents Wed, 26 Sep 2012 20:38:25 GMT.
<!-- Exchanged POSIX in / favor of Epoch for the / sake of clarity dsh 02-06-12 -->By
setting the header to a specific Epoch time, you indicate
when you want the object to expire, not be served, and be
deleted completely from the storage system.</para>
<para>The <code>X-Delete-After</code> header takes an integer
number of seconds and calculates the amount of time from
now that you want the object to be deleted. The proxy
server that receives the request converts this header into
an <code>X-Delete-At</code> header and calculates the
deletion time using its current time plus the value given
in seconds.</para>
<para>For existing objects that you want to assign expiration
headers to, use the &POST; operation.</para>
<example>
<title>Delete Object at HTTP Request</title>
<para>In the example, the <code>X-Delete-At</code> header
is assigned with a Unix Epoch timestamp in integer
form for Mon, 11 Jun 2012 15:38:25 GMT. Use <link
xlink:href="http://www.epochconverter.com/"
>http://www.epochconverter.com/</link> for example
timestamps and a batch converter.</para>
<literallayout class="monospaced"><xi:include href="samples/object-delete-at-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Delete Object after HTTP Request</title>
<para><!-- Reworded this here / paragraph to make more sense / and match what I see dsh 02-06-12 -->In
this example, the <code>X-Delete-After</code> header
is assigned a value in seconds, equivalent to 10 days.
After this time, the object expires.</para>
<!-- Removed, "The system then converts the time necessary for an <code>X-Delete-At</code> header operation." Doesn't seem to match dsh 02-06-12-->
<literallayout class="monospaced"><xi:include href="samples/object-delete-after-req.txt" parse="text"/></literallayout>
</example>
</section>
<section xml:id="Object_Versioning-e1e3230">
<!-- begin 4.3.2.7 -->
<title>Object Versioning</title>
<para>Object versioning allows you to store multiple versions
of your content to recover from unintended overwrites. It
provides an easy method to implement version control which
can be used on any type of content. It is strongly
recommended that you put non-current objects in a
container apart from where the current versions exist.
Once you enable Object Versioning on a container (such as
a "current version" container), &PUT;s to existing objects
in that container copy the prior object to a separate
"non-current version" container. Each of the non-current
versions of an object has a time stamp appended to it, so
you know when it was created.</para>
<para>To enable object versioning, your cloud provider has to
set <code>allow_versions</code> to <code>TRUE</code> in
their container config. Then, create a container where
your non-current versions will be written. Next, set the
metadata <code>X-Versions-Location</code> header on the
container that holds the current versions of your objects.
Set the metadata header to point to the new non-current
version container you created. The name of the container
must be UTF-8 encoded and then URL-encoded before putting
into the <code>X-Versions-Location</code> header. This is
where your non-current versions will be stored. Once this
is done, each object in your current-version container
will have Object Versioning enabled; changes to the
objects automatically create non-current versions in the
separate container.</para>
<para>Nothing is written to the non-current version container
when you initially &PUT; an object into the
current-version container. Only when you make edits to the
objects via &PUT; will you create non-current versions.
These non-current versions are labeled according to the
schema below.</para>
<para>
<emphasis>Naming Schema:</emphasis> Non-current versions
are assigned the name
&lt;length&gt;&lt;object_name&gt;/&lt;timestamp&gt;, where
length is the 3-character zero-padded hexadecimal
character length of the &lt;object_name&gt; and
&lt;timestamp&gt; is when the it was initially created as
a current version.</para>
<para>Any return status in the 2xx range, such as 202
(Accepted), denotes success. Status codes in the 4xx or
5xx range denote failure. You should retry your request if
you receive an error. Please note, however, that if you
have specified a container that does not exist as your
non-current version container, a status of 412
(Precondition Failed) returns when you edit the versioned
object. If you receive this error, check that the
container exists.</para>
<para>A &GET; to a versioned object returns the current
version of the object without having to do any request
redirects or metadata lookups.</para>
<para>A &POST; to a versioned object only updates the object's
metadata; it does not create a new version of the object.
In other words, new versions are only created when the
content of the object changes.</para>
<para>A &DELETE; to a versioned object removes the current
version of the object and replaces it with the next-most
current version, moving it from the non-current container
to the current. This next-most current version carries
with it any metadata last set on it. If want to completely
remove an object and you have five total versions of it,
you must &DELETE; it five times.</para>
<note>
<para>A large-object manifest file cannot be versioned,
but it may point to versioned segments.</para>
</note>
<para>To turn off Object Versioning on your current version
container, remove its <code>X-Versions-Location</code>
metadata by sending an empty key value.</para>
<example>
<title>Object Versioning with cURL</title>
<para>Make sure a version-storing container exists,
creating it if necessary (this example names it
"versions"). Then create a container with the
<code>X-Versions-Location</code> header. In this
example, this container is named "current". You can
also add the <code>X-Versions-Location</code> header
to an existing container. In this example, the name of
the container is “versions”; the location for the
current version is the container "current".</para>
<para>Create a container named versions.</para>
<screen><prompt>$</prompt> <userinput>curl -i -XPUT -H "X-Auth-Token: &lt;token&gt;" http://&lt;storage_url&gt;/versions</userinput></screen>
<para>Create a container named current with the
<code>X-Versions-Location</code> header that
references "versions".</para>
<screen><prompt>$</prompt> <userinput>curl -i -XPUT -H "X-Auth-Token: &lt;token&gt;" \
-H "X-Versions-Location: versions" http://&lt;storage_url&gt;/current</userinput></screen>
<para>Create an object (the first version):</para>
<screen><prompt>$</prompt> <userinput>curl -i -XPUT --data-binary 1 -H "X-Auth-Token: &lt;token&gt;" \
http://&lt;storage_url&gt;/current/myobject</userinput></screen>
<para>Now create a new version of that object:</para>
<screen><prompt>$</prompt> <userinput>curl -i -XPUT --data-binary 2 -H "X-Auth-Token: &lt;token&gt;" \
http://&lt;storage_url&gt;/current/myobject</userinput></screen>
<para>See a listing of the older versions of the
object:</para>
<screen><prompt>$</prompt> <userinput>curl -i -H "X-Auth-Token: &lt;token&gt;" \
http://&lt;storage_url&gt;/versions?prefix=008myobject/</userinput></screen>
<para>Now delete the current version of the object and see
that the older version is gone:</para>
<screen><prompt>$</prompt> <userinput>curl -i -XDELETE -H "X-Auth-Token: &lt;token&gt;" \
http://&lt;storage_url&gt;/current/myobject</userinput></screen>
<screen><userinput><prompt>$</prompt> curl -i -H "X-Auth-Token: &lt;token&gt;" \
http://&lt;storage_url&gt;/versions?prefix=008myobject/</userinput></screen>
</example>
</section>
<section xml:id="copy-object">
<title>Copy Object</title> <title>Copy Object</title>
<para>Suppose you upload a file with the wrong object name or <para>Suppose you upload a file with the wrong object name or
content type, or you needed to move some objects to content type, or you needed to move some objects to
@@ -990,7 +424,7 @@
time. Refer to <link linkend="Expiring_Objects-e1e3228" time. Refer to <link linkend="Expiring_Objects-e1e3228"
>Expiring Objects</link> for more details.</para> >Expiring Objects</link> for more details.</para>
<example> <example>
<title>Object Delete HTTP Request</title> <title>Object Delete request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-delete-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-delete-req.txt" parse="text"/></literallayout>
</example> </example>
<para>No response body is returned. A status code of 2xx ( <para>No response body is returned. A status code of 2xx (
@@ -998,7 +432,7 @@
code 404 (Not Found) is returned when the object does not code 404 (Not Found) is returned when the object does not
exist.</para> exist.</para>
<example> <example>
<title>Object Delete HTTP Response</title> <title>Object Delete response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-delete-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-delete-resp.txt" parse="text"/></literallayout>
</example> </example>
</section> </section>
@@ -1009,7 +443,7 @@
<para>The only required header to be sent in the request is <para>The only required header to be sent in the request is
the authorization token.</para> the authorization token.</para>
<example> <example>
<title>Get Object Metadata HTTP Request</title> <title>Get Object Metadata request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-metadata-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-metadata-req.txt" parse="text"/></literallayout>
</example> </example>
<para>No response body is returned. Metadata is returned as <para>No response body is returned. Metadata is returned as
@@ -1017,7 +451,7 @@
inclusive) indicates success; status 404 (Not Found) is inclusive) indicates success; status 404 (Not Found) is
returned when the object does not exist.</para> returned when the object does not exist.</para>
<example> <example>
<title>Get Object Metadata HTTP Response</title> <title>Get Object Metadata response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-metadata-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-metadata-resp.txt" parse="text"/></literallayout>
</example> </example>
</section> </section>
@@ -1040,7 +474,7 @@
delete all existing metadata added with a previous delete all existing metadata added with a previous
&PUT;/&POST;.</para> &PUT;/&POST;.</para>
<example> <example>
<title>Update Object Metadata HTTP Request</title> <title>Update Object Metadata request: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-update-metadata-req.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-update-metadata-req.txt" parse="text"/></literallayout>
</example> </example>
<para>No response body is returned. A status code of 2xx <para>No response body is returned. A status code of 2xx
@@ -1048,8 +482,8 @@
404 (Not Found) is returned if the requested object does 404 (Not Found) is returned if the requested object does
not exist.</para> not exist.</para>
<example> <example>
<title>Update Object Metadata HTTP Response</title> <title>Update Object Metadata response: HTTP</title>
<literallayout class="monospaced"><xi:include href="samples/object-update-metadata-resp.txt" parse="text"/></literallayout> <literallayout class="monospaced"><xi:include href="samples/object-update-metadata-resp.txt" parse="text"/></literallayout>
</example> </example>
</section> </section>-->
</section> </section>

View File

@@ -1,325 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY COPY '<command xmlns="http://docbook.org/ns/docbook">COPY</command>'>
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
<!ENTITY CHECK '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Check_mark_23x20_02.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
<!ENTITY ARROW '<inlinemediaobject xmlns="http://docbook.org/ns/docbook">
<imageobject>
<imagedata fileref="img/Arrow_east.svg"
format="SVG" scale="60"/>
</imageobject>
</inlinemediaobject>'>
]>
<section xml:id="storage-account-services" <section xml:id="storage-account-services"
xmlns="http://docbook.org/ns/docbook" xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"> xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
<title>Storage Account Services</title> <title>Storage account services</title>
<para>Perform the following operations at the account level of the <para>Lists containers and gets, creates, updates, or deletes
URL:</para> account metadata. You can perform these actions at the account
<informaltable rules="all"> level of the storage system.</para>
<thead> <wadl:resources xmlns:wadl="http://wadl.dev.java.net/2009/02">
<tr> <wadl:resource
<td colspan="1">Verb</td> href="http://git.openstack.org/cgit/openstack/api-site/plain/api-ref/src/wadls/object-api/src/os-object-api-1.0.wadl#account">
<td colspan="2">URI</td> <wadl:method href="#listContainers"/>
<td colspan="3">Description</td> <wadl:method href="#retrieveaccountmeta"/>
</tr> <wadl:method href="#updateaccountmeta"/>
</thead> <wadl:method href="#deleteaccountmeta"/>
<tbody> </wadl:resource>
<tr> </wadl:resources>
<td colspan="1">&GET;</td>
<td colspan="2">/<parameter>account</parameter></td>
<td colspan="3">Lists containers.</td>
</tr>
<tr>
<td colspan="1">&HEAD;</td>
<td colspan="2">/<parameter>account</parameter></td>
<td colspan="3">Gets account metadata.</td>
</tr>
<tr>
<td colspan="1">&POST;</td>
<td colspan="2">/<parameter>account</parameter></td>
<td colspan="3">Creates or updates account
metadata.</td>
</tr>
<tr>
<td colspan="1">&POST;</td>
<td colspan="2">/<parameter>account</parameter></td>
<td colspan="3">Deletes account metadata.</td>
</tr>
</tbody>
</informaltable>
<variablelist>
<title>Optional headers for HEAD and GET</title>
<varlistentry>
<term><code>X-Newest</code></term>
<listitem>
<para>Set the optional <code>X-newest</code> header to
<code>True</code> in HEAD and GET requests to have
Object Storage return the latest version of the account.
If set to <code>True</code>, Object Storage queries all
replicas to return the most recent one. Without this header,
Object Storage responds faster after it finds one valid replica.
Because setting this header to <code>True</code> is more
expensive for the back end, use it only when it is
absolutely needed.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>For example, the URL for the requests end with the OpenStack
Object Storage account string, as follows:</para>
<example>
<title>Storage Account Services HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/object-api-general-req.txt" parse="text"/></literallayout>
</example>
<section xml:id="s_listcontainers">
<title>List Containers</title>
<para>&GET; operations against the <code>X-Storage-Url</code>
for an account are performed to list storage containers
sorted by name. The sort order for the name is based on a
<link
xlink:href="http://www.sqlite.org/datatype3.html#collation"
>binary comparison</link>, a single built-in collating
sequence that compares string data by using the SQLite
memcmp() function, regardless of text encoding. The
following list describes the optional query parameters
that are supported with this request.</para>
<variablelist>
<title>Query Parameters</title>
<varlistentry>
<term><code>limit</code></term>
<listitem>
<para>For an integer value <inlineequation>
<mathphrase><emphasis>n</emphasis></mathphrase>
</inlineequation>, limits the number of
results to <inlineequation>
<mathphrase><emphasis>n</emphasis></mathphrase>
</inlineequation> values.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><code>marker</code></term>
<listitem>
<para>Given a string value <inlineequation>
<mathphrase><emphasis>x</emphasis></mathphrase>
</inlineequation>, return container names
greater in value than the specified
marker.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><code>end_marker</code></term>
<listitem>
<para>Given a string value <inlineequation>
<mathphrase><emphasis>x</emphasis></mathphrase>
</inlineequation>, return container names less
in value than the specified marker.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><code>format</code></term>
<listitem>
<para>Specify either <code>json</code> or
<code>xml</code> to return the respective
serialized response.</para>
</listitem>
</varlistentry>
</variablelist>
<para>At this time, a <code>prefix</code> query parameter is
not supported at the account level.</para>
<example>
<title>List Containers HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/containers-list-req.txt" parse="text"/></literallayout>
</example>
<para>A list of containers is returned in the response body,
one container per line. The HTTP response's status code
will be 2xx (between 200 and 299, inclusive).</para>
<example>
<title>List Containers HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/containers-list-resp.txt" parse="text"/></literallayout>
</example>
<section xml:id="s_serializedlistoutput">
<title>Serialized List Output</title>
<para>If a <code>format=xml</code> or
<code>format=json</code> argument is appended to
the storage account URL, the service serves extended
container information serialized in the chosen format.
The sample responses are formatted for readability.</para>
<para>The following HTTP request asks for a JSON response,
so the response returns an HTTP header and a JSON
response.</para>
<example>
<title>Get Containers Details HTTP and JSON
Request</title>
<literallayout class="monospaced"><xi:include href="samples/container-get-details-json-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>Get Containers Details HTTP and JSON
Response</title>
<literallayout class="monospaced"><xi:include href="samples/container-get-details-http-json-resp.txt" parse="text"/></literallayout>
<programlisting language="json"><xi:include href="samples/container-get-details-resp.json" parse="text"/></programlisting>
</example>
<para>The following HTTP request asks for an XML response,
so the response returns an HTTP header and an XML
response.</para>
<example>
<title>Containers Details HTTP and XML Request</title>
<literallayout class="monospaced"><xi:include href="samples/container-get-details-http-xml-resp.txt" parse="text"/></literallayout>
</example>
<example>
<title>Containers Details HTTP and XML
Response</title>
<literallayout class="monospaced"><xi:include href="samples/container-get-details-http-xml-resp.txt" parse="text"/></literallayout>
<programlisting language="xml"><xi:include href="samples/container-get-details-resp.xml" parse="text"/></programlisting>
</example>
</section>
<section xml:id="s_list-large-number-containers">
<title>Controlling a Large List of Containers</title>
<para>The system returns a maximum of 10,000 container
names per request. To retrieve subsequent container
names, another request must be made with the 'marker'
parameter. The marker indicates where the last list
left off; the system returns container names greater
than this marker, up to 10,000 again. Note that the
marker value should be URL-encoded prior to sending
the HTTP request.</para>
<para>If 10,000 is larger than desired, use the 'limit'
parameter.</para>
<para>If the number of container names returned equals the
limit given (or 10,000 if no limit is given), you may
assume there are more container names.</para>
<example>
<title>List Large Number of Containers</title>
<para>For example, let's use a listing of five
container names:</para>
<literallayout class="monospaced">apples
bananas
kiwis
oranges
pears</literallayout>
<para>We'll use a limit of two to show how things
work:</para>
<literallayout class="monospaced"><xi:include href="samples/large-container-list-req.txt" parse="text"/></literallayout>
<literallayout class="monospaced">apples
bananas</literallayout>
<para>Because we received two items back, we can
assume there are more container names to list, so
we make another request with a marker of the last
item returned:</para>
<literallayout class="monospaced"><xi:include href="samples/large-container-list-filter-req.txt" parse="text"/></literallayout>
<literallayout class="monospaced">kiwis
oranges</literallayout>
<para>Again, two items are returned; there might be
more:</para>
<literallayout class="monospaced"><xi:include href="samples/large-container-list-filter2-req.txt" parse="text"/></literallayout>
<literallayout class="monospaced">pears</literallayout>
<para>With this one-item response we received less
than the limit number of container names,
indicating that this is the end of the
list.</para>
<para>By using <code>end_marker</code> we can limit
the result set to container names less than the
given value.</para>
<literallayout class="monospaced"><xi:include href="samples/large-container-list-filter-end-marker-req.txt" parse="text"/></literallayout>
<literallayout class="monospaced">apples
bananas
kiwis</literallayout>
</example>
</section>
</section>
<section xml:id="retrieve-account-metadata">
<title>Get Account Metadata</title>
<para>&HEAD; operations against an account are performed to
retrieve the number of containers and the total bytes
stored in OpenStack Object Storage for the account. This
information is returned in two custom headers,
<code>X-Account-Container-Count</code> and
<code>X-Account-Bytes-Used</code>. Since the storage
system is designed to store large amounts of data, care
should be taken when representing the total bytes response
as an integer; when possible, convert it to a 64-bit
unsigned integer if your platform supports that primitive
type.</para>
<example>
<title>Get Account Metadata HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/account-get-metadata-req.txt" parse="text"/></literallayout>
</example>
<para>The HTTP return code will be 2xx (between 200 and 299,
inclusive) if the request succeeds. A 401 (Unauthorized)
will be returned for an invalid account or access
key.</para>
<example>
<title>Get Account Metadata HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/account-get-metadata-resp.txt" parse="text"/></literallayout>
</example>
</section>
<section xml:id="create-update-account-metadata">
<title>Create or Update Account Metadata</title>
<para>You can associate custom metadata headers with the
account level URI. These headers must take the format
<code>X-Account-Meta-*</code>.</para>
<para>To create or update an account metadata header use the
&POST; query. Subsequent requests for the same key/value
pair overwrite the previous value.</para>
<example>
<title>Update Account Metadata HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/account-update-metadata-req.txt" parse="text"/></literallayout>
</example>
<para>No response body is returned. A status code of 2xx
(between 200 and 299, inclusive) indicates success.</para>
<example>
<title>Update Account Metadata HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/account-update-metadata-resp.txt" parse="text"/></literallayout>
</example>
<para>To confirm your metadata changes, perform a &HEAD;
request on the account. Do not send the metadata in your
&HEAD; request.</para>
<example>
<title>View Account Metadata HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/account-view-metadata-req.txt" parse="text"/></literallayout>
</example>
<example>
<title>View Account Metadata HTTP Response</title>
<literallayout class="monospaced"><xi:include href="samples/account-view-metadata-resp.txt" parse="text"/></literallayout>
</example>
</section>
<section xml:id="delete-account-metadata">
<title>Delete Account Metadata</title>
<para>To delete a metadata header, send an empty value for
that particular header, such as for the
<code>X-Account-Meta-Book</code> header.</para>
<para>If the tool you use to communicate with Object Storage,
such as older versions of cURL, does not support empty
headers, send the
<literal>X-Remove-Account-Meta-</literal><replaceable>name</replaceable><literal>:</literal>
<replaceable>arbitrary value</replaceable> header. For
example, <code>X-Remove-Account-Meta-Book: x</code>. The
<replaceable>arbitrary value</replaceable> is
ignored.</para>
<example>
<title>Delete Account Metadata HTTP Request</title>
<literallayout class="monospaced"><xi:include href="samples/account-delete-metadata-req.txt" parse="text"/></literallayout>
<para>No response body is returned. A status code from 200
to 299 indicates success.</para>
</example>
</section>
</section> </section>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="archive-auto-extract">
<title>Auto-extract archive files</title>
<para>Use the auto-extract archive feature to upload a tar(1)
archive file. </para>
<para>The Object Storage system extracts files from the archive
file and creates an object.</para>
<section xml:id="archive-auto-extract-put">
<title>Auto-extract archive PUT request</title>
<para>To upload an archive file, you make a &PUT; request. Add
the
<parameter>extract-archive=<replaceable>format</replaceable></parameter>
query parameter to indicate that you are uploading a
tar(1) archive file instead of normal content. </para>
<para>Valid values for the <replaceable>format</replaceable>
variable are <literal>tar</literal>,
<literal>tar.gz</literal>, or
<literal>tar.bz2</literal>.</para>
<para>The path you specify in the &PUT; request is a prefix
for the resulting object names. For example, if the first
object in the tar(1) archive is
<filename>/home/file1.txt</filename>, a path of
<filename>/v1/12345678912345/mybackup/castor/</filename>
results in an object name of
<filename>castor/home/file1.txt</filename> in the
<literal>mybackup</literal> container in the
<literal>12345678912345</literal> account. </para>
<para>In the &PUT; request, you can specify the path
for:</para>
<itemizedlist>
<listitem>
<para>An account</para>
</listitem>
<listitem>
<para>A specific container</para>
</listitem>
<listitem>
<para>A specific object prefix</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="archive-auto-extract-create">
<title>Create an archive for auto-extract</title>
<para>You must use the tar(1) utility to create the tar(1)
archive file.</para>
<para>You can upload only regular files and you cannot upload
other items, such as empty directories, symbolic links,
and so on.</para>
<para>You must UTF-8-encode the member names.</para>
<para>The archive auto-extract feature supports these
formats:</para>
<itemizedlist>
<listitem>
<para>The POSIX.1-1988 (ustar) format.</para>
</listitem>
<listitem>
<para>The GNU tar format, including longname and
longlink extensions and the sparse
extension.</para>
</listitem>
<listitem>
<para>The POSIX.1-2001 (pax) format.</para>
<para>You can compress the archive by using gzip(1) or
bzip2(1).</para>
<para>Use the <parameter>extract-archive</parameter>
query parameter to specify the format. Specify
<literal>tar</literal>,
<literal>tar.gz</literal>, or
<literal>tar.bz2</literal> as the
format.</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="archive-auto-extract-response">
<title>Auto-extract archive response: JSON</title>
<para>When the request is processed by the system, you are in
effect performing multiple sub-operations. Even if all
sub-operations fail, the operation will return a 201
Created status. You must examine the response body to
determine which members failed to result in an object
creation. You can use the Accept request header to
indicate the format of the response body as follows: -
text/plain. Plain text. This is the default if the Accept
header is not specified. - application/json. Format as
JSON - application/xml or text/xml. Format as XML See
(xref to Response Body for Bulk Operations) for more
information.</para>
</section>
</section>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="authentication">
<title>Authentication</title>
<para>The <emphasis role="italic">owner</emphasis> of an Object
Storage account controls access to that account and its
containers and objects. An owner is the user who has the
<literal>admin</literal> role for that tenant. The tenant
is also known as the project or account. As the account owner,
you can modify account metadata and create, modify, and delete
containers and objects.</para>
<para>To identify yourself as the account owner, include an
authentication token in the <literal>X-Auth-Token</literal>
header in the API request. </para>
<para>Depending on the token value in the
<literal>X-Auth-Token</literal> header, one of the
following actions occur:</para>
<itemizedlist>
<listitem>
<para><literal>X-Auth-Token</literal> contains the token
for the account owner.</para>
<para>The request is permitted and has full access to make
changes to the account.</para>
</listitem>
<listitem>
<para>The <literal>X-Auth-Token</literal>header is omitted
or it contains a token for a non-owner or a token that
is not valid.</para>
<para>The request fails with a <errorcode>401</errorcode>
<errortext>Unauthorized</errortext> or
<errorcode>403</errorcode>
<errortext>Forbidden</errortext>response. </para>
<para>You have no access to accounts or containers, unless
an access control list (ACL) explicitly grants
access.</para>
<para>The account owner can grant account and container
access to users through access control lists (ACLs).
For more information about ACLs, see <xref
linkend="special-metadata-acls"/>.</para>
</listitem>
</itemizedlist>
<para>The following table describes the authentication services
that you can use with Object Storage:</para>
<informaltable rules="all">
<thead>
<tr>
<th>Authentication service</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<para>OpenStack Identity Service
(Keystone)</para></td>
<td><para>The Object Storage account name is the same
as the tenant ID.</para><para>For information
about the Identity Service, see <xref
linkend="get_auth_token_keystone"
/>.</para>
</td>
</tr>
<tr>
<td>
<para>Tempauth middleware</para></td>
<td><para>Object Storage includes this middleware.
User and account management is performed in
the Object Storage system itself.</para>
<para>For information about Tempauth, see <xref
linkend="get_auth_token_tempauth"
/>.</para>
</td>
</tr>
<tr>
<td>
<para>swauth (in GitHub) or other custom
middleware</para></td>
<td><para>This custom middleware is modeled on
Tempauth, so usage is typically similar to
Tempauth.</para><para>Specifically, you use
the <literal>X-Auth-Token</literal> header to
pass an authentication token to an API
request.</para>
</td>
</tr>
</tbody>
</informaltable>
<para>Authentication tokens expire after a time period that the
authentication service defines. When a token expires, use of
the token causes requests to fail with a
<errorcode>401</errorcode>
<errortext>Unauthorized</errortext> response. To continue, you
must obtain a new token.</para>
</section>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="bulk_operations">
<title>Bulk operations</title>
<section xml:id="bulk-delete">
<title>Bulk Delete</title>
<para> With bulk delete you can delete up to 10,000
(configurable) objects or containers in one request. The
objects to be deleted are listed in the body of a DELETE
operation. The ?bulk-delete query parameter is used to
indicate that you are performing a bulk delete operation
instead of a normal delete. Bulk Delete Request Body
------------------------------- To indicate that you are
performing a bulk delete operation, add the ?bulk-delete
query parameter to the path. The path should be the
account (e.g., /v1/12345678912345) containing the objects
and containers. The Content-Type request header must be
set to text/plain. The request body comprises a list of
object or container names, seperated by a newline
character. In addition: - The names must be UFT-8 encoded
and then URL-encoded. - To indicate an object, specify the
container and object name as follows:
{container-name}/{object-name} - To indicate a container,
specify the container name as follows: {container-name} -
A container must be empty. If it contains objects, the
container will not be deleted. - At most 10,000
(configurable) items can be in the list Bulk Delete
Response -------------------------- When the request is
processed by the system, you are in effect performing
multiple sub-operations. Even if all sub-operations fail,
the operation will return a 200 status. You must examine
the response body to determine which members failed to
result in an object deletion. You can use the Accept
request header to indicate the format of the response body
as follows: - text/plain. Plain text. This is the default
if the Accept header is not specified. - application/json.
Format as JSON - application/xml or text/xml. Format as
XML. See (xref to Response Body for Bulk Operations) for
more information. Response Body for Bulk Operations
=========================== Some bulk operations such as
Bulk Delete and Archive Auto Extraction perform multiple
sub-operations. While some of the operations may succeed,
other may fail. To indicate which sub-operations have
succeeded and failed, the bulk operation returns a
response body containing more details.</para>
<para>You can use the Accept request header to indicate the
format of the response body. The response body contains
the following information:</para>
<para>- The number of files actually deleted or created
(depending on context) - The number of not found objects
(for Bulk Delete only) - Errors. This is a list of object
name and associated error status for the objects that
failed to create or delete. The format depends on the
Accept header. </para>
<para>The following example shows a text/plain response body
where there are no failures. This example is from the
Archive Auto Extraction operation. </para>
<screen><computeroutput>Number Files Created: 10
Errors:</computeroutput></screen>
<para>The following example shows a text/plain response where
there are some failures. In this example, the Object
Storage system has been configured to reject certain
character strings so the 400 Bad Request error occurs for
objects using the restricted strings. </para>
<screen><computeroutput>Number Files Created: 8
Errors:
/v1/12345678912345/mycontainer/home/xx%3Cyy, 400 Bad Request
/v1/12345678912345/mycontainer/../image.gif, 400 Bad Request</computeroutput></screen>
<para>This is the same failure response in application/json
format. This example output has been reformatted with
whitespace to make it clearer -- the actual response has
no such whitespace. </para>
<programlisting language="json">{
"Number Files Created": 1,
"Errors": [
["/v1/12345678912345/mycontainer/home/xx%3Cyy", "400 Bad Request"],
["/v1/12345678912345/mycontainer/../image.gif", "400 Bad Request"]
]
}</programlisting>
<para>The following example shows an example response to a
Bulk Delete request in application/xml format. In this
example, the mycontainer container is not empty so cannot
be deleted.</para>
<programlisting language="xml"><xi:include parse="text" href="samples/bulk-delete-response.xml"/></programlisting>
</section>
</section>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="large-lists">
<title>Page through large lists of containers or objects</title>
<para>If you have a large number of containers or objects, you can
use the <parameter>marker</parameter>,
<parameter>limit</parameter>, and
<parameter>end_marker</parameter> parameters to control
how many items are returned in a list and where the list
starts or ends.</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold"><parameter>marker</parameter>
parameter</emphasis>. When you request a list of
containers or objects, Object Storage returns a
maximum of 10,000 names for each request. To get
subsequent names, you must make another request with
the <parameter>marker</parameter> parameter. Set the
<literal>marker</literal> parameter to the name of
the last item returned in the previous list. You must
URL-encode the <parameter>marker</parameter> value
before you send the HTTP request. Object Storage
returns a maximum of 10,000 names again.</para>
</listitem>
<listitem>
<para><emphasis role="bold"><parameter>limit</parameter>
parameter</emphasis>. To return fewer than 10,000
names, use the <parameter>limit</parameter> parameter.
If the number of names returned equals the specified
<parameter>limit</parameter> (or 10,000 if you
omit the <parameter>limit</parameter> parameter), you
can assume there are more names to list. If the number
of names in the list is exactly divisible by the
<parameter>limit</parameter> value, the last
request has no content.</para>
</listitem>
<listitem>
<para><emphasis role="bold"
><parameter>end_marker</parameter>
parameter</emphasis>. Limits the result set to
names that are less than the
<parameter>end_marker</parameter> parameter value.
You must URL-encode the
<parameter>end_marker</parameter> value before you
send the HTTP request.</para>
</listitem>
</itemizedlist>
<para>For examples of how to page through large lists, see <xref
linkend="examples"/>.</para>
</section>

View File

@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="object_storage_api_overview">
<title>Object Storage API overview</title>
<para>OpenStack Object Storage is an object-based storage system
that stores content and metadata as objects. You create,
modify, and get objects and metadata by using the Object
Storage API, which is implemented as a set of Representational
State Transfer (REST) web services.</para>
<para>You use the HTTPS (SSL) protocol to interact with Object
Storage, and you use standard HTTP calls to perform API
operations. You can also use language-specific APIs, which use
the ReSTful API, that make it easier for you to integrate into
your applications.</para>
<para>To assert your right to access and change data in an
account, you identify yourself to Object Storage by using an
authentication token. To get a token, you present your
credentials to an authentication service. The authentication
service returns a token and the URL for the account. Depending
on which authentication service that you use, the URL for the
account appears in:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">OpenStack Identity
Service</emphasis>. The URL is defined in the
service catalog.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Tempauth</emphasis>. The URL
is provided in the <literal>X-Storage-Url</literal>
response header.</para>
</listitem>
</itemizedlist>
<para>In both cases, the URL is the full URL and includes the
account resource. For information about authentication, see
<xref linkend="authentication"/>.</para>
<para>The Object Storage API supports the standard, non-serialized
response format, which is the default, and both JSON and XML
serialized response formats. See <xref
linkend="serialized-response-formats"/>.</para>
<para>The Object Storage system organizes data in a hierarchy, as
follows:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Account</emphasis>. Represents
the top-level of the hierarchy.</para>
<para>Your service provider creates your account and you
own all resources in that account. The account defines
a namespace for containers. A container might have the
same name in two different accounts.</para>
<para>In the OpenStack environment,
<firstterm>account</firstterm> is synonymous with
a project or tenant.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Container</emphasis>. Defines
a namespace for objects. An object with the same name
in two different containers represents two different
objects. You can create any number of containers
within an account.</para>
<para>In addition to containing objects, you can also use
the container to control access to objects by using an
Access Control List (ACL). You cannot store an ACL
with individual objects.</para>
<para>In addition, you configure and control many other
features, such as object versioning, at the container
level. See <xref linkend="set-object-versions"
/>.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Object</emphasis>. Stores data
content, such as documents, images, and so on. You can
also store custom metadata with an object.</para>
<para>With the Object Storage API, you can:</para>
<itemizedlist>
<listitem>
<para>Store an unlimited number of objects. Each
object can be as large as 5 GBs.</para>
</listitem>
<listitem>
<para>Upload and store objects of any siz with
large object creation. See <xref
linkend="large-object-creation"/>.</para>
</listitem>
<listitem>
<para>Use cross-origin resource sharing to manage
object security. See <xref
linkend="cors-headers"/>.</para>
</listitem>
<listitem>
<para>Compress files. See <xref
linkend="file-compression"/>.</para>
</listitem>
<listitem>
<para>Override browser behavior for an object. See
<xref linkend="content-disposition"
/>.</para>
</listitem>
<listitem>
<para>Schedule objects for deletion. See <xref
linkend="expire-objects"/>.</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>The account, container, and object hierarchy affects the way
you interact with the Object Storage API.</para>
<para>Specifically, the resource path reflects this structure and
has this format:</para>
<programlisting>/v1/{account}/{container}/{object}</programlisting>
<para>For example, for the <literal>flowers/rose.jpg</literal>
object in the <literal>images</literal> container in the
<literal>12345678912345</literal> account, the resource
path is:</para>
<programlisting>/v1/12345678912345/images/flowers/rose.jpg</programlisting>
<para>Notice that the object name contains the
<literal>/</literal> character. This slash does not
indicate that Object Storage has a sub-hierarchy called
<literal>flowers</literal> because containers do not store
objects in actual sub-folders. However, the inclusion of
<literal>/</literal> or a similar convention inside object
names enables you to create pseudo-hierarchical folders and
directories. See <xref
linkend="pseudo-hierarchical-folders-directories"
/>.</para>
<para>For example, if the endpoint for Object Storage is
<literal>objects.mycloud.com</literal>, the returned URL
is
<literal>https://objects.mycloud.com/v1/12345678912345</literal>.</para>
<para>To access a container, append the container name to the
resource path.</para>
<para>To access an object, append the container and the object
name to the path.</para>
<para>If you have a large number of containers or objects, you can
user query parameters to page through large lists of
containers or objects. Use the <parameter>marker</parameter>,
<parameter>limit</parameter>, and
<parameter>end_marker</parameter> query parameters to
control how many items are returned in a list and where the
list starts or ends. See <xref linkend="large-lists"/>.</para>
<para>Object Storage HTTP requests have the following default
constraints:</para>
<informaltable rules="all">
<thead>
<tr>
<th>Item</th>
<th>Maximum value</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Number of HTTP headers</td>
<td>90</td>
<td/>
</tr>
<tr>
<td>Length of HTTP headers</td>
<td>4096 bytes</td>
<td/>
</tr>
<tr>
<td>Length per HTTP request line</td>
<td>8192 bytes</td>
<td/>
</tr>
<tr>
<td>Length of HTTP request</td>
<td>5 GBs</td>
<td/>
</tr>
<tr>
<td>Length of container names</td>
<td>256 bytes</td>
<td>Cannot contain the <literal>/</literal>
character.</td>
</tr>
<tr>
<td>Length of object names</td>
<td>1024 bytes</td>
<td>By default, there are no character
restrictions.</td>
</tr>
</tbody>
</informaltable>
<para>You must UTF-8-encode and then URL-encode container and
object names before you call the API binding. If you use an
API binding that performs the URL-encoding for you, do not
URL-encode the names before you call the API binding.
Otherwise, you double-encode these names. Check the length
restrictions against the URL-encoded string.</para>
<para>These sections describe the operations that you can perform
with the Object Storage API:</para>
<itemizedlist>
<listitem>
<para><xref linkend="storage_account_services"/>. Use to
perform account-level tasks.</para>
<para>Lists containers for a specified account. Creates,
updates, and deletes account metadata. Shows account
metadata.</para>
</listitem>
<listitem>
<para><xref linkend="storage_container_services"/>. Use to
perform container-level tasks.</para>
<para>Lists objects in a specified container. Creates,
shows details for, and deletes containers. Creates,
updates, shows, and deletes container metadata.</para>
</listitem>
<listitem>
<para><xref linkend="storage_object_services"/>. Use to
perform object-level tasks.</para>
<para>Creates, replaces, shows details for, and deletes
objects. Copies objects with another object with a new
or different name. Updates object metadata.</para>
</listitem>
</itemizedlist>
</section>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="pseudo-hierarchical-folders-directories">
<title>Pseudo-hierarchical folders and directories</title>
<!-- reworked this section / as path and its elements / are not supported - dsh - 02-16-12 -->
<para>Although you cannot nest directories in OpenStack Object
Storage, you can simulate a hierarchical structure within a
single container by adding forward slash characters
(<literal>/</literal>) in the object name. To navigate the
pseudo-directory structure, you can use the
<code>delimiter</code> query parameter. this examples show
you how to use pseudo-hierarchical folders and
directories.</para>
<note>
<para>In this example, the objects reside in a container
called <code>backups</code>. Within that container, the
objects are organized in a pseudo-directory called
<code>photos</code>. Keep in mind that the container
name is not displayed in the example, but that it is a
part of the object URLs. For instance, the URL of the
picture <code>me.jpg</code> is
<uri>https://storage.swiftdrive.com/v1/CF_xer7_343/backups/photos/me.jpg</uri>.</para>
</note>
<example>
<title>List pseudo-hierarchical folders request: HTTP</title>
<para>To display a list of all the objects in the storage
container, use &GET; without a <code>delimiter</code> or
<code>prefix</code>.</para>
<literallayout class="monospaced">GET /v1/AccountString/backups</literallayout>
<para>The system returns status code 2xx (between 200 and 299,
inclusive) and the requested list of the objects.</para>
<literallayout class="monospaced">photos/animals/cats/persian.jpg
photos/animals/cats/siamese.jpg
photos/animals/dogs/corgi.jpg
photos/animals/dogs/poodle.jpg
photos/animals/dogs/terrier.jpg
photos/me.jpg
photos/plants/fern.jpg
photos/plants/rose.jpg</literallayout>
<para>
<!-- The JIRA ticket / doc-97 subsumed / to this location - dsh - 02-03-12 -->Use
the delimiter parameter to limit the displayed results.
You can use any character as a delimiter. However, to use
<code>delimiter</code> with pseudo-directories, use
the parameter slash (<literal>/</literal>).</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?delimiter=/</literallayout>
<para>The system returns status code 2xx (between 200 and 299,
inclusive) and the requested matching objects. Because you
use the slash, only the pseudo-directory
<code>photos/</code> displays. Keep in mind that the
returned values from a slash <code>delimiter</code> query
are not real objects. They have a content-type of
<literal>application/directory</literal> and are in
the <literal>subdir</literal> section of json and xml
results.</para>
<literallayout class="monospaced">photos/</literallayout>
<para>Use the <code>prefix</code> and <code>delimiter</code>
parameters to view the objects inside a pseudo-directory,
including further nested pseudo-directories.</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?prefix=photos/&#38;delimiter=/</literallayout>
<para>The system returns status code 2xx (between 200 and 299,
inclusive) and the objects and pseudo-directories within
the top level pseudo-directory.</para>
<literallayout class="monospaced">photos/animals/
photos/me.jpg
photos/plants/</literallayout>
<para>You can create an unlimited number of nested
pseudo-directories. To navigate through them, use a longer
<code>prefix</code> parameter coupled with the
<code>delimiter</code> parameter. In this sample
output, there is a pseudo-directory called
<code>dogs</code> within the pseudo-directory
<code>animals</code>. To navigate directly to the
files contained within <code>dogs</code>, enter the
following command:</para>
<literallayout class="monospaced">GET /v1/AccountString/backups?prefix=photos/animals/dogs/&#38;delimiter=/ </literallayout>
<para>The system returns status code <returnvalue>2<replaceable>nn</replaceable></returnvalue> (between 200 and 299,
inclusive) and the objects and pseudo-directories within
the nested pseudo-directory.</para>
<literallayout class="monospaced">photos/animals/dogs/corgi.jpg
photos/animals/dogs/poodle.jpg
photos/animals/dogs/terrier.jpg</literallayout>
</example>
</section>

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section [
<!-- Useful for describing APIs -->
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="serialized-response-formats">
<title>Serialized response formats</title>
<para>The Object Storage API supports the standard, non-serialized
response format, which is the default, and both JSON and XML
data serialization response formats.</para>
<note>
<para>To run the cURL command examples, you must export <link
xlink:href="run_curl_commands">environment
variables</link>.</para>
</note>
<para>To define the response format, use one of these
methods:</para>
<variablelist wordsize="10">
<varlistentry>
<term><emphasis role="bold"
><code>format=<replaceable>format</replaceable></code>
query parameter</emphasis></term>
<listitem>
<para>Append this parameter to the URL for a &GET;
request, where <replaceable>format</replaceable>
is <code>json</code> or <code>xml</code>. </para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="bold"><literal>Accept</literal>
request header</emphasis></term>
<listitem>
<para>Include this header in the &GET; request. The
valid header values are:</para>
<itemizedlist>
<listitem>
<para><code>text/plain</code>. Plain text
response format. The default.</para>
</listitem>
<listitem>
<para><code>application/json</code>. JSON data
serialization response format.</para>
</listitem>
<listitem>
<para><code>application/xml</code>. XML data
serialization response format.</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
<example>
<title>JSON example with format query parameter</title>
<para>For example, this request uses the
<parameter>format</parameter> query parameter to ask
for a JSON response:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL?format=json -X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 96
X-Account-Object-Count: 1
X-Timestamp: 1389453423.35964
X-Account-Meta-Subject: Literature
X-Account-Bytes-Used: 14
X-Account-Container-Count: 2
Content-Type: application/json; charset=utf-8
Accept-Ranges: bytes
X-Trans-Id: tx274a77a8975c4a66aeb24-0052d95365
Date: Fri, 17 Jan 2014 15:59:33 GMT</computeroutput></screen>
<para>Object Storage lists container names with additional
information in JSON format:</para>
<programlisting language="json">[
{
"count":0,
"bytes":0,
"name":"janeausten"
},
{
"count":1,
"bytes":14,
"name":"marktwain"
}
]</programlisting>
</example>
<example>
<title>XML example with Accept header</title>
<para>This request uses the <literal>Accept</literal> request
header to ask for an XML response:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL -X GET -H "X-Auth-Token: $token" -H "Accept: application/xml; charset=utf-8"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 263
X-Account-Object-Count: 3
X-Account-Meta-Book: MobyDick
X-Timestamp: 1389453423.35964
X-Account-Bytes-Used: 47
X-Account-Container-Count: 2
Content-Type: application/xml; charset=utf-8
Accept-Ranges: bytes
X-Trans-Id: txf0b4c9727c3e491694019-0052e03420
Date: Wed, 22 Jan 2014 21:12:00 GMT</computeroutput></screen>
<para>Object Storage lists container names with additional
information in XML format:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;account name="AUTH_73f0aa26640f4971864919d0eb0f0880">
&lt;container>
&lt;name>janeausten&lt;/name>
&lt;count>2&lt;/count>
&lt;bytes>33&lt;/bytes>
&lt;/container>
&lt;container>
&lt;name>marktwain&lt;/name>
&lt;count>1&lt;/count>
&lt;bytes>14&lt;/bytes>
&lt;/container>
&lt;/account></programlisting>
<para>The remainder of the examples in this guide use
standard, non-serialized responses. However, all &GET;
requests that perform list operations accept the
<parameter>format</parameter> query parameter or
<literal>Accept</literal> request header.</para>
</example>
</section>

View File

@@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE section [
<!-- Some useful entities borrowed from HTML -->
<!ENTITY ndash "&#x2013;">
<!ENTITY mdash "&#x2014;">
<!ENTITY hellip "&#x2026;">
<!-- Useful for describing APIs -->
<!ENTITY COPY '<command xmlns="http://docbook.org/ns/docbook">COPY</command>'>
<!ENTITY GET '<command xmlns="http://docbook.org/ns/docbook">GET</command>'>
<!ENTITY HEAD '<command xmlns="http://docbook.org/ns/docbook">HEAD</command>'>
<!ENTITY PUT '<command xmlns="http://docbook.org/ns/docbook">PUT</command>'>
<!ENTITY POST '<command xmlns="http://docbook.org/ns/docbook">POST</command>'>
<!ENTITY DELETE '<command xmlns="http://docbook.org/ns/docbook">DELETE</command>'>
]>
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
xml:id="set-object-versions">
<title>Object versioning</title>
<para>You can store multiple versions of your content so that you
can recover from unintended overwrites. Object versioning is
an easy way to implement version control, which you can use
with any type of content.</para>
<note>
<para>You cannot version a large-object manifest file, but the
large-object manifest file can point to versioned
segments.</para>
</note>
<para>It is strongly recommended that you put non-current objects
in a different container than the container where current
object versions reside. </para>
<procedure>
<title>To enable and use object versioning</title>
<step>
<para>To enable object versioning, ask your cloud provider
to set the <option>allow_versions</option> option to
<literal>TRUE</literal> in the container
configuration file. </para>
</step>
<step>
<para>Create an <literal>archive</literal> container to
store older versions of objects.</para>
<para>Create the <literal>archive</literal>
container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/archive -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx46f8c29050834d88b8d7e-0052e1859d
Date: Thu, 23 Jan 2014 21:11:57 GMT</computeroutput></screen>
</step>
<step>
<para>Create a <literal>current</literal> container to
store current versions of objects.</para>
<para>Include the <literal>X-Versions-Location</literal>
header. This header defines the container that holds
the non-current versions of your objects. You must
UTF-8-encode and then URL-encode the container name
before you include it in the
<code>X-Versions-Location</code> header. This
header enables object versioning for all objects in
the <literal>current</literal> container. Changes to
objects in the <literal>current</literal> container
automatically create non-current versions in the
<literal>archive</literal> container.</para>
<para>Create the <literal>current</literal>
container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: archive"</userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txb91810fb717347d09eec8-0052e18997
Date: Thu, 23 Jan 2014 21:28:55 GMT</computeroutput></screen>
</step>
<step>
<para>Create the first version of an object in the
<literal>current</literal> container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/current/my_object --data-binary 1 -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Last-Modified: Thu, 23 Jan 2014 21:31:22 GMT
Content-Length: 0
Etag: d41d8cd98f00b204e9800998ecf8427e
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx5992d536a4bd4fec973aa-0052e18a2a
Date: Thu, 23 Jan 2014 21:31:22 GMT</computeroutput></screen>
<para>Nothing is written to the non-current version
container when you initially &PUT; an object in the
<literal>current</literal> container. However,
subsequent &PUT; requests that edit an object trigger
the creation of a version of that object in the
<literal>archive</literal> container. </para>
<para>These non-current versions are named as
follows:</para>
<programlisting>&lt;length>&lt;object_name>&lt;timestamp></programlisting>
<para> Where length is the 3-character, zero-padded
hexadecimal character length of the object,
&lt;object_name&gt; is the object name, and
&lt;timestamp&gt; is the time when the object was
initially created as a current version.</para>
</step>
<step>
<para>Create a second version of the object in the
<literal>current</literal> container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/current/my_object --data-binary 2 -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 201 Created
Last-Modified: Thu, 23 Jan 2014 21:41:32 GMT
Content-Length: 0
Etag: d41d8cd98f00b204e9800998ecf8427e
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx468287ce4fc94eada96ec-0052e18c8c
Date: Thu, 23 Jan 2014 21:41:32 GMT</computeroutput></screen>
</step>
<step>
<para>Issue a &GET; request to a versioned object to get
the current version of the object. You do not have to
do any request redirects or metadata lookups.</para>
<para>List older versions of the object in the
<literal>archive</literal> container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/archive?prefix=009my_object -X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 200 OK
Content-Length: 30
X-Container-Object-Count: 1
Accept-Ranges: bytes
X-Timestamp: 1390513280.79684
X-Container-Bytes-Used: 0
Content-Type: text/plain; charset=utf-8
X-Trans-Id: tx9a441884997542d3a5868-0052e18d8e
Date: Thu, 23 Jan 2014 21:45:50 GMT
009my_object/1390512682.92052</computeroutput></screen>
<note>
<para>A &POST; request to a versioned object updates
only the metadata for the object and does not
create a new version of the object. New versions
are created only when the content of the object
changes.</para>
</note>
</step>
<step>
<para>Issue a &DELETE; request to a versioned object to
remove the current version of the object and replace
it with the next-most current version in the
non-current container.</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/current/my_object -X DELETE -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx006d944e02494e229b8ee-0052e18edd
Date: Thu, 23 Jan 2014 21:51:25 GMT</computeroutput></screen>
<para>List objects in the <literal>archive</literal>
container to show that the archived object was moved
back to the <literal>current</literal>
container:</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/archive?prefix=009my_object -X GET -H "X-Auth-Token: $token"</userinput></screen>
<screen><computeroutput>HTTP/1.1 204 No Content
Content-Length: 0
X-Container-Object-Count: 0
Accept-Ranges: bytes
X-Timestamp: 1390513280.79684
X-Container-Bytes-Used: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx044f2a05f56f4997af737-0052e18eed
Date: Thu, 23 Jan 2014 21:51:41 GMT</computeroutput></screen>
<para>This next-most current version carries with it any
metadata last set on it. If want to completely remove
an object and you have five versions of it, you must
&DELETE; it five times.</para>
</step>
<step>
<para>To disable object versioning for the
<literal>current</literal> container, remove its
<literal>X-Versions-Location</literal> metadata
header by sending an empty key value.</para>
<screen><prompt>#</prompt> <userinput>curl -i $publicURL/current -X PUT -H "Content-Length: 0" -H "X-Auth-Token: $token" -H "X-Versions-Location: "</userinput></screen>
<screen><computeroutput>HTTP/1.1 202 Accepted
Content-Length: 76
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txe2476de217134549996d0-0052e19038
Date: Thu, 23 Jan 2014 21:57:12 GMT
&lt;html>&lt;h1>Accepted&lt;/h1>&lt;p>The request is accepted for processing.&lt;/p>&lt;/html></computeroutput></screen>
</step>
</procedure>
</section>