<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Adrian Smith&#039;s Blog &#187; openstack</title>
	<atom:link href="http://www.17od.com/tag/openstack/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.17od.com</link>
	<description></description>
	<lastBuildDate>Tue, 15 Jan 2013 21:15:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Ten Useful Openstack Swift Features</title>
		<link>http://www.17od.com/2012/12/19/ten-useful-openstack-swift-features/</link>
		<comments>http://www.17od.com/2012/12/19/ten-useful-openstack-swift-features/#comments</comments>
		<pubDate>Wed, 19 Dec 2012 20:33:07 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[openstack]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=607</guid>
		<description><![CDATA[CORS support For security reasons Javascript running in a browser is not allowed to make requests to domains other than the one from where it came from. This is referred to as the Same Origin Policy. CORS is specification allowing browsers and application servers work out an agreement whereby these types of requests are allowed. [...]]]></description>
				<content:encoded><![CDATA[<h2>CORS support</h2>
<p>For security reasons Javascript running in a browser is not allowed to make requests to domains other than the one from where it came from. This is referred to as the <a href="http://en.wikipedia.org/wiki/Same_origin_policy">Same Origin Policy<a/>. <a href="http://en.wikipedia.org/wiki/Cross-origin_resource_sharing">CORS</a> is specification allowing browsers and application servers work out an agreement whereby these types of requests are allowed.</p>
<p>Swift 1.7.5 introduced <a href="http://docs.openstack.org/developer/swift/misc.html#cors-headers">CORS support</a>. This means a Javascript application running in a browser and hosted outside of a Swift cluster can still query that cluster&#8217;s API. I expect to see lots of Swift based applications over the coming months thanks to this great new feature.</p>
<h2>The ETag</h2>
<p>Every object written to a Swift cluster has an <a href="http://en.wikipedia.org/wiki/HTTP_ETag">ETag</a> associated with it. The value of this ETag is the MD5 digest of the file&#8217;s contents. What makes this useful is that you can use it to make a conditional request for the object using the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24">If-Match</a>, <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26">If-None-Match</a> headers.</p>
<p>For example, lets say your Swift cluster contains the object &#8220;movie1.mp4&#8243;. You already have a version of the file locally but you&#8217;re not sure if it&#8217;s exactly the same. You don&#8217;t want to have to download it unnecessarily because it would take too long and/or might incur bandwidth charges. What you can do is invoke a conditional download request, i.e.</p>
<pre class="lang:sh decode:true">$ md5sum movie1.mp4
d41d8cd98f00b204e9800998ecf8427e  movie1.mp4

$ curl -i -H 'X-Auth-Token: xxx' -H 'If-None-Match: d41d8cd98f00b204e9800998ecf8427e' http://swift.17od.com/movies/movie1.mp4
HTTP/1.1 304 Not Modified
...</pre>
<p>The 304 response code tells us that our local version is the same as the remote version. If it wasn&#8217;t the same it would be downloaded.</p>
<h2>Object Versioning</h2>
<p>With object versioning, each PUT request to an object will result in the existing object being archived to a special &#8220;versions&#8221; container.</p>
<p>Versioning is controlled at the container level by setting the header &#8220;X-Versions-Location&#8221; to the name of the container where you want to archive object versions.</p>
<p>For more information see <a href="http://docs.openstack.org/developer/swift/overview_object_versioning.html">Object Versioning</a> in the developer documentation. </p>
<h2>Renaming or Moving an Object</h2>
<p>Renaming or moving objects isn&#8217;t supported in the classic sense. However the same result can be achieved by downloading the existing object and re-uploading it to the new container and/or with a new name. Of course if the object is large this can be a time consuming operation. Luckily Swift supports server side copies. What this means is this object is copied from it&#8217;s source to destination all within the confines of the Swift cluster.</p>
<p>Either PUT or COPY can be used to perform a server side copy. Neither has an advantage over the other.</p>
<p>For example, given the container and object &#8220;photos/sunset.jpg&#8221;, here&#8217;s how to move it to &#8220;holiday-pics/sunset_glow.jpg&#8221;.</p>
<pre class="lang:sh decode:true">
$ curl -X PUT -H 'X-Auth-Token: xxx' -H 'X-Copy-From: /photos/sunset.jpg' http://swift.17od.com/holiday-pics/sunset_glow.jpg
</pre>
<p>See <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/copy-object.html">Copy Object</a> for more details.</p>
<h2>Expiring Objects</h2>
<p>Objects can be given an expiry time. When that time is reached Swift will automatically delete the object. Object&#8217;s are given an expiry time by setting either the <b>X-Delete-At</b> or <b>X-Delete-After</b> headers.</p>
<p>The value given to X-Delete-At is a <a href="http://en.wikipedia.org/wiki/Unix_time">Unix Epoch timestamp</a>. There are many ways of converting a time to an epoch integer. For example on UNIX you can to,</p>
<pre class="lang:sh decode:true">
$ date +%s
1355945201
</pre>
<p>The <a href="http://www.epochconverter.com/">epoch converter</a> website allows you to convert any time to an epoch and vice-versa.</p>
<p>X-Delete-After is a convenience header allowing you to give the number of seconds from now when you want the object deleted. Swift will use this value to calculate an epoch time this number of seconds into the future and set an X-Delete-At header on the object.</p>
<pre class="lang:sh decode:true">
# delete the object on Sat, 19 Dec 2015 19:18:52 GMT
$ curl -X POST -H 'X-Auth-Token: xxx' -H 'X-Delete-On: 1450552732' http://swift.17od.com/holiday-pics/sunset_glow.jpg
</pre>
<pre class="lang:sh decode:true">
# delete the object 24 hours from now, 24*60*60
$ curl -X POST -H 'X-Auth-Token: xxx' -H 'X-Delete-After: 86400' http://swift.17od.com/holiday-pics/sunset_glow.jpg
</pre>
<p>See <a href="http://docs.openstack.org/developer/swift/overview_expiring_objects.html">Expiring Object Support</a> in the developer documentation for more information.</p>
<h2>Segmented Objects</h2>
<p>Swift has an object size limit of 5Gb. Larger objects must be split up on the client side and the segments uploaded individually. A manifest object is then used to create a logical object built up from the segments.</p>
<p>It&#8217;s not just large objects that can be segmented. Any sized object can be broken up. Having said that I can&#8217;t think of a good reason why you&#8217;d want to do this?</p>
<p>On UNIX the <code>split</code> command can be used to split an object up into segments. There&#8217;s two ways of using split, either give it the number of segments or the size of the segments you want to split the object up into.</p>
<pre class="lang:sh decode:true">
# split an object up into 5 segments
$ split -n 5 at_the_beach.mp4 at_the_beach.mp4-

# split an object up where each segment is at most 5GB
$ split -b 5G at_the_beach.mp4 at_the_beach.mp4-
</pre>
<p>In each case the result will be a number of files called <code>at_the_beach.mp4-xx</code> where xx is an alphabetically ordered sequence of characters, e.g. aa, ab, ac and so on. This ordering is important because when Swift rebuilds the object it sorts the segments by name before concatenating them. Each of these segments should be uploaded into the same container.</p>
<p>The manifest object is an object with no content. Instead it has the header <code>X-Object-Manifest</code>. The value of this header is the container name and common prefix of the segments making up the object. Assuming the segments were uploaded into a container called &#8216;holiday-pics&#8217; and the prefix was &#8216;at_the_beach.mp4-&#8217; the header value would be &#8216;holiday-pics/at_the_beach.mp4-&#8217;.</p>
<pre class="lang:sh decode:true">
$ curl -X PUT -H 'X-Auth-Token: xxx' -H 'X-Object-Manifest: holiday-pics/at_the_beach.mp4-' http://swift.17od.com/holiday-pics/at_the_beach.mp4
</pre>
<p>A GET for the manifest object will return the reassembled source object. Swift will stream each segment in sequence so from the client side it will appear as one continuous object.</p>
<p>See <a href="http://docs.openstack.org/developer/swift/overview_large_objects.html">Large Object Support</a> in the developer documentation for more information.</p>
<h2>Metadata</h2>
<p>Accounts, Containers and Objects can all have custom metadata headers associated with them. These headers are simple name/value pairs. Custom headers are distinguished from system headers with a prefix, X-Account-Meta, X-Container-Meta or X-Object-Meta.</p>
<p>Headers can be set on an existing account, container or object using the POST method. Alternatively the headers can be set when the container or object is being created using PUT.</p>
<pre class="lang:sh decode:true">
# Set a header on an existing object
$ curl -X POST -H 'X-Auth-Token: xxx' -H 'X-Object-Meta-Location: Dublin' http://swift.17od.com/holiday-pics/at_the_beach.mp4

# Set a header on a container when creating it
$ curl -X PUT -H 'X-Auth-Token: xxx' -H 'X-Container-Meta-Year: 2012' http://swift.17od.com/holiday-pics/
</pre>
<p>Metadata can be retrieved using the HEAD method.</p>
<pre class="lang:sh decode:true">
$ curl -i -X HEAD -H 'X-Auth-Token: xxx' http://swift.17od.com/holiday-pics/
HTTP/1.1 204 No Content
Content-Length: 0
X-Container-Object-Count: 3
Accept-Ranges: bytes
X-Timestamp: 1355861803.81992
X-Container-Bytes-Used: 2
X-Container-Meta-Year: 2012
Content-Type: text/plain; charset=utf-8
Date: Wed, 19 Dec 2012 20:07:03 GMT
</pre>
<h2>Permissions</h2>
<p>Permissions in Swift are controlled at the container level. Only users classified as administrators can create containers. By default regular users can&#8217;t create or access containers. </p>
<p>Users can be given read or write permissions for all the objects in a container using the X-Container-Read and X-Container-Write headers.</p>
<pre class="lang:sh decode:true">
# Give bob and alice read access to the holiday-pics container
$ curl -X POST -H 'X-Auth-Token: xxx' -H 'X-Container-Read: bob, alice' http://swift.17od.com/holiday-pics/

# Give bob write access to the holiday-pics container
$ curl -X POST -H 'X-Auth-Token: xxx' -H 'X-Container-Write: bob' http://swift.17od.com/holiday-pics/
</pre>
<p>For more information see the <a href="http://docs.openstack.org/developer/swift/misc.html#acls">ACLs</a> section of the developer docs.</p>
<h2>Pseudo-Hierarchical Directories</h2>
<p>While containers can be compared with regular filesystem directories, it&#8217;s not possible to nest them. A container with thousands of objects can become extremely difficult to navigate and manage. With that in mind Swift supports a feature called pseudo-hierarchical directories. These are directory structures derived from the names of objects themselves. For example, lets say we have a container with the following six objects,</p>
<p>photos/2010/001.jpg<br />
photos/2011/001.jpg<br />
photos/2011/002.jpg<br />
photos/2012/001.jpg<br />
photos/2012/002.jpg<br />
photos/2012/003.jpg</p>
<p>By using a delimiter character Swift can be asked to list the objects as if they were in a directory structure similar to,</p>
<pre class="show-plain-default:true nums:false lang:default decode:true " >
/photos/
|-- 2010
|   `-- 001.jpg
|-- 2011
|   |-- 001.jpg
|   `-- 002.jpg
`-- 2012
    |-- 001.jpg
    |-- 002.jpg
    `-- 003.jpg
</pre>
<p>For example,</p>
<pre class="lang:sh decode:true">
$ curl -X GET -H 'X-Auth-Token: xxx' http://swift.17od.com/adrian/?delimiter=/
photos/

$ curl -X GET -H 'X-Auth-Token: xxx' "http://swift.17od.com/adrian/?delimiter=/&#038;prefix=photos/"
photos/2010/
photos/2011/
photos/2012/

$ curl -X GET -H 'X-Auth-Token: xxx' "http://swift.17od.com/adrian/?delimiter=/&#038;prefix=photos/2012/"
photos/2012/001.jpg
photos/2012/002.jpg
photos/2012/003.jpg
</pre>
<p>For more information see <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/pseudo-hierarchical-folders-directories.html">Pseudo-Hierarchical Folders/Directories</a> in the Developer Guide.</p>
<h2>Swift All in One</h2>
<p>Like anything, the best way to learn more about Swift it to play around with it. Luckily that&#8217;s relatively easy thanks to <a href="http://docs.openstack.org/developer/swift/development_saio.html">Swift All in One</a>, a set of instructions describing how to setup a fully functional Swift cluster on a single machine (ideally a VM).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2012/12/19/ten-useful-openstack-swift-features/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
