Recently I had a colleague come to me with a request. They had a Nutanix Prism Central production environment with certain images loaded. The previous administrator failed to document where those images were stored and they could not be located. My colleague wanted to download the images from their production Prism Central so they could upload them to a new test environment. I have written a Python script that will make that quite easy.
As with other scripts I have posted, there are some caveats to go over. First, I wrote this on Linux with Python 3. I have tested it on Windows 10 with Ubuntu subsystem which had Python 3 installed, but not on Windows with just Python installed. On the Nutanix side, this was tested against PC & AOS v5.10.multiple. All APIs used are publicly available/documented APIs.
This script requires the “requests” module, which is standard in some distros. If it’s not, then use “pip3 install requests” to install it. Same with hurry.filesize. Make sure you “pip3 install hurry.filesize” not “pip3 install hurry”. See the import line for other modules you may need to install.
Now to the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
#!/usr/bin/python3 import requests, os, subprocess, platform, getpass, time from requests.auth import HTTPBasicAuth from requests.packages.urllib3.exceptions import InsecureRequestWarning from hurry.filesize import size uriimages = "/images/" urilist = "/images/list" imageno = "exit" ############################################### # DO NOT CHANGE ANYTHING BELOW THIS LINE!!!!! # ############################################### headers = {'content-type': 'application/json'} requests.packages.urllib3.disable_warnings(InsecureRequestWarning) FNULL = open(os.devnull, 'w') def ping(host): ping_str = "-n 1" if platform.system().lower()=="windows" else "-c 1" args = "ping " + " " + ping_str + " " + host need_sh = False if platform.system().lower()=="windows" else True return subprocess.call(args, shell=need_sh, stdout=FNULL, stderr=subprocess.STDOUT) == 0 # should convert these to try|except? def restget(uri): response = requests.get(uri,auth=HTTPBasicAuth(user,passwd),headers=headers,verify=False) return(response) def restdl(url,path): response = requests.get(url,auth=HTTPBasicAuth(user,passwd),headers=headers,verify=False,stream=True) handle = open(path, "wb") for chunk in response.iter_content(chunk_size=512): if chunk: handle.write(chunk) def restpost(uri,payload): response = requests.post(uri,auth=HTTPBasicAuth(user,passwd),headers=headers,json=payload,verify=False) return(response) ######################## # MAIN # ######################## if __name__ == '__main__': CIP = input("Enter your Prism Central IP/DNS address: ") buri3 = "https://" + CIP + ":9440/api/nutanix/v3" user = input("Enter your Nutanix cluster username: ") passwd = getpass.getpass("Enter your Nutanix cluster password: ") if ping(CIP): print("\n") uri = buri3 + urilist payload = {'kind':'image','sort_order':'ASCENDING','sort_attribute':'name','length':50} status = restpost(uri,payload) # want to see the full output of the rest call? Uncomment this line: # print(status.json()) if (status.ok): while (imageno.lower() != "x"): print ("\n" * 100) print("\nList of Images currently on Prism Central: \n") for a in range(len(status.json()['entities'])): try: status.json()['entities'][a]['status']['resources']['size_bytes'] except: print(str(a) + ": " + status.json()['entities'][a]['status']['name'] + "\t\t(Size Unknown)") else: print(str(a) + ": " + status.json()['entities'][a]['status']['name'] + "\t\t(" + size(status.json()['entities'][a]['status']['resources']['size_bytes']) + ")") imageno = input("\nPlease enter the number of the image you wish to download (x to exit): ") # definitely a cleaner way to do this if/when I get time... if (imageno == "x"): print("Exiting...\n") elif (int(imageno) <= status.json()['metadata']['total_matches']): print("downloading " + status.json()['entities'][int(imageno)]['status']['name'] + "\n") url = buri3 + uriimages + status.json()['entities'][int(imageno)]['metadata']['uuid'] + "/file" path = "./" + status.json()['entities'][int(imageno)]['status']['name'] dlstatus = restdl(url,path) time.sleep(3) else: print("Unable to get image list from PC:\t ", status.json() ,"\n Please investigate. Exiting...") raise SystemExit else: print("Cannot ping cluster " + CIP) print("Please investigate. Exiting...") raise SystemExit print("\n") |
As this is a REST API based script, there is no need to run this in a CVM. Run this from your workstation. Make sure you are in a directory that has enough storage to store the image you download. The script will show you the file sizes of your images. One thing I’d like to add is a progress bar.
Update: Added support for up to 50 images to be listed. If you need more try changing the length from 50 to what you need. Also accounted for images that do not report a file size.
Here’s a screenshot of the script being run: