Created
July 18, 2020 00:26
-
-
Save prziborowski/8bbb9233b58246fd4abfc6f936da160c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Written by Nathan Prziborowski | |
Github: https://github.com/prziborowski | |
This code is released under the terms of the Apache 2 | |
http://www.apache.org/licenses/LICENSE-2.0.html | |
Download a VM file using an http request. | |
""" | |
import atexit | |
import os | |
import os.path | |
import re | |
from six.moves.urllib.request import Request, urlopen | |
from tools import cli | |
from pyVim.connect import SmartConnectNoSSL, Disconnect | |
from pyVmomi import vim | |
__author__ = 'prziborowski' | |
def setup_args(): | |
parser = cli.build_arg_parser() | |
parser.add_argument('-v', '--vm', help='Name of VM to use for downloading files', | |
required=True) | |
parser.add_argument('-d', '--dest-dir', | |
help='Directory to store downloaded files locally', required=True) | |
parser.add_argument('-f', '--file', | |
help='Individual file to download, leave blank for all VM files') | |
return cli.prompt_for_password(parser.parse_args()) | |
def get_obj(si, vim_type, name): | |
""" | |
Get an object based on name. | |
Not optimized for speed due to 'name' property fetch. | |
See https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/filter_vms.py | |
for optimized example. | |
""" | |
viewManager = si.content.viewManager | |
containerView = viewManager.CreateContainerView(si.content.rootFolder, [vim_type], True) | |
try: | |
for obj in containerView.view: | |
if obj.name == name: | |
return obj | |
finally: | |
containerView.Destroy() | |
raise Exception("Failed to find object of type %s in inventory with name %s" % | |
(vim_type, name)) | |
def main(): | |
args = setup_args() | |
try: | |
si = SmartConnectNoSSL(host=args.host, | |
user=args.user, | |
pwd=args.password, | |
port=args.port) | |
atexit.register(Disconnect, si) | |
except: | |
print("Unable to connect to %s" % args.host) | |
return 1 | |
vm = get_obj(si, vim.VirtualMachine, args.vm) | |
host = vm.runtime.host # The host the VM is registered to should be able to access files. | |
sessionMgr = si.content.sessionManager | |
# Retrieve all files, unless specified to just pick an individual file. | |
for info in vm.layoutEx.file: | |
if (args.file is not None and info.name.endswith(args.file)) or args.file is None: | |
m = re.match(r'\[(?P<ds_name>.*?)\] (?P<file_path>.*)', info.name) | |
if m is None: | |
print("No match for %s" % info.name) | |
continue | |
ds_name = m.group('ds_name') | |
file_path = m.group('file_path') | |
# Generate the URL we want to access from the host. | |
# ha-datacenter is the moID of the datacenter at the host level. | |
url = 'https://{}/folder/{}?dcPath=ha-datacenter&dsName={}'.format( | |
host.name, file_path, ds_name) | |
spec = vim.SessionManager.HttpServiceRequestSpec(method='GET', url=url) | |
ticket = sessionMgr.AcquireGenericServiceTicket(spec) | |
# The ticket.id gives us access to make this individual request. | |
headers = {'Content-Type': 'application/octet-stream', | |
'Cookie': 'vmware_cgi_ticket={}'.format(ticket.id)} | |
request = Request(url, headers=headers) | |
print("Url: %s" % url) | |
r = urlopen(request) | |
if r.getcode() == 200: | |
dest_path = os.path.join(args.dest_dir, os.path.basename(file_path)) | |
with open(dest_path, 'wb') as f: | |
while True: | |
data = r.read(4096) | |
if len(data) == 0: | |
break | |
f.write(data) | |
else: # We might fail if the VM is running and has files locked. | |
print("Failed to retrieve %s with error code %d" % (file_path, r.getcode())) | |
if __name__ == '__main__': | |
exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment