Installing and using Swiftly with Rackspace Cloud Files

So you want a commandline tool for managing cloud files containers? Enter, swiftly. Now you’ve seen examples before with curl, fog and pyrax, but here’s a special one which is a commandline application.

# Upgrade pip just for hoots
pip install --upgrade pip

# Install swiftly
pip install swiftly

Now swiftly is installed, how about configuring it in your home directory

# put a .swiftly.conf in your home directory, if your root i.e. /root/.swiftly.
vi ~/.swiftly.conf

This is what the configuration should look like

[swiftly]                                                                       
auth_user = mycloudusername                                                        
auth_key = mycloudapikey                                  
auth_url = https://identity.api.rackspacecloud.com/v2.0                         
region = lon
bash-4.2 Tue Feb 16 15:04:34 pirax-test ~# swiftly get

current
export
exports
gallery
images
lb_153727_TESTING_Nov_2015
lb_153727_TESTING_Oct_2015
magento-stack-single-magento_server-gxlxbm7b6be2
meh
meh2
rackspace_orchestration_templates_store
scripts
testing
testing999
versions

This gives us the output of all of the cloud containers as shown above. Pretty cool. But what about placing files in a container?

swiftly put -i ~/myfile.txt CONTAINER/path/to/file/somefilenamethatsdifferent.txt

So If I wanted to upload to meh2 I would do an

swiftly put -i ~/mylocalfile.txt meh2/some/container/path/somefileiuploaded.txt

The destination file can be called mylocalfile.txt if you want but I want to illustrate the target name can be different to the local source name.

Stopping a process from crapping out without PIDcrap

So, this one comes up a lot too. So you wanna run a process, and you don’t want it to crap out, you don’t want PIDCrap or any other lunatic solution that simply doesn’t work 100%. Well, welcome to until.

I’ve been executing a ruby script that does some stuff with fog.

ruby my-fog-cloud-files-container-deleter-thingy.rb

but, it keeps crapping out with lots of errors

I figured crapout no more and nabbed this handy snippet, credit to good ole stackoverflow

until ruby my-fog-cloud-files-container-deleter-thingy.rb; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

Now when it craps out, it continues where it left off.. nice, simple, elegant.

I don’t know what kind of error handling swiftly and pyrax has available in built, but this is a nice way to do it. Theoretically this oneliner might be of use for turbolift as well as any other batch like job which might end prematurely before the code deploy finishes. I wish cloud init had something like this

Removing and purging all Rackspace Cloud Files from all containers

So, this one comes up a lot at work, and thanks to knowitnot.com I came accross this example using ruby and fog, its simple, dont runnaway!

Regex lets you define the exact things you want to delete, but be careful. I’m using .* , I’ve removed it and replaced it with some_regex, to make sure people don’t accidentally nuke their cloud files 😀

Install first

yum install rubygem-fog.noarch
#!/usr/bin/env ruby
# Author: Jason Barnett 

require 'fog'

def delete_file(container, file_num, max_tries)
  max_retries ||= max_tries
  try = 0
  puts "(#{file_num} of #{container.files.count}) Removing #{container.files[file_num].key}"
  begin
    container.files[file_num].destroy
  rescue Excon::Errors::NotFound, Excon::Errors::Timeout, Fog::Storage::Rackspace::NotFound => e
    if try == max_retries
      $stderr.puts e.message
    else
      try += 1
      puts "Retry \##{try}"
      retry
    end
  end
end

def equal_div(first, last, num_of_groups)
  total      = last - first
  group_size = total / num_of_groups + 1

  top    = first
  bottom = top + group_size
  blocks = 1.upto(num_of_groups).inject([]) do |result, x|
    bottom = last if bottom > last
    result << [ top, bottom ]

    top    += group_size + 1
    bottom =  top + group_size

    result
  end

  blocks
end

service = Fog::Storage.new({
    :provider             => 'Rackspace',               # Rackspace Fog provider
    :rackspace_username   => 'your_rackspace_username', # Your Rackspace Username
    :rackspace_api_key    => 'your_api_key',            # Your Rackspace API key
    :rackspace_region     => :ord,                      # Defaults to :dfw
    :connection_options   => {},                        # Optional
    :rackspace_servicenet => false                      # Optional, only use if you're the Rackspace Region Data Center
})

containers = service.directories.select do |s|
  s.key =~ /^some_regex/  # Only delete containers that match the regexp
end

TOT_THREADS = 4
threads     = []

containers.each do |container|
  puts
  puts "-----------------------------------------"
  puts "-- Removing _ALL_ objects from #{container.key}"
  puts "-----------------------------------------"
  puts

  #puts "container.files.count: #{container.files.count}"

  ## separates the number of files into equal groups to distribute to each thread
  mygroups = equal_div(0, container.files.count - 1, TOT_THREADS)

  0.upto(TOT_THREADS - 1) do |thread|
    threads << Thread.new([ container, mygroups[thread] ]) { |tObject|
      tObject[1][0].upto(tObject[1][1]) do |x|
        delete_file(tObject[0], x, 5)
      end
    }

  end
  threads.each { |aThread|  aThread.join }
  puts "Deleting #{container.key}"
  container.destroy
end

The script works, supporting multiple threads:

(8178 of 10000) Removing conv/2015/04/15/08/bdce78e4cab875e9e17eeeae051b1128.log.gz
(3183 of 10000) Removing conv/2015/03/17/18/0ea71bf7a834fc02b01c7f65c4eb23b0.log.gz
(5685 of 10000) Removing conv/2015/04/01/08/e4d6a7a2ee83d0be116cca6b1a92ad2a.log.gz
(682 of 10000) Removing conv/2015/02/26/07/163f33cf4e33c64139ab3bd7092a9478.log.gz
(8179 of 10000) Removing conv/2015/04/15/09/09ef6c4ecaa9341e76648b6e175db888.log.gz
(5686 of 10000) Removing conv/2015/04/01/09/23fa1dce145c8343efd8e0227fd41e35.log.gz
(3184 of 10000) Removing conv/2015/03/17/18/66cb5ac707c40777a1a78b1486e1c4f3.log.gz
(683 of 10000) Removing conv/2015/02/26/07/35f28368ed45b2fb7c7076c3b78eb008.log.gz
(5687 of 10000) Removing conv/2015/04/01/09/42882b705c2d7cfe5c726ddec3e457fc.log.gz
(3185 of 10000) Removing conv/2015/03/17/18/73dbb421db0093279138b6f69f246c06.log.gz
(8180 of 10000) Removing conv/2015/04/15/09/1a01e6b1779b76b5221b1c8c08398b00.log.gz
(684 of 10000) Removing conv/2015/02/26/07/44a59e91f6632383f18ff253e4404dba.log.gz
(3186 of 10000) Removing conv/2015/03/17/18/8f8ba5791ab0c1979b168517b229ef74.log.gz
(5688 of 10000) Removing conv/2015/04/01/09/8ff43c8a5de8a41ee9890686150c8c19.log.gz
(8181 of 10000) Removing conv/2015/04/15/09/28035bc7882fe36bb33da670e6c71ac0.log.gz
(685 of 10000) Removing conv/2015/02/26/07/7947d1b3f712d175281d33a6073531d9.log.gz
(8182 of 10000) Removing conv/2015/04/15/09/34a597377f63709a75c9fd6e8a68e073.log.gz
(3187 of 10000) Removing conv/2015/03/17/18/a92a58f166cc9bd1ff54a5f996bb776b.log.gz
(5689 of 10000) Removing conv/2015/04/01/09/9a728570208bcac32fd11f1581a57fbb.log.gz

List Cloud Networks using Rackspace API

In the previous chapter we learnt how to add networks using the API. It’s really simple, its basically a network and label placeholder. But what about viewing the networks we have after we’ve made some? This is pretty simple to confirm.

I have simplified the code a bit to make it easier to read.

#!/bin/sh

USERNAME='mycloudusername'
APIKEY='mycloudapikey'
ACCOUNT_NUMBER=10010101
API_ENDPOINT="https://lon.networks.api.rackspacecloud.com/v2.0/$ACCOUNT_NUMBER"

TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`

curl -i -X GET https://lon.networks.api.rackspacecloud.com/v2.0/networks -H "X-Auth-Token: $TOKEN" 

Output

# ./list-networks.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5143  100  5028  100   115   4472    102  0:00:01  0:00:01 --:--:--  4477
HTTP/1.1 200 OK
Date: Fri, 12 Feb 2016 10:13:49 GMT
Via: 1.1 Repose (Repose/6.2.0.2)
Date: Fri, 12 Feb 2016 10:13:49 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 336
Server: Jetty(9.2.z-SNAPSHOT)

{"networks": [{"status": "ACTIVE", "subnets": [], "name": "Isolatednet", "admin_state_up": true, "tenant_id": "10010101", "shared": false, "id": "ae36972f-5cba-4327-8bff-15d8b05dc3ee"}], "networks_links": [{"href": "http://localhost:9696/v2.0/networks?marker=ae36972f-5cba-4327-8bff-15d8b05dc3ee&page_reverse=True", "rel": "previous"}]}

Pretty cool, but the format kind of sucks, I forgot to use python |-mjson.tool or jq to format the json output. Lets do that now by adding the line to the end of the curl -i line.

Now the output is nice:

{
    "networks": [
        {
            "admin_state_up": true,
            "id": "ae36972f-5cba-4327-8bff-15d8b05dc3ee",
            "name": "Isolatednet",
            "shared": false,
            "status": "ACTIVE",
            "subnets": [],
            "tenant_id": "10010101"
        }
    ],
    "networks_links": [
        {
            "href": "http://localhost:9696/v2.0/networks?marker=ae36972f-5cba-4327-8bff-15d8b05dc3ee&page_reverse=True",
            "rel": "previous"
        }
    ]
}

The complete code will look like;

#!/bin/sh

USERNAME='mycloudusername'
APIKEY='mycloudapikey'
ACCOUNT_NUMBER=10010101
API_ENDPOINT="https://lon.networks.api.rackspacecloud.com/v2.0/$ACCOUNT_NUMBER"

TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`

# with header no formatting
#curl -i -X GET https://lon.networks.api.rackspacecloud.com/v2.0/networks -H "X-Auth-Token: $TOKEN"
# without header with formatting
curl -X GET https://lon.networks.api.rackspacecloud.com/v2.0/networks -H "X-Auth-Token: $TOKEN" | python -mjson.tool

Using Meta-data to track Rackspace Cloud Servers

Hey, so from time to time we have customers who ask us about how they can tag their servers, this might be for automation or for means of organising their servers. Whilst it’s not possible to tag servers thru the API in such a way that it shows the ‘tag’ in the UI, that you can add in the mycloud control panel. You can instead use the cloud server meta-data set command, it’s easy enough. Here is how I achieved it.

set-meta-data.sh

#!/bin/bash

USERNAME='mycloudusername'
APIKEY='mycloudapikey'
# Tenant ID (account number is the number shown in the URL address when logged into Rackspace control panel)
ACCOUNT_NUMBER=1001010
API_ENDPOINT="https://lon.servers.api.rackspacecloud.com/v2/$ACCOUNT_NUMBER"
SERVER_ID='e9036384-c9be-4c8c-8551-c2f269c424bc'

# This just grabs from a large JSON output the AUTH TOKEN for the API. We auth with the apikey, and we get the auth token and set it in this variable 'TOKEN'
TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`


# Then we re-use the $TOKEN we retrieved for the call to the API, supply the $ACCOUNT_NUMBER and importantly, the $API_ENDPOINT.
# Also we sent a file, metadata.json that contains the meta-data we want to add to the server.
curl -s -v  \
-H "X-Auth-Token: $TOKEN"  \
-H "X-Project-Id: $ACCOUNT_NUMBER" \
-H "Accept: application/json"  \
-X PUT -d @metadata.json -H "content-type: application/json" "$API_ENDPOINT/servers/$SERVER_ID/metadata" | python -mjson.tool

metadata.json

{
    "metadata": {
        "Label" : "MyServer",
        "Version" : "v1.0.1-2"
    }
}
chmod +x set-meta-data.sh
./set-meta-data.sh

OK , so now you’ve set the data.

What about retrieving it you ask? That’s not too difficult. Just remove the PUT and replace it with a GET, and take away the -d @metadata.json bit, and we’re off, like so:

get-meta-data.sh


#!/bin/bash

USERNAME='mycloudusername'
APIKEY='mycloudapikey'
ACCOUNT_NUMBER=1001010
API_ENDPOINT="https://lon.servers.api.rackspacecloud.com/v2/$ACCOUNT_NUMBER"
SERVER_ID='c2036384-c9be-4c8c-8551-c2f269c4249r'


TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`



curl -s -v  \
-H "X-Auth-Token: $TOKEN"  \
-H "X-Project-Id: $ACCOUNT_NUMBER" \
-H "Accept: application/json"  \
-X GET "$API_ENDPOINT/servers/$SERVER_ID/metadata" | python -mjson.tool

simples! and as the fonz would say ‘Hey, grades are not cool, learning is cool. ‘

chmod +x get-meta-data.sh
./get-meta-data.sh 

Testing CDN Consistency with bash date time curl while loop

This is a simple one. Soa customer was complaining that after 3 minutes the cache time of the file on his CDN was changing. I wanted to built a way to test the consistency of the requests. Here is how I did it.

file curl-format.txt

     timenamelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
   time_pretransfer:  %{time_pretransfer}\n
      time_redirect:  %{time_redirect}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ----------\n
         time_total:  %{time_total}\n

Short, simple, and to the point;

while ((1!=0)); do date; curl -w "@curl-format.txt" -o /dev/null -s "https://www.somecdndomain.secure.raxcdn.com/img/upload/3someimage_t32337827238.jpg"; done;

Output looks like:

                    ----------
         time_total:  0.395
Tue Feb  9 09:03:28 UTC 2016
      time_namelookup:  0.151
       time_connect:  0.154
    time_appconnect:  0.332
   time_pretransfer:  0.333
      time_redirect:  0.000
 time_starttransfer:  0.338
                    ----------
         time_total:  0.351
Tue Feb  9 09:03:28 UTC 2016
      time_namelookup:  0.151
       time_connect:  0.154
    time_appconnect:  0.324
   time_pretransfer:  0.324
      time_redirect:  0.000
 time_starttransfer:  0.331
                    ----------
         time_total:  0.347
Tue Feb  9 09:03:29 UTC 2016
      time_namelookup:  0.151
       time_connect:  0.154
    time_appconnect:  0.385
   time_pretransfer:  0.385
      time_redirect:  0.000
 time_starttransfer:  0.391
                    ----------
         time_total:  0.404
Tue Feb  9 09:03:29 UTC 2016
      time_namelookup:  0.151
       time_connect:  0.155
    time_appconnect:  0.348
   time_pretransfer:  0.349
      time_redirect:  0.000
 time_starttransfer:  0.357
                    ----------
         time_total:  0.374
Tue Feb  9 09:03:30 UTC 2016
      time_namelookup:  0.151
       time_connect:  0.155
    time_appconnect:  0.408
   time_pretransfer:  0.409
      time_redirect:  0.000
 time_starttransfer:  0.417
                    ----------
         time_total:  0.433
Tue Feb  9 09:03:30 UTC 2016

pretty handy andy.

With headers

# while ((1!=0)); do date; curl -IL -w "@curl-format.txt" -s "https://www.scdn3.secure.raxcdn.com/img/upload/3_sdsdsds6a9e80df0baa19863ffb8.jpg"; sleep 180; done;

Installing Kali Linux on the Cloud

So, I want to install Kali Linux on the cloud, which… for me is good, but I highly recommend against doing this on any other cloud than your own private cloud.

katoolin

It’s actually pretty simple to get started with Kali, since it’s based on Debian and Ubuntu based distros (mainly debian from what I understand), it’s possible to install the repo’s on both Ubuntu and Debian. There’s even a really nice tool I found on techmint.com explaining the process. Here I am using wheezy 7. I’m pretty sure I could have used Debian, Jessie 8 though.

Step 1. Update repo and install git

# Update your repository
apt-get update
# Install git
apt-get install git

Step 2. Install katoolin from git

git clone https://github.com/LionSec/katoolin.git  && cp katoolin/katoolin.py /usr/bin/katoolin
# Make sure katoolin can be executed
chmod +x  /usr/bin/katoolin

# Start script to install kali
katoolin

What katoolin looks like

 $$\   $$\             $$\                         $$\ $$\           
 $$ | $$  |            $$ |                        $$ |\__|          
 $$ |$$  /  $$$$$$\  $$$$$$\    $$$$$$\   $$$$$$\  $$ |$$\ $$$$$$$\  
 $$$$$  /   \____$$\ \_$$  _|  $$  __$$\ $$  __$$\ $$ |$$ |$$  __$$\ 
 $$  $$<    $$$$$$$ |  Kali linux tools installer |$$ |$$ |$$ |  $$ |
 $$ |\$$\  $$  __$$ |  $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |$$ |$$ |  $$ |
 $$ | \$$\ \$$$$$$$ |  \$$$$  |\$$$$$$  |\$$$$$$  |$$ |$$ |$$ |  $$ |
 \__|  \__| \_______|   \____/  \______/  \______/ \__|\__|\__|  \__| V1.0 


 + -- -- +=[ Author: LionSec | Homepage: www.lionsec.net
 + -- -- +=[ 330 Tools 

		

1) Add Kali repositories & Update 
2) View Categories
3) Install classicmenu indicator
4) Install Kali menu
5) Help

Press 1 to add kali repositories and update.
Then press 1 again. It just set the repositories.
Now press 2. It will update the repositories.

Just one more step!

Then type 'gohome' to return to the first menu.
Then press '2' to see selection of packages to install
Then press '0' to install all of them.

Installing goodies..

katoolin-upgrade

Using Cloud Files Versioning, Setting up from Scratch

Sooooo.. you want to use cloud-files, but, you want to have versioning? no problem! Here’s how you do it from the ground up.

Authorise yourself thru identity API

Basically… set the token by querying the identity api with username and password..

!/bin/bash

# Username used to login to control panel
USERNAME='mycloudusername'

# Find the APIKey in the 'account settings' part of the menu of the control panel
APIKEY='mycloudapikey'

# This section simply retrieves the TOKEN
TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`

If you were to add to this file;

echo $TOKEN

You’d see this when running it

# ./versioning.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5143  100  5028  100   115   3991     91  0:00:01  0:00:01 --:--:--  3996
8934534DFGJdfSdsdFDS232342DFFsDDFIKJDFijTx8WMIDO8CYzbhyViGGyekRYvtw3skCYMaqIWhw8adskfjds894FGKJDFKj34i2jgidgjdf@DFsSDsd

To understand how the curl works to authorise itself with the identity API and specifically how the TOKEN is extracted from the return output and set in the script, here is the -v verbose output


# ./versioning.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
* About to connect() to identity.api.rackspacecloud.com port 443 (#0)
*   Trying 72.3.138.129...
* Connected to identity.api.rackspacecloud.com (72.3.138.129) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_DHE_RSA_WITH_AES_128_CBC_SHA
* Server certificate:
* 	subject: CN=identity.api.rackspacecloud.com,OU=Domain Validated,OU=Thawte SSL123 certificate,OU=Go to https://www.thawte.com/repository/index.html,O=identity.api.rackspacecloud.com
* 	start date: Nov 14 00:00:00 2011 GMT
* 	expire date: Nov 12 23:59:59 2016 GMT
* 	common name: identity.api.rackspacecloud.com
* 	issuer: CN=Thawte DV SSL CA,OU=Domain Validated SSL,O="Thawte, Inc.",C=US
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0> POST /v2.0/tokens HTTP/1.1
> User-Agent: curl/7.29.0
> Host: identity.api.rackspacecloud.com
> Accept: */*
> Content-type: application/json
> Content-Length: 115
>
} [data not shown]
* upload completely sent off: 115 out of 115 bytes
< HTTP/1.1 200 OK
< Server: nginx
< Date: Tue, 02 Feb 2016 18:19:06 GMT
< Content-Type: application/json
< Content-Length: 5028
< Connection: keep-alive
< X-NewRelic-App-Data: Censored
< vary: Accept, Accept-Encoding, X-Auth-Token
< Front-End-Https: on
<
{ [data not shown]
100  5143  100  5028  100   115   3825     87  0:00:01  0:00:01 --:--:--  3826
* Connection #0 to host identity.api.rackspacecloud.com left intact
{
    "access": {
        "serviceCatalog": [
            {
                "endpoints": [
                    {
                        "internalURL": "https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_10045567",
                        "publicURL": "https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10045567",
                        "region": "LON",
                        "tenantId": "MossoCloudFS_10010101"
                    }
                ],
                "name": "cloudFiles",
                "type": "object-store"
            },
            {
   "token": {
            "RAX-AUTH:authenticatedBy": [
                "APIKEY"
            ],
            "expires": "2016-02-03T18:31:18.838Z",
            "id": "#$dfgkldfkl34klDFGDFGLK#$OFDOKGDFODJ#$OFDOGIDFOGI34ldfldfgkdo34lfdFGDKDFGDODFKDFGDFLK",
            "tenant": {
                "id": "10010101",
                "name": "10010101"
            }
        },

This is truncated, the output is larger, but basically the "token" section is stripped away at the id: part so that only the string is left, then that password is added into the TOKEN variable.

So no you understand auth.

Create the Version container

This contains all of the version changes of any file

i.e. if you overwrite a file 10 times, all 10 versions will be saved

# Create Versioning Container (Backup versions)
curl -i -XPUT -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions

Note we use $TOKEN , which is basically just hte password with the X-Auth-Token Header. -H means 'send this header'. X-Auth-Token is the header name, and $TOKEN is the password we populated in the variable in the first auth section above.

Create a Current Container

This only contains the 'current' or most latest version of the file

# Create current container (latest versions)
curl -i -XPUT -H "X-Auth-Token: $TOKEN" -H  "X-Versions-Location: versions"  https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current

I'm being a bit naughty here, I could make MossoCloudFS_10010101 a variable, like $CONTAINERSTORE or $CONTAINERPARENT. Or better $TENANTCONTAINER But meh. You get the idea. And learnt something.

Note importantly X-Versions-Location Header set when creating the 'current' cloud files container. It's asking to store versions of changes in current to the versions folder. Nice.

Create an object

Create the first version of an object, because its awesome

# Create an object
curl -i -XPUT --data-binary 1 -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current/myobject.obj

yay! My first object. I just put the number 1 in it. Not very imaginative but you get the idea. Now lets revise the object

Create a new version of the object

# Create a new version of the object (second version)
curl -i -XPUT --data-binary 2 -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current/myobject.obj

Create a list of the older versions of the object

# Create a list of the older versions of the object
curl -i -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions?prefix=008myobject.obj

Delete the current version of an object

# Delete the current version of the object
curl -i -XDELETE -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions?prefix=008myobject.obj

Pretty cool. Altogether now.

#!/bin/bash

# Username used to login to control panel
USERNAME='mycloudusername'

# Find the APIKey in the 'account settings' part of the menu of the control panel
APIKEY=mycloudapikey'


# This section simply retrieves the TOKEN
TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`


# This section requests the Glance API to copy the cloud server image uuid to a cloud files container called export

# Create Versioning Container (Backup versions)
curl -i -XPUT -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions

# Create current container (latest versions)
curl -i -XPUT -H "X-Auth-Token: $TOKEN" -H  "X-Versions-Location: versions"  https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current


# Create an object
curl -i -XPUT --data-binary 1 -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current/myobject.obj

# Create a new version of the object (second version)
curl -i -XPUT --data-binary 2 -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/current/myobject.obj

# Create a list of the older versions of the object
curl -i -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions?prefix=008myobject.obj

# Delete the current version of the object

curl -i -XDELETE -H "X-Auth-Token: $TOKEN" https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_10010101/versions?prefix=008myobject.obj

What the output of the full script looks like:

# ./versioning.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5143  100  5028  100   115   4291     98  0:00:01  0:00:01 --:--:--  4290
HTTP/1.1 202 Accepted
Content-Length: 76
Content-Type: text/html; charset=UTF-8
X-Trans-Id: tx514bac5247924b5db247d-0056b0ecb7lon3
Date: Tue, 02 Feb 2016 17:51:51 GMT

Accepted

The request is accepted for processing.

HTTP/1.1 202 Accepted Content-Length: 76 Content-Type: text/html; charset=UTF-8 X-Trans-Id: tx7b7f42fc19b1428b97cfa-0056b0ecb8lon3 Date: Tue, 02 Feb 2016 17:51:52 GMT

Accepted

The request is accepted for processing.

HTTP/1.1 201 Created Last-Modified: Tue, 02 Feb 2016 17:51:53 GMT Content-Length: 0 Etag: c4ca4238a0b923820dcc509a6f75849b Content-Type: text/html; charset=UTF-8 X-Trans-Id: tx2495824253374261bf52a-0056b0ecb8lon3 Date: Tue, 02 Feb 2016 17:51:53 GMT HTTP/1.1 201 Created Last-Modified: Tue, 02 Feb 2016 17:51:54 GMT Content-Length: 0 Etag: c81e728d9d4c2f636f067f89cc14862c Content-Type: text/html; charset=UTF-8 X-Trans-Id: tx785e4a5b784243a1b8034-0056b0ecb9lon3 Date: Tue, 02 Feb 2016 17:51:54 GMT HTTP/1.1 204 No Content Content-Length: 0 X-Container-Object-Count: 2 Accept-Ranges: bytes X-Storage-Policy: Policy-0 X-Container-Bytes-Used: 2 X-Timestamp: 1454435183.80523 Content-Type: text/html; charset=UTF-8 X-Trans-Id: tx4782072371924905bc513-0056b0ecbalon3 Date: Tue, 02 Feb 2016 17:51:54 GMT

Rackspace Customer takes the time to improve my script :D

Wow. this was an awesome customer. Who was obviously capable in using the API but was struggling. So I thrown them my portable python -mjson parsing script for identity token and glance image export to cloud files. So,the customer wrote back, commenting that I’d made a mistake, specifically I had added ‘export’ instead of ‘exports’

#!/bin/bash

# Task ID - supply with command
TASK=$1
# Username used to login to control panel
USERNAME='myusername'
# Find the APIKey in the 'account settings' part of the menu of the control panel
APIKEY='myapikeyhere'

# This section simply retrieves the TOKEN
TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`

# Requests progress of specified task
curl -X GET -H "X-Auth-Token: $TOKEN" "https://lon.images.api.rackspacecloud.com/v2/10010101/tasks/$TASK"

I just realised that the customer didn’t adapt the script to be able to pass in the image ID, on the initial export to cloud files.

Theoretically you could not only do the above but.. something like:

I just realised your script you sent checks the TASK. I just amended my initial script a bit further with your suggestion to accept myclouduser mycloudapikey and mycloudimageid

#!/bin/bash

# Username used to login to control panel
USERNAME=$1
# Find the APIKey in the 'account settings' part of the menu of the control panel
APIKEY=$2

# Find the image ID you'd like to make available on cloud files
IMAGEID=$3

# This section simply retrieves the TOKEN
TOKEN=`curl https://identity.api.rackspacecloud.com/v2.0/tokens -X POST -d '{ "auth":{"RAX-KSKEY:apiKeyCredentials": { "username":"'$USERNAME'", "apiKey": "'$APIKEY'" }} }' -H "Content-type: application/json" |  python -mjson.tool | grep -A5 token | grep id | cut -d '"' -f4`


# This section requests the Glance API to copy the cloud server image uuid to a cloud files container called export
curl https://lon.images.api.rackspacecloud.com/v2/10031542/tasks -X POST -H "X-Auth-Token: $TOKEN" -H "Content-Type: application/json" -d '{"type": "export", "input": {"image_uuid": "'"$IMAGEID"'", "receiving_swift_container": "exports"}}'

# I thought that could theoretically process the output of the above and extract $TASK_ID to check the TASK too.

Note my script isn’t perfect but the customer did well!

This way you could simply provide to the script the cloud username, password and imageid. Then when the glance export starts, the task could be extracted in the same way as the TOKEN is from identity auth.

That way you could simply run something like

./myexportvhd.sh mycloudusername mycloudapikey mycloudimageid 

Not only would it start the image export to a set export folder.
But it'd provide you an update as to the task status.

You could go further, you could then watch the tasks status with a batch script while loop, until all show a complete or failed output and then record which ones succeeded and which ones failed. You could then create a batch script off that which downloaded and rsynched to somewhere the ones that succeeded.

Or..something like that.

I love it when one of our customers makes me think really hard. Gotta love that!