diff --git a/README.md b/README.md index d325da10..fd3c803c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ samples require the vSphere Management SDK packages (pyVmomi) to be installed on The samples have been developed to work with python 2.7.x and 3.3+ ## Supported OnPrem vCenter Releases -vCenter 6.0, 6.5, 6.7, 7.0 and 7.0U1. +vCenter 6.0, 6.5, 6.7, 7.0, 7.0U1 and 7.0U2. Certain APIs and samples that are introduced in 6.5 release, such as vCenter, Virtual Machine and Appliance Management. Please refer to the notes in each sample for detailed compatibility information. ## Supported NSX-T Releases @@ -214,8 +214,8 @@ $ python samples/vsphere/vcenter/vm/list_vms.py -v ### vSphere API Documentation * [VMware Cloud on AWS vSphere (latest version)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/cloud/index.html) -* [vSphere 7.0 Update 1 (latest)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.1.0/) -* Previous releases: [7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.0.1/) [6.7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.7.0) [6.6.1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.6.1) [6.5](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.5) [6.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.0) +* [vSphere 7.0 Update 2 (latest)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.2.0/) +* Previous releases: [7.0 U1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.1.0/) [7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.0.1/) [6.7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.7.0) [6.6.1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.6.1) [6.5](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.5) [6.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.0) ### VMware Cloud on AWS API Documentation diff --git a/samples/vsphere/vcenter/vm/guest/guest_ops.py b/samples/vsphere/vcenter/vm/guest/guest_ops.py new file mode 100644 index 00000000..9b2f394d --- /dev/null +++ b/samples/vsphere/vcenter/vm/guest/guest_ops.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python + +""" +* ******************************************************* +* Copyright (c) VMware, Inc. 2020. All Rights Reserved. +* SPDX-License-Identifier: MIT +* ******************************************************* +* +* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN, +* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED +* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, +* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. +""" + +__author__ = 'VMware Inc.' +__vcenter_version__ = 'VCenter 7.0 U2' + +import os +import ssl +import time + +from com.vmware.vcenter.vm.guest.filesystem_client import Transfers +from com.vmware.vcenter.vm.guest_client import Credentials +from com.vmware.vcenter.vm.guest_client import Processes +from com.vmware.vcenter_client import VM +from samples.vsphere.common import sample_cli +from samples.vsphere.common import sample_util +from samples.vsphere.common.ssl_helper import get_unverified_session +from vmware.vapi.vsphere.client import create_vsphere_client + +try: + # Python 3 + from urllib.parse import urlparse + import http.client as httpclient +except ImportError: + # Python 2 + from urlparse import urlparse + import httplib as httpclient + + +class GuestOps(object): + """ + Demonstrate the vAPI Guest Operations. + + Show the basic procedure to start a program or process on a Linux + guest VM and collect any output: + - create a temporary directory and temporary files for the process + stdout and stderr. + - upload a script to the guest. + - execute the script and collect the output. + + Prerequisites: + - vCenter + - ESX host + - running guest 'Photon-3.2-64-EFI-Open-VM-Tools-for-GuestOps-SDK' + with open-vm-tools installed and running. The testbed created by + samples/vsphere/vcenter/setup/main.py does not contain a guest + with a runnable Linux or Windows OS. + """ + + # Create the Process.CreateSpec for initiating processes in the guest + def _process_create_spec(self, path, args=None, dir=None, env={}): + return Processes.CreateSpec(path=path, + arguments=args, + working_directory=dir, + environment_variables=env) + + # Create the Transfer.CreateSpec for the file transfer to/from the guest + def _create_transfer_spec(self, + path, + attributes=None): + return Transfers.CreateSpec(attributes=attributes, + path=path) + + # Create a FileAttributeCreateSpec for a generic (non-OS specific) guest + def _fileAttributeCreateSpec_Plain(self, + size, + overwrite=None, + last_modified=None, + last_accessed=None): + return Transfers.FileCreationAttributes(size, + overwrite=overwrite, + last_modified=last_modified, + last_accessed=last_accessed) + + # Create a FileAttributeCreateSpec for a linux (Posix) guest + def _fileAttributeCreateSpec_Linux(self, + size, + overwrite=None, + last_modified=None, + last_accessed=None, + owner_id=None, + group_id=None, + permissions=None): + posix = Transfers.PosixFileAttributesCreateSpec(owner_id=owner_id, + group_id=group_id, + permissions=permissions) + return Transfers.FileCreationAttributes(size, + overwrite=overwrite, + last_modified=last_modified, + last_accessed=last_accessed, + posix=posix) + + def _download(self, + url, + expectedLen=None): + urloptions = urlparse(url) + # Skip server cert verification. + # This is not recommended in production code. + conn = httpclient.HTTPSConnection(urloptions.netloc, + context=ssl._create_unverified_context()) + + conn.request("GET", urloptions.path + "?" + urloptions.query) + res = conn.getresponse() + if res.status != 200: + print("GET request failed with errorcode : %s" % res.status) + raise HTTPError(res.status, res.reason) + body = res.read().decode() + + return body + + def _upload(self, url, body): + urloptions = urlparse(url) + conn = httpclient.HTTPSConnection(urloptions.netloc, + context=ssl._create_unverified_context()) + + headers = {"Content-Length": len(body)} + # Skip server cert verification. + # This is not recommended in production code. + conn.request("PUT", urloptions.path + "?" + urloptions.query, + body, + headers) + res = conn.getresponse() + if res.status != 200: + print("PUT request failed with errorcode : %s" % res.status) + raise HTTPError(res.status, res.reason) + + return res + + def __init__(self): + # Create argument parser for standard inputs: + # server, username, password, cleanup and skipverification + parser = sample_cli.build_arg_parser() + + # Add your custom input arguments + parser.add_argument('--vm_name', + action='store', + help='Name of the testing vm') + parser.add_argument('--root_user', + action='store', + help='Administrator account user name') + parser.add_argument('--root_passwd', + action='store', + help='Administrator account password') + + args = sample_util.process_cli_args(parser.parse_args()) + self.vm_name = args.vm_name + self.root_user = args.root_user + self.root_passwd = args.root_passwd + + self.cleardata = args.cleardata + + # Skip server cert verification if needed. + # This is not recommended in production code. + session = get_unverified_session() if args.skipverification else None + + # Connect to vSphere client + self.client = create_vsphere_client(server=args.server, + username=args.username, + password=args.password, + session=session) + + def run(self): + # Using vAPI to find VM. + filter_spec = VM.FilterSpec(names=set([self.vm_name])) + vms = self.client.vcenter.VM.list(filter_spec) + if len(vms) != 1: + raise Exception('Could not locate the required VM with name ' + + self.vm_name + '. Please create the vm first.') + if vms[0].power_state != 'POWERED_ON': + raise Exception('VM is not powered on: ' + vms[0].power_state) + vm_id = vms[0].vm + + # Check that vmtools svc (non-interactive user) is running. + info = self.client.vcenter.vm.guest.Operations.get(vm_id) + if info.guest_operations_ready is not True: + raise Exception('VMware Tools/open-vm-tools is not running as required.') + + # Establish the user credentials that will be needed for all Guest Ops + # APIs. + creds = Credentials(interactive_session=False, + user_name=self.root_user, + password=self.root_passwd, + type=Credentials.Type.USERNAME_PASSWORD) + + # Step 2 - Create a temporary directory from which to run the command + # and capture any output + tempDir = self.client.vcenter.vm.guest.filesystem.Directories.create_temporary( + vm_id, creds, '', '', parent_path=None) + + # Step 3 - Create temproary files to reveive stdout and stderr + # as needed. + stdout = self.client.vcenter.vm.guest.filesystem.Files.create_temporary( + vm_id, creds, '', '.stdout', parent_path=tempDir) + stderr = self.client.vcenter.vm.guest.filesystem.Files.create_temporary( + vm_id, creds, '', '.stderr', parent_path=tempDir) + + # Step 4 - (Optional) copy in the script to be run. + # While optional, using this step to demo tranfer of a + # file to a guest. + scriptPath = self.client.vcenter.vm.guest.filesystem.Files.create_temporary( + vm_id, creds, '', '.sh', tempDir) + + # Create script contents and transfer to the guest. + # TODO: Need generic pick up of script content + baseFN = os.path.basename(scriptPath) + script = ('#! /bin/bash\n' + '# ' + + baseFN + '\n' + '\n' + 'sleep 5 # Adding a little length to the process.\n' + 'ps -ef\n' + 'echo\n' + 'rpm -qa | sort\n' + '\n') + print(script) + attr = self._fileAttributeCreateSpec_Linux(size=len(script), + overwrite=True, + permissions='0755') + spec = self._create_transfer_spec(path=scriptPath, + attributes=attr) + toURL = self.client.vcenter.vm.guest.filesystem.Transfers.create(vm_id, + creds, + spec) + res = self._upload(toURL, script) + + # Check that the uploaded file size is correct. + info = self.client.vcenter.vm.guest.filesystem.Files.get(vm_id, + creds, + scriptPath) + if info.size != len(script): + raise Exception('Uploaded file size not as epected.') + + # Step 5 - Start the program on the guest, capturing stdout and stderr + # in the separate temp files obtained earlier. + options = (" > " + stdout + " 2> " + stderr) + + spec = self._process_create_spec(scriptPath, + args=options, + dir=tempDir) + pid = self.client.vcenter.vm.guest.Processes.create(vm_id, creds, spec) + print('process created with pid: %s\n' % pid) + + # Step 6 + # Need a loop to wait for the process to finish to handle longer + # running processes. + while True: + time.sleep(1.0) + try: + # List the single process for pid. + result = self.client.vcenter.vm.guest.Processes.get(vm_id, + creds, + pid) + if result.exit_code is not None: + print('Command: ' + result.command) + print('Exit code: %s\n' % result.exit_code) + break + if result.finished is None: + print('Process with pid %s is still running.' % pid) + continue + except Exception as e: + raise e + + # Step 7 Copy out the results (stdout). + spec = self._create_transfer_spec(path=stdout) + # create the download URL + fromURL = self.client.vcenter.vm.guest.filesystem.Transfers.create(vm_id, + creds, + spec) + body = self._download(fromURL, expectedLen=info.size) + print("----------- stdout ------------------") + print(body) + print("---------------------------------------") + + # Optionally the contents of "stderr" could be downloaded. + + # And finally, clean up the temporary files and directories on the + # Linux guest. Deleting the temporary diretory and its contents. + self.client.vcenter.vm.guest.filesystem.Directories.delete(vm_id, + creds, + tempDir, + recursive=True) + + +def main(): + sample = GuestOps() + sample.run() + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index bd025e63..4ef0b2aa 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import os from setuptools import setup setup(name='vSphere Automation SDK', - version='1.49.0', + version='1.50.0', description='VMware vSphere Automation SDK for Python', url='https://github.com/vmware/vsphere-automation-sdk-python', author='VMware, Inc.',