{"id":684,"date":"2016-07-01T10:44:35","date_gmt":"2016-07-01T09:44:35","guid":{"rendered":"http:\/\/www.haxed.me.uk\/?p=684"},"modified":"2016-07-01T12:26:11","modified_gmt":"2016-07-01T11:26:11","slug":"moving-cloud-servers-regions-automation-rackspace-managed-services","status":"publish","type":"post","link":"https:\/\/haxed.me.uk\/index.php\/2016\/07\/01\/moving-cloud-servers-regions-automation-rackspace-managed-services\/","title":{"rendered":"Moving Rackspace Cloud Servers between Regions with automation II"},"content":{"rendered":"<p>Hey folks. So, recently I have been doing a bit of work on the Rackspace community, specifically trying to document and make as easy as possible the importing and exporting of cloud server VHD&#8217;s between Rackspace regions. This might be really useful if you are designing some HA or multi-region and\/or load balancing solution that might be utilizing autoscale, and other kinds of redundancy too, but moving your &#8216;golden image&#8217; between regions might be quite difficult if doing the entire process manually or step by step as I have documented in the below two articles:<\/p>\n<p>Exporting Cloud server images from a Rackspace Region\n<link>\nhttps:\/\/community.rackspace.com\/products\/f\/25\/t\/7089\n<\/link>\n<p>Importing Cloud Server Images to a Rackspace Region\n<link>\nhttps:\/\/community.rackspace.com\/products\/f\/25\/t\/7186\n<\/link>\n<p>In this article I completely finish writing the &#8216;automation demo&#8217; of how to specifically move images, without changing much at all, apart from one &#8216;serverID&#8217; variable, and the source and destination. The script isn&#8217;t finished yet, however the last time I posted this on my blog I was so excited, I actually forgot to include the import function. (which is kind of important!) sorry about that.<\/p>\n<p><code><br \/>\n#!\/bin\/bash<\/p>\n<p>USERNAME='yourmycloudusernamehere'<br \/>\nAPIKEY='youapikeyhere'<br \/>\nAPI_ENDPOINT='https:\/\/lon.servers.api.rackspacecloud.com\/v2\/1000000'<br \/>\nSERVER_ID='94157dc7-924a-424a-8825-c5ffbd341622'<br \/>\nTENANT='1000000'<br \/>\nCUSTOMER_ID='1000000'<\/p>\n<p>#### DO NOT CHANGE BELOW THIS LINE<\/p>\n<p>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`<\/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\" -o \/tmp\/export-file<\/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: 1000000\" \\<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: 1000000\" \\<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_1000000'<\/p>\n<p>curl -v -s  \\<br \/>\n-H \"X-Auth-Token: $TOKEN\"  \\<br \/>\n-H \"X-Project-Id: 1000000\" \\<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_1000000'<\/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\/1000000\/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\/1000000\/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_1000000'<\/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>### DO NOT CHANGE ANYTHING ABOVE THIS POINT<\/p>\n<p>USERNAME='yourmycloudusernamegoeshere'<br \/>\nAPIKEY='yourapikeyfromsecondregiongoeshere'<\/p>\n<p>### DO NOT CHANGE ANYTHING BELOW THIS POINT<\/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_900000'<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: 900000\" \\<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: 900000\" \\<br \/>\n-H \"Accept: application\/json\" \\<br \/>\n-X PUT \"$API_ENDPOINT\/import\/$CLOUD_FILES_NAME.vhd\" -T \"$CLOUD_FILES_NAME.vhd\"<\/p>\n<p># Find the Customer_ID<br \/>\nIMPORT_IMAGE_ENDPOINT=https:\/\/ord.images.api.rackspacecloud.com\/v2\/$CUSTOMER_ID<\/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>VHD_NOTES=\"autoimport-$SERVER_ID\"<br \/>\nIMPORT_CONTAINER=import<br \/>\nVHD_FILENAME=\"$CLOUD_FILES_NAME.vhd\"<\/p>\n<p>curl -X POST \"$IMPORT_IMAGE_ENDPOINT\/tasks\" \\<br \/>\n      -H \"X-Auth-Token: $TOKEN\" \\<br \/>\n      -H \"Content-Type: application\/json\" \\<br \/>\n      -d \"{\\\"type\\\":\\\"import\\\",\\\"input\\\":{\\\"image_properties\\\":{\\\"name\\\":\\\"$VHD_NOTES\\\"},\\\"import_from\\\":\\\"$IMPORT_CONTAINER\/$VHD_FILENAME\\\"}}\" |\\<br \/>\n      python -mjson.tool<\/p>\n<p><\/code><\/p>\n<p>As You can probably see my code is still rather rough, but it&#8217;s just so darn exciting that this script works from start to finish, nicely I just HAD to share it a bit earlier! The plan now is to add commandline function so that you can specify .\/moveregion {SOURCE_REGION} {DEST_REGION} {SERVER_ID} {TENANT_ID} . Then a customer or a racker would only need these 4 variables to import and export images in an automated way.<\/p>\n<p>I can rewrite the script in such a way that it would accept a .txt file of a couple of hundred cloud server UUID&#8217;s, and it would take the server UUID of each, use that uuid to create an image of each server, export to cloud files, import to cloud files, and then import to glance image store for the second region destination. Which naturally, would save hundreds of hours of human time doing this manually.. which is &#8230; nice \ud83d\ude00<\/p>\n<p>I would really like to make a UI frontend, using something like Django, and utilize some form of &#8216;light&#8217; database, that keeps track of all the API import\/exports, and even provides estimated time for completion, but my UI skills are really limited to xhtml, css php and mysql.. I need a python or django guy to help out with some of this. If anyone is interested, please reach out to me.<\/p>\n<p>This project will be avaialble on github soon<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey folks. So, recently I have been doing a bit of work on the Rackspace community, specifically trying to document and make as easy as possible the importing and exporting of cloud server VHD&#8217;s between Rackspace regions. This might be &hellip; <a href=\"https:\/\/haxed.me.uk\/index.php\/2016\/07\/01\/moving-cloud-servers-regions-automation-rackspace-managed-services\/\">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,56,19,15,14,37,10,30,43,9,7,36,11,12,52],"tags":[],"class_list":["post-684","post","type-post","status-publish","format-standard","hentry","category-api","category-automation","category-autoscale","category-bash","category-cloud","category-cloud-files","category-disaster-recovery","category-filesystem","category-glance-api","category-ha","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\/684","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=684"}],"version-history":[{"count":1,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts\/684\/revisions"}],"predecessor-version":[{"id":686,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/posts\/684\/revisions\/686"}],"wp:attachment":[{"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/media?parent=684"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/categories?post=684"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haxed.me.uk\/index.php\/wp-json\/wp\/v2\/tags?post=684"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}