Skip to content

Instantly share code, notes, and snippets.

@prziborowski
Created July 18, 2020 00:26
Show Gist options
  • Save prziborowski/8bbb9233b58246fd4abfc6f936da160c to your computer and use it in GitHub Desktop.
Save prziborowski/8bbb9233b58246fd4abfc6f936da160c to your computer and use it in GitHub Desktop.
#!/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