diff --git a/samples/attach_vdisk_to_vm.py b/samples/attach_vdisk_to_vm.py new file mode 100755 index 00000000..cd535971 --- /dev/null +++ b/samples/attach_vdisk_to_vm.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for attaching a first class disk (fcd) to a virtual machine +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVim.task import WaitForTask +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for attaching a fcd to a vm + + -d datastore + -v vdisk + -n vm_name + -i uuid + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-v', '--vdisk', + required=True, + action='store', + help='First Class Disk name to be attached') + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-n', '--vm_name', + action='store', + help='Virtual Machine name where disk is attached') + + group.add_argument('-i', '--uuid', + action='store', + help='Virtual Machine UUID where disk is attached') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def attach_fcd_to_vm(vm, vdisk, datastore): + """ + Attach already existing first class disk to vm + """ + # Finding next available unit number + unit_number = 0 + for dev in vm.config.hardware.device: + if hasattr(dev.backing, 'fileName'): + unit_number = int(dev.unitNumber) + 1 + # unit_number 7 reserved for scsi controller + if unit_number == 7: + unit_number += 1 + if unit_number >= 16: + raise Exception("We don't support this many disks.") + if isinstance(dev, vim.vm.device.VirtualSCSIController): + controller = dev + + # Setting backings + spec = vim.vm.ConfigSpec() + disk_spec = vim.vm.device.VirtualDeviceSpec() + disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add + disk_spec.device = vim.vm.device.VirtualDisk() + disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() + disk_spec.device.backing.diskMode = 'persistent' + disk_spec.device.backing.fileName = vdisk.config.backing.filePath + disk_spec.device.backing.thinProvisioned = True + disk_spec.device.unitNumber = unit_number + disk_spec.device.controllerKey = controller.key + + # Creating change list + dev_changes = [] + dev_changes.append(disk_spec) + spec.deviceChange = dev_changes + + # Sending the request + task = vm.ReconfigVM_Task(spec=spec) + return task + + +def main(): + """ + Simple command-line program for deleting a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Retrieve FCD Object + vdisk = retrieve_fcd(content, datastore, args.vdisk) + + # Retrieve VM + vm = None + if args.uuid: + search_index = content.searchIndex + vm = search_index.FindByUuid(None, args.uuid, True) + elif args.vm_name: + vm = get_obj(content, [vim.VirtualMachine], args.vm_name) + + # Attaching FCD to VM + if vm: + task = attach_fcd_to_vm(vm, vdisk, datastore) + tasks.wait_for_tasks(service_instance, [task]) + else: + raise RuntimeError("VM not found.") + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/create_vdisk.py b/samples/create_vdisk.py new file mode 100755 index 00000000..7b2119f1 --- /dev/null +++ b/samples/create_vdisk.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for creating a first class disk (fcd) +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl, vim, pbm, VmomiSupport + + +def get_args(): + """ + Adds additional args for creating a fcd + + -d datastore + -n name + -c capacityInGB + -e policy + -k keepAfterDeleteVm + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-n', '--name', + required=True, + action='store', + help='First Class Disk name to be created') + + parser.add_argument('-c', '--capacityInGB', + required=True, + action='store', + help='Size in GB of the First Class Disk.', + type=int) + + # because -s is reserved for 'service' and -p is reserved for 'password' + parser.add_argument('-e', '--policy', + action='store', + help='Storage Policy name. If unset, the default ' + 'policy of the datastore specified will apply.') + + parser.add_argument('-k', '--keepAfterDeleteVm', + action='store_true', + help='Keep after VM deletion. Choice of the ' + 'deletion behavior of this virtual storage object. ' + 'If not set, the default value is false.') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def get_pbm_connection(stub): + import pyVmomi + import ssl + # Make compatible with both Python2/3 + try: + from http import cookies + except ImportError: + import Cookie as cookies + + sessionCookie = stub.cookie.split('"')[1] + httpContext = VmomiSupport.GetHttpContext() + cookie = cookies.SimpleCookie() + cookie["vmware_soap_session"] = sessionCookie + httpContext["cookies"] = cookie + VmomiSupport.GetRequestContext()["vcSessionCookie"] = sessionCookie + hostname = stub.host.split(":")[0] + + context = None + if hasattr(ssl, "_create_unverified_context"): + context = ssl._create_unverified_context() + pbmStub = pyVmomi.SoapStubAdapter( + host=hostname, + version="pbm.version.version1", + path="/pbm/sdk", + poolSize=0, + sslContext=context) + pbmSi = pbm.ServiceInstance("ServiceInstance", pbmStub) + pbmContent = pbmSi.RetrieveContent() + + return pbmContent + + +def retrieve_storage_policy(pbmContent, policy): + """ + Retrieves the vmware object for the storage policy specified + """ + # Set PbmQueryProfile + pm = pbmContent.profileManager + + # Retrieving Storage Policies + profileIds = pm.PbmQueryProfile(resourceType=pbm.profile.ResourceType( + resourceType="STORAGE"), profileCategory="REQUIREMENT" + ) + if len(profileIds) > 0: + profiles = pm.PbmRetrieveContent(profileIds=profileIds) + else: + raise RuntimeError("No Storage Policies found.") + + # Searching for Storage Policy + profile = None + for p in profiles: + if p.name == policy: + profile = p + break + if not profile: + raise RuntimeError("Storage Policy specified not found.") + + return profile + + +def main(): + """ + Simple command-line program for creating a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Connect to SPBM Endpoint + pbmContent = get_pbm_connection(service_instance._stub) + + # Retrieving Storage Policy + if args.policy: + policy = retrieve_storage_policy(pbmContent, args.policy) + else: + policy = None + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Setting FCD Specifications + spec = vim.vslm.CreateSpec() + spec.name = args.name + spec.capacityInMB = args.capacityInGB * 1024 + if args.keepAfterDeleteVm: + spec.keepAfterDeleteVm = True + spec.backingSpec = vim.vslm.CreateSpec.DiskFileBackingSpec() + spec.backingSpec.provisioningType = "thin" + spec.backingSpec.datastore = datastore + if policy: + spec.profile = [vim.vm.DefinedProfileSpec( + profileId=policy.profileId.uniqueId)] + + # Create FCD + storage = content.vStorageObjectManager + task = storage.CreateDisk_Task(spec) + tasks.wait_for_tasks(service_instance, [task]) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/create_vdisk_from_snapshot.py b/samples/create_vdisk_from_snapshot.py new file mode 100755 index 00000000..4f23f433 --- /dev/null +++ b/samples/create_vdisk_from_snapshot.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for creating a first class disk (fcd) from a snapshot +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl, vim, pbm, VmomiSupport + + +def get_args(): + """ + Adds additional args for creating a fcd from a snapshot + + -d source_datastore + -v source_vdisk + -n snapshot + -D dest_datastore + -V dest_vdisk + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--source_datastore', + required=True, + action='store', + help='Datastore name where source disk is located') + + parser.add_argument('-v', '--source_vdisk', + required=True, + action='store', + help='First Class Disk name with specified snapshot') + + # because -s is reserved for 'service', we use -n for snapshot name + parser.add_argument('-n', '--snapshot', + required=True, + action='store', + help='Snapshot name to be cloned') + + parser.add_argument('-D', '--dest_datastore', + required=True, + action='store', + help='Datastore name where new disk is located') + + parser.add_argument('-V', '--dest_vdisk', + required=True, + action='store', + help='First Class Disk name to be created') + + # because -s is reserved for 'service' and -p is reserved for 'password' + parser.add_argument('-e', '--policy', + action='store', + help='Storage Policy name for new disk. If unset, ' + 'the default policy of the datastore specified ' + 'will apply.') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def get_pbm_connection(stub): + import pyVmomi + import ssl + # Make compatible with both Python2/3 + try: + from http import cookies + except ImportError: + import Cookie as cookies + + sessionCookie = stub.cookie.split('"')[1] + httpContext = VmomiSupport.GetHttpContext() + cookie = cookies.SimpleCookie() + cookie["vmware_soap_session"] = sessionCookie + httpContext["cookies"] = cookie + VmomiSupport.GetRequestContext()["vcSessionCookie"] = sessionCookie + hostname = stub.host.split(":")[0] + + context = None + if hasattr(ssl, "_create_unverified_context"): + context = ssl._create_unverified_context() + pbmStub = pyVmomi.SoapStubAdapter( + host=hostname, + version="pbm.version.version1", + path="/pbm/sdk", + poolSize=0, + sslContext=context) + pbmSi = pbm.ServiceInstance("ServiceInstance", pbmStub) + pbmContent = pbmSi.RetrieveContent() + + return pbmContent + + +def retrieve_storage_policy(pbmContent, policy): + """ + Retrieves the vmware object for the storage policy specified + """ + # Set PbmQueryProfile + pm = pbmContent.profileManager + + # Retrieving Storage Policies + profileIds = pm.PbmQueryProfile(resourceType=pbm.profile.ResourceType( + resourceType="STORAGE"), profileCategory="REQUIREMENT" + ) + if len(profileIds) > 0: + profiles = pm.PbmRetrieveContent(profileIds=profileIds) + else: + raise RuntimeError("No Storage Policies found.") + + # Searching for Storage Policy + profile = None + for p in profiles: + if p.name == policy: + profile = p + break + if not profile: + raise RuntimeError("Storage Policy specified not found.") + + return profile + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def retrieve_snapshot(content, datastore, vdisk, snapshot): + """ + Retrieves the vmware object for the snapshot specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve Snapshot + snap = None + snaps = storage.RetrieveSnapshotInfo(vdisk.config.id, datastore) + for s in snaps.snapshots: + if s.description == snapshot: + snap = s.id + break + if not snap: + raise RuntimeError("Snapshot not found.") + return snap + + +def main(): + """ + Simple command-line program for deleting a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Connect to SPBM Endpoint + pbmContent = get_pbm_connection(service_instance._stub) + + # Retrieving Storage Policy + if args.policy: + p = retrieve_storage_policy(pbmContent, args.policy) + policy = [vim.vm.DefinedProfileSpec( + profileId=p.profileId.uniqueId)] + else: + policy = None + + # Retrieve Source Datastore Object + source_datastore = get_obj( + content, [vim.Datastore], args.source_datastore) + + # Retrieve Source FCD Object + source_vdisk = retrieve_fcd( + content, source_datastore, args.source_vdisk) + + # Retrieve Snapshot Object + snapshot = retrieve_snapshot( + content, source_datastore, source_vdisk, args.snapshot) + + # Retrieve Destination Datastore Object + dest_datastore = get_obj(content, [vim.Datastore], args.dest_datastore) + + # Create FCD from Snapshot + storage = content.vStorageObjectManager + if policy: + task = storage.CreateDiskFromSnapshot_Task( + source_vdisk.config.id, + dest_datastore, + snapshot, + args.dest_vdisk, + policy) + else: + task = storage.CreateDiskFromSnapshot_Task( + source_vdisk.config.id, + dest_datastore, + snapshot, + args.dest_vdisk) + tasks.wait_for_tasks(service_instance, [task]) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/create_vdisk_snapshot.py b/samples/create_vdisk_snapshot.py new file mode 100755 index 00000000..b8997904 --- /dev/null +++ b/samples/create_vdisk_snapshot.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for creating a snapshot of a first class disk (fcd) +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for creating a snapshot of a fcd + + -d datastore + -v vdisk + -n snapshot + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-v', '--vdisk', + required=True, + action='store', + help='First Class Disk name to create snapshot for') + + # because -s is reserved for 'service', we use -n for snapshot name + parser.add_argument('-n', '--snapshot', + required=True, + action='store', + help='New snapshot name') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def main(): + """ + Simple command-line program for creating a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Retrieve FCD Object + vdisk = retrieve_fcd(content, datastore, args.vdisk) + + # Create FCD Snapshot + storage = content.vStorageObjectManager + task = storage.VStorageObjectCreateSnapshot_Task( + vdisk.config.id, datastore, args.snapshot) + tasks.wait_for_tasks(service_instance, [task]) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/delete_vdisk.py b/samples/delete_vdisk.py new file mode 100755 index 00000000..61dbefcf --- /dev/null +++ b/samples/delete_vdisk.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for deleting a first class disk (fcd) +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for deleting a fcd + + -d datastore + -v vdisk + -y yes + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-v', '--vdisk', + required=True, + action='store', + help='First Class Disk name to be deleted') + + parser.add_argument('-y', '--yes', + action='store_true', + help='Confirm disk deletion.') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def main(): + """ + Simple command-line program for deleting a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Retrieve FCD Object + vdisk = retrieve_fcd(content, datastore, args.vdisk) + + # Confirming FCD deletion + if not args.yes: + response = cli.prompt_y_n_question("Are you sure you want to " + "delete vdisk '" + args.vdisk + + "'?", + default='no') + if not response: + print("Exiting script. User chose not to delete HDD.") + exit() + + # Delete FCD + storage = content.vStorageObjectManager + task = storage.DeleteVStorageObject_Task(vdisk.config.id, datastore) + tasks.wait_for_tasks(service_instance, [task]) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/delete_vdisk_snapshot.py b/samples/delete_vdisk_snapshot.py new file mode 100755 index 00000000..ef115ebe --- /dev/null +++ b/samples/delete_vdisk_snapshot.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for deleting a snapshot of a first class disk (fcd) +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for deleting a snapshot of a fcd + + -d datastore + -v vdisk + -n snapshot + -y yes + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-v', '--vdisk', + required=False, + action='store', + help='First Class Disk name to delete snapshot for') + + # because -s is reserved for 'service', we use -n for snapshot name + parser.add_argument('-n', '--snapshot', + required=True, + action='store', + help='Snapshot name to be deleted') + + parser.add_argument('-y', '--yes', + action='store_true', + help='Confirm disk deletion.') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def retrieve_snapshot(content, datastore, vdisk, snapshot): + """ + Retrieves the vmware object for the snapshot specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve Snapshot + snap = None + snaps = storage.RetrieveSnapshotInfo(vdisk.config.id, datastore) + for s in snaps.snapshots: + if s.description == snapshot: + snap = s.id + break + if not snap: + raise RuntimeError("Snapshot not found.") + return snap + + +def main(): + """ + Simple command-line program for deleting a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Retrieve FCD Object + vdisk = retrieve_fcd(content, datastore, args.vdisk) + + # Retrieve Snapshot Object + snapshot = retrieve_snapshot(content, datastore, vdisk, args.snapshot) + + # Confirming Snapshot deletion + if not args.yes: + response = cli.prompt_y_n_question("Are you sure you want to " + "delete snapshot '" + + args.snapshot + "'?", + default='no') + if not response: + print("Exiting script. User chose not to delete snapshot.") + exit() + + # Delete FCD Snapshot + storage = content.vStorageObjectManager + task = storage.DeleteSnapshot_Task( + vdisk.config.id, datastore, snapshot) + tasks.wait_for_tasks(service_instance, [task]) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/detach_disk_from_vm.py b/samples/detach_disk_from_vm.py new file mode 100755 index 00000000..8daba4c4 --- /dev/null +++ b/samples/detach_disk_from_vm.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for detaching a disk from a VM without deleting the VMDK +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for detaching a disk from a vm + + -n vm_name + -i uuid + -d disknumber + -l language + """ + parser = cli.build_arg_parser() + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-n', '--vm_name', + action='store', + help='Virtual Machine name where disk is attached') + + group.add_argument('-i', '--uuid', + action='store', + help='Virtual Machine UUID where disk is attached') + + parser.add_argument('-d', '--disknumber', + required=True, + help='HDD number to detach.', + type=int) + + parser.add_argument('-l', '--language', + default='English', + help='Language your vcenter used.') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def get_hdd_prefix_label(language): + language_prefix_label_mapper = { + 'English': 'Hard disk ', + 'Chinese': u'硬盘 ' + } + return language_prefix_label_mapper.get(language) + + +def detach_disk_from_vm(vm, disk_number, language): + """ + Detach first class disk from vm + """ + hdd_prefix_label = get_hdd_prefix_label(language) + if not hdd_prefix_label: + raise RuntimeError('HDD prefix label could not be found') + + hdd_label = hdd_prefix_label + str(disk_number) + virtual_hdd_device = None + for dev in vm.config.hardware.device: + if isinstance(dev, vim.vm.device.VirtualDisk) \ + and dev.deviceInfo.label == hdd_label: + virtual_hdd_device = dev + if not virtual_hdd_device: + raise RuntimeError('Virtual {} could not ' + 'be found.'.format(virtual_hdd_device)) + + virtual_hdd_spec = vim.vm.device.VirtualDeviceSpec() + virtual_hdd_spec.operation = \ + vim.vm.device.VirtualDeviceSpec.Operation.remove + virtual_hdd_spec.device = virtual_hdd_device + + spec = vim.vm.ConfigSpec() + spec.deviceChange = [virtual_hdd_spec] + task = vm.ReconfigVM_Task(spec=spec) + return task + + +def main(): + """ + Simple command-line program for detaching a disk from a virtual machine. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve VM + vm = None + if args.uuid: + search_index = content.searchIndex + vm = search_index.FindByUuid(None, args.uuid, True) + elif args.vm_name: + vm = get_obj(content, [vim.VirtualMachine], args.vm_name) + + # Detaching Disk from VM + if vm: + task = detach_disk_from_vm(vm, args.disknumber, args.language) + tasks.wait_for_tasks(service_instance, [task]) + else: + raise RuntimeError("VM not found.") + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/list_vdisk_snapshots.py b/samples/list_vdisk_snapshots.py new file mode 100755 index 00000000..a7d775b2 --- /dev/null +++ b/samples/list_vdisk_snapshots.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Written by Chris Arceneaux +# GitHub: https://github.com/carceneaux +# Email: carceneaux@thinksis.com +# Website: http://arsano.ninja +# +# Note: Example code For testing purposes only +# +# This code has been released under the terms of the Apache-2.0 license +# http://opensource.org/licenses/Apache-2.0 + +""" +Python program for listing all snapshots of a first class disk (fcd) +""" + +import atexit + +from tools import cli, tasks +from pyVim import connect +from pyVmomi import vmodl +from pyVmomi import vim + + +def get_args(): + """ + Adds additional args for listing all snapshots of a fcd + + -d datastore + -v vdisk + """ + parser = cli.build_arg_parser() + + parser.add_argument('-d', '--datastore', + required=True, + action='store', + help='Datastore name where disk is located') + + parser.add_argument('-v', '--vdisk', + required=True, + action='store', + help='First Class Disk name to delete snapshot for') + + my_args = parser.parse_args() + return cli.prompt_for_password(my_args) + + +def get_obj(content, vimtype, name): + """ + Retrieves the vmware object for the name and type specified + """ + obj = None + container = content.viewManager.CreateContainerView( + content.rootFolder, vimtype, True) + for c in container.view: + if c.name == name: + obj = c + break + return obj + + +def retrieve_fcd(content, datastore, vdisk): + """ + Retrieves the vmware object for the first class disk specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve First Class Disks + disk = None + for d in storage.ListVStorageObject(datastore): + disk_info = storage.RetrieveVStorageObject(d, datastore) + if disk_info.config.name == vdisk: + disk = disk_info + break + if not disk: + raise RuntimeError("First Class Disk not found.") + return disk + + +def retrieve_snapshots(content, vdisk): + """ + Retrieves the vmware object for the snapshot specified + """ + # Set vStorageObjectManager + storage = content.vStorageObjectManager + + # Retrieve all Snapshots + snapshots = storage.RetrieveSnapshotInfo( + vdisk.config.id, vdisk.config.backing.datastore).snapshots + if len(snapshots) > 0: + # Print snapshot information + print("") + for s in snapshots: + print("Name: %s " % s.description) + print("ID: %s " % s.id.id) + print("Create Time: %s " % s.createTime) + print("") + else: + print("No snapshots found for this vdisk.") + + +def main(): + """ + Simple command-line program for deleting a snapshot of a first class disk. + """ + + args = get_args() + + try: + if args.disable_ssl_verification: + service_instance = connect.SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + else: + service_instance = connect.SmartConnect(host=args.host, + user=args.user, + pwd=args.password, + port=int(args.port)) + + atexit.register(connect.Disconnect, service_instance) + + content = service_instance.RetrieveContent() + + # Retrieve Datastore Object + datastore = get_obj(content, [vim.Datastore], args.datastore) + + # Retrieve FCD Object + vdisk = retrieve_fcd(content, datastore, args.vdisk) + + # Retrieve all Snapshots + retrieve_snapshots(content, vdisk) + + except vmodl.MethodFault as error: + print("Caught vmodl fault : " + error.msg) + return -1 + + return 0 + + +# Start program +if __name__ == "__main__": + main() diff --git a/samples/tools/cli.py b/samples/tools/cli.py index 0175cfdb..5cba5911 100644 --- a/samples/tools/cli.py +++ b/samples/tools/cli.py @@ -108,7 +108,11 @@ def prompt_y_n_question(question, default="no"): while True: print(question + prompt) - choice = raw_input().lower() + # Make compatible with both Python2/3 + try: + choice = input().lower() + except ImportError: + choice = raw_input().lower() if default is not None and choice == '': return valid[default] elif choice in valid: