{"id":677,"date":"2016-06-24T17:38:35","date_gmt":"2016-06-24T16:38:35","guid":{"rendered":"http:\/\/www.haxed.me.uk\/?p=677"},"modified":"2016-06-25T00:51:18","modified_gmt":"2016-06-24T23:51:18","slug":"move-rackspace-cloud-servers-regions","status":"publish","type":"post","link":"https:\/\/haxed.me.uk\/index.php\/2016\/06\/24\/move-rackspace-cloud-servers-regions\/","title":{"rendered":"Move Rackspace Cloud Servers between Regions (Automation)"},"content":{"rendered":"<p>Hey!<\/p>\n<p>So I wrote a piece of software (basic) using BASh which exports Rackspace Cloud Servers between regions. It&#8217;s pure API CALLS using curl and I&#8217;m particularly proud of this piece, since it only took a day. (once I spent the whole of the next day figuring out an issue with the JSON and bash expansion for parameters to export the cloud server image to cloud files).<\/p>\n<p>This is a super rough example of an automation-in-progress for cloud-servers between regions. Once you&#8217;ve set the script up, you simply change the serverid, and the script can do the rest, and you can migrate server by server, or perform batch migrates with this. <\/p>\n<p>I&#8217;m going to refactor and rewrite it when I have time, but for now, here you are! Enjoy \ud83d\ude00 <\/p>\n<p>I hope that this is useful to people, particularly our customers.. when I release a finely tuned version that has commandline arguments support.<br \/>\n<code><br \/>\n#!\/bin\/bash<\/p>\n<p>USERNAME=''<br \/>\nAPIKEY=''<br \/>\nAPI_ENDPOINT='https:\/\/lon.servers.api.rackspacecloud.com\/v2\/100101010'<br \/>\nSERVER_ID='cd2b545b-99d4-42c1-a881-4714f4bf4b92'<br \/>\nTENANT='100101010'<br \/>\nTOKEN=`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`<\/p>\n<p># START IMAGE CREATION<br \/>\necho \"Creating Image at Local Datacentre\"<\/p>\n<p>curl -v -D export-headers \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-H \"content-type: application\/json\" \\<br \/>\n-d '{\"createImage\" : {\"name\" : \"RA-'$SERVER_ID'\", \"metadata\": { \"ImageType\": \"Rackspace Automation Image Exported from '$TENANT'\", \"ImageVersion\": \"2.0\"}}}' \\<br \/>\n-X POST \"$API_ENDPOINT\/servers\/$SERVER_ID\/action\" > export-headers<\/p>\n<p>echo \"export headers\"<br \/>\ncat export-headers<\/p>\n<p># Retrieve correct ImageID and use to check status of image<br \/>\nIMAGEID=$(cat export-headers | grep -i location | sed 's\/\\\/\/ \/g' | awk '{print $7}')<br \/>\nsleep 5<br \/>\necho \"image id\"<br \/>\necho $IMAGEID<\/p>\n<p>API_ENDPOINT='https:\/\/lon.images.api.rackspacecloud.com\/v2\/images\/'<br \/>\nURL=$API_ENDPOINT$IMAGEID<br \/>\nURL=${URL%$'\\r'}<\/p>\n<p>curl -v \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: 100101010\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-H \"content-type: application\/json\" \\<br \/>\n-X GET \"$URL\" | python -mjson.tool > imagestatus<\/p>\n<p>echo \"imagestatus: $imagestatus\"<\/p>\n<p>STATUS=$(cat imagestatus  | grep status | awk '{print $2}' | sed 's\/\"\/\/g' | sed 's\/,\/\/g')<\/p>\n<p>## WAIT FOR IMAGE TO EXIT SAVE STATE<\/p>\n<p>echo \"Waiting for image to complete...\"<br \/>\nsleep 5<br \/>\nwhile [ \"$STATUS\" != \"active\" ]; do<br \/>\n\techo \"image $IMAGEID is still saving...\"<br \/>\n\tsleep 10<br \/>\n\tcurl -s  \\<br \/>\n\t-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n\t-H \"X-Project-Id: 100101010\" \\<br \/>\n\t-H \"Accept: application\/json\" \\<br \/>\n\t-H \"content-type: application\/json\" \\<br \/>\n\t-X GET \"$URL\" | python -mjson.tool > imagestatus<\/p>\n<p>STATUS=$(cat imagestatus | grep status | awk '{print $2}' | sed 's\/\"\/\/g' | sed 's\/,\/\/g')<br \/>\ndone<\/p>\n<p>## PREPARE\/CREATE CLOUD FILES CONTAINER for EXPORT<\/p>\n<p>echo \"Preparing\/Creating Cloud Files Container for Export\"<br \/>\nAPI_ENDPOINT='https:\/\/storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_100101010'<\/p>\n<p>curl -v -s  \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: 100101010\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-X PUT \"$API_ENDPOINT\/export\"<br \/>\nsleep 5<\/p>\n<p>## EXPORT VHD TO CLOUD FILES<\/p>\n<p>echo \"Exporting VHD to Cloud Files\"<br \/>\n# This section simply retrieves the TOKEN<br \/>\nTOKEN=`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`<\/p>\n<p>echo \"IMAGEID detected as $IMAGEID\"<br \/>\n# This section requests the Glance API to copy the cloud server image uuid to a cloud files container called export<br \/>\n# > export-cloudfiles<\/p>\n<p>echo \"THE IMAGE ID IS: $IMAGEID\"<br \/>\nIMAGEID=${IMAGEID%$'\\r'}<br \/>\ncurl -v \"https:\/\/lon.images.api.rackspacecloud.com\/v2\/$TENANT\/tasks\" -X POST -H \"X-Auth-Token: $TOKEN\" -H \"Content-Type: application\/json\" -d '{\"type\": \"export\", \"input\": {\"image_uuid\": \"'$IMAGEID'\" , \"receiving_swift_container\": \"export\"}}' -o export-cloudfiles<br \/>\necho \"Export looks like\"<\/p>\n<p>cat export-cloudfiles<\/p>\n<p>sleep 15<\/p>\n<p>echo \"export cloud-files looks like:\"<br \/>\ncat export-cloudfiles<\/p>\n<p>TASKID_EXPORT=$(cat export-cloudfiles | python -mjson.tool | grep '\"id\"' | awk '{print $2}' | sed 's\/\"\/\/g' | sed 's\/,\/\/g')<\/p>\n<p>echo \"task ID export looks like\"<br \/>\necho \"$TASKID_EXPORT\"<\/p>\n<p>API_ENDPOINT='https:\/\/storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_100101010'<\/p>\n<p>sleep 15<\/p>\n<p>echo \"Waiting for Task to complete...\"<br \/>\n## WAIT FOR TASKID EXPORT TO COMPLETE TO CLOUD FILES<\/p>\n<p># This section simply retrieves the TOKEN<br \/>\nTOKEN=`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`<\/p>\n<p># This section requests the Glance API to copy the cloud server image uuid to a cloud files container called export<br \/>\ncurl \"https:\/\/lon.images.api.rackspacecloud.com\/v2\/10101010\/tasks\/$TASKID_EXPORT\" -X GET -H \"X-Auth-Token: $TOKEN\" -H \"Content-Type: application\/json\" | python -mjson.tool > export-status<\/p>\n<p>EXPORT_STATUS=$(cat export-status | grep status | awk '{print $2}' | sed 's\/\"\/\/g' | sed 's\/,\/\/g')<\/p>\n<p>while [ \"$EXPORT_STATUS\" = \"processing\" ]; do<br \/>\nsleep 15<br \/>\ncurl \"https:\/\/lon.images.api.rackspacecloud.com\/v2\/100101010\/tasks\/$TASKID_EXPORT\" -X GET -H \"X-Auth-Token: $TOKEN\" -H \"Content-Type: application\/json\" | python -mjson.tool > export-status<br \/>\nEXPORT_STATUS=$(cat export-status | grep status | awk '{print $2}' | sed 's\/\"\/\/g' | sed 's\/,\/\/g')<br \/>\ndone<\/p>\n<p># SET CORRECT CLOUD FILES NAME<br \/>\nCLOUD_FILES_NAME=$(cat export-cloudfiles | python -mjson.tool | grep image_uuid | awk '{print $2}' | sed 's\/,\/\/g'  | sed 's\/\"\/\/g')<\/p>\n<p>## Download VHD Cloud from Cloud Files to this server<\/p>\n<p>API_ENDPOINT='https:\/\/storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_10101010'<\/p>\n<p># GET FILE FROM SOURCE CLOUD FILES<\/p>\n<p>URL=\"$API_ENDPOINT\/export\/$CLOUD_FILES_NAME.vhd\"<br \/>\nURL=${URL%$'\\r'}<\/p>\n<p>curl -s \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: $TENANT\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-X GET \"$API_ENDPOINT\/export\/$CLOUD_FILES_NAME.vhd\" > $CLOUD_FILES_NAME.vhd<\/p>\n<p>## NEW API USER\/PASS REQUIRED FOR 2ND REGION<\/p>\n<p>USERNAME=''<br \/>\nAPIKEY=''<\/p>\n<p>## Now for uploading the VHD to Cloud Files to Destination REGION<\/p>\n<p>API_ENDPOINT='https:\/\/storage101.ord1.clouddrive.com\/v1\/MossoCloudFS_891671'<br \/>\nTOKEN=`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`<\/p>\n<p>curl -v -s  \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: 891671\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-X PUT \"$API_ENDPOINT\/import\"<\/p>\n<p>## Upload VHD Image to Cloud Files destination for import<br \/>\ncurl -v -s  \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: 891671\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-X PUT \"$API_ENDPOINT\/import\/$CLOUD_FILES_NAME.vhd\" -T \"$CLOUD_FILES_NAME.vhd\"<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey! So I wrote a piece of software (basic) using BASh which exports Rackspace Cloud Servers between regions. It&#8217;s pure API CALLS using curl and I&#8217;m particularly proud of this piece, since it only took a day. (once I spent &hellip; <a href=\"https:\/\/haxed.me.uk\/index.php\/2016\/06\/24\/move-rackspace-cloud-servers-regions\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,42,19,15,39,37,30,9,7,36,11,12,52],"tags":[],"class_list":["post-677","post","type-post","status-publish","format-standard","hentry","category-api","category-automation","category-bash","category-cloud","category-cloud-backup","category-disaster-recovery","category-glance-api","category-linux","category-management-tools","category-migration","category-openstack","category-openstack-api","category-virtualization"],"_links":{"self":[{"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts\/677","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/comments?post=677"}],"version-history":[{"count":4,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts\/677\/revisions"}],"predecessor-version":[{"id":681,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts\/677\/revisions\/681"}],"wp:attachment":[{"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/media?parent=677"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/categories?post=677"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/tags?post=677"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}