Milestone 5 Automation continued - zacharylongo/Tech-Journals GitHub Wiki

Automation Code

Includes functions to:

  • View VM info
  • Create VM's from template
  • Delete a target VM
  • Power on / off a VM
  • Change a VM's network adapter

Reflection

  • This lab took an excruciating amount of time to complete due to my infamiliarity with Python

  • Many times I properly created a function but forgot to ask for input or display that a function complied correctly and did its expected task

  • I accidentally deleted my "save snapshot" function and forgot how I created it. It was functional.

  • Overall this lab was extremely beneficial to my understanding of python scripting and the effectiveness of my use of VScode.

Code (with annotations):

# Import Modules
import getpass  # Used to securely input Vcenter password
from pyVim.connect import SmartConnect
from pyVmomi import vim  # Imports the VMware vSphere API bindings
import ssl  # Imports SSL module

# Define a list of valid network names
valid_networks = ["Network1", "Network2", "Network3"]

# Function to connect to the Vcenter Server
def connect_to_vcenter(vcenter_host, username, password):
    try:
        s = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        s.verify_mode = ssl.CERT_NONE
        si = SmartConnect(host=vcenter_host, user=username, pwd=password, sslContext=s)
        return si
    except Exception as e:
        print(f"Error connecting to vCenter: {str(e)}")
        return None

# Function to retrieve names of all virtual machines in vCenter
def get_all_vm_names(si):
    vm_names = []
    if si is not None:
        content = si.RetrieveContent()
        view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

        for vm in view.view:
            vm_names.append(vm.name)

        view.Destroy()

    return vm_names

# Function to allow the user to select a virtual machine from the list
def select_vm_to_view_info(vm_names):
    print("Available VMs:")
    for i, vm_name in enumerate(vm_names, 1):
        print(f"{i}. {vm_name}")  # Display a numbered list of available VM's

    while True:
        try:
            choice = int(input("Select a VM (enter the number): "))
            if 1 <= choice <= len(vm_names):  # Check if the choice is within a valid range
                return vm_names[choice - 1]  # Subtract 1 here
            else:
                print("Invalid choice. Please select a valid number.")
        except ValueError:
            print("Invalid input. Please enter a number.")

# Function to retrieve information about a selected virtual machine by name
def get_vm_info_by_name(si, vm_name):
    vm_info = []
    if si is not None:
        content = si.RetrieveContent()
        view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

        for vm in view.view:
            if vm.name == vm_name:
                vm_info.append({
                    'Name': vm.name,
                    'Power State': vm.runtime.powerState,
                    'Number of CPUs': vm.config.hardware.numCPU,
                    'Memory (GB)': vm.config.hardware.memoryMB / 1024.0,
                    'IP Address': vm.summary.guest.ipAddress
                })

        view.Destroy()

    return vm_info

# Function to power on a virtual machine by name
def power_on_vm(si, vm_name):
    if si is not None:
        content = si.RetrieveContent()
        view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

        for vm in view.view:
            if vm.name == vm_name:
                if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOff:
                    task = vm.PowerOn()
                    print(f"Powering on VM: {vm_name}")
                    return task
                else:
                    print(f"VM {vm_name} is already powered on.")
                    return None

        view.Destroy()

# Function to power off a virtual machine by name
def power_off_vm(si, vm_name):
    if si is not None:
        content = si.RetrieveContent()
        view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

        for vm in view.view:
            if vm.name == vm_name:
                if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
                    task = vm.PowerOff()
                    print(f"Powering off VM: {vm_name}")
                    return task
                else:
                    print(f"VM {vm_name} is already powered off.")
                    return None

        view.Destroy()

def create_vm_from_template(si, template_name, vm_name, datastore, cluster, network):
    if si is not None:
        content = si.RetrieveContent()
        datacenter = content.rootFolder.childEntity[0]

        # List available templates
        available_templates = content.viewManager.CreateContainerView(datacenter, [vim.VirtualMachine], True).view
        available_templates = [template for template in available_templates if template.config.template]

        if not available_templates:
            print("No templates available")
            return

        print("Available Templates:")
        for i, template in enumerate(available_templates, 1):
            print(f"{i}. {template.name}")

        # Prompt the user to select a template
        while True:
            try:
                template_choice = int(input("Select a Template (enter the number): "))
                if 1 <= template_choice <= len(available_templates):
                    selected_template = available_templates[template_choice - 1]
                    break
                else:
                    print("Invalid choice. Please select a valid number.")
            except ValueError:
                print("Invalid input. Please enter a number.")


        # List available datastores
        available_datastores = content.viewManager.CreateContainerView(datacenter, [vim.Datastore], True).view
        print("Available Datastores:")
        for i, ds in enumerate(available_datastores, 1):
            print(f"{i}. {ds.name}")

        # Prompt the user to select a datastore
        while True:
            try:
                datastore_choice = int(input("Select a Datastore (enter the number): "))
                if 1 <= datastore_choice <= len(available_datastores):
                    selected_datastore = available_datastores[datastore_choice - 1]
                    break
                else:
                    print("Invalid choice. Please select a valid number.")
            except ValueError:
                print("Invalid input. Please enter a number.")

        # Prompt the user to enter the new VM name
        vm_name = input("Enter the name for the new VM: ")

        # Prompt the user to select a cluster
        cluster_name = input("Enter the cluster name: ")

        # Prompt the user to select a network
        network_name = input("Enter the network name: ")

        try:
            relospec = vim.vm.RelocateSpec()
            relospec.datastore = selected_datastore
            relospec.pool = selected_template.resourcePool

            clonespec = vim.vm.CloneSpec()
            clonespec.location = relospec
            clonespec.powerOn = False
            clonespec.template = False

            new_vm = selected_template.Clone(folder=datacenter.vmFolder, name=vm_name, spec=clonespec)
            print(f"Creating VM: {vm_name} from template: {selected_template.name}")
        except Exception as e:
            print(f"Error creating VM from template: {str(e)}")
    else:
        print("Could not connect to vCenter.")
# Function to delete a virtual machine
def delete_vm(si, vm_name):
    if si is not None:
        content = si.RetrieveContent()
        view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

        for vm in view.view:
            if vm.name == vm_name:
                try:
                    task = vm.Destroy()
                    print(f"Deleting VM: {vm_name}")
                    return task
                except Exception as e:
                    print(f"Error deleting VM: {str(e)}")
                    return None

        view.Destroy()
    else:
        print("Could not connect to vCenter.")

# Function to change a VM's network
def change_vm_network(si, vm_name, network):
    if network in valid_networks:
        if si is not None:
            content = si.RetrieveContent()
            view = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)

            for vm in view.view:
                if vm.name == vm_name:
                    network_spec = vim.vm.device.VirtualDeviceSpec()
                    network_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
                    network_spec.device = vim.vm.device.VirtualVmxnet3()
                    network_spec.device.deviceInfo = vim.Description()
                    network_spec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
                    network_spec.device.backing.useAutoDetect = False
                    network_spec.device.backing.network = get_network_by_name(content, network)
                    network_spec.device.wakeOnLanEnabled = True

                    edit_spec = vim.vm.ConfigSpec(deviceChange=[network_spec])
                    task = vm.ReconfigVM_Task(spec=edit_spec)
                    print(f"Changing network of VM {vm_name} to {network}")
                    return task
            view.Destroy()
        else:
            print("Could not connect to vCenter.")
    else:
        print("Invalid network name. Please enter a valid network name.")

# Function to get network by name
def get_network_by_name(content, network_name):
    for network in content.viewManager.CreateContainerView(content.rootFolder, [vim.Network], True).view:
        if network.name == network_name:
            return network
    return None

# Main function to execute code
def main():
    vcenter_host = "vcenter.zachary.longo.local"  # Updated hostname
    username = "zach-adm"
    password = getpass.getpass("Enter your vCenter password: ")

    si = connect_to_vcenter(vcenter_host, username, password)

    if si is not None:
        while True:
            print("\nActions:")
            print("1. View VM Information")
            print("2. Power On VM")
            print("3. Power Off VM")
            print("4. Create VM from Template")
            print("5. Delete VM")
            print("6. Change VM Network")
            print("7. Exit")

            choice = input("Select an action (1/2/3/4/5/6/7): ")

            if choice == '1':
                # Code to view VM information (existing code)
                vm_names = get_all_vm_names(si)
                if not vm_names:
                    print("No VMs found in the vCenter.")
                else:
                    selected_vm = select_vm_to_view_info(vm_names)
                    vm_info = get_vm_info_by_name(si, selected_vm)
                    if vm_info:
                        print("VM Information:")
                        print("VM Name: ", vm_info[0]['Name'])
                        print("Power State: ", vm_info[0]['Power State'])
                        print("Number of CPUs: ", vm_info[0]['Number of CPUs'])
                        print("Memory (GB): ", vm_info[0]['Memory (GB)'])
                        print("IP Address: ", vm_info[0]['IP Address'])
                    else:
                        print(f"No information found for VM: {selected_vm}")
            elif choice == '2':
                # Code to power on VM (existing code)
                vm_names = get_all_vm_names(si)
                if not vm_names:
                    print("No VMs found in the vCenter.")
                else:
                    selected_vm = select_vm_to_view_info(vm_names)
                    power_on_vm(si, selected_vm)
            elif choice == '3':
                # Code to power off VM (existing code)
                vm_names = get_all_vm_names(si)
                if not vm_names:
                    print("No VMs found in the vCenter.")
                else:
                    selected_vm = select_vm_to_view_info(vm_names)
                    power_off_vm(si, selected_vm)
            elif choice == '4':
                # Code to create VM from template
                template_name = input("Enter the template name: ")
                vm_name = input("Enter the name for the new VM: ")
                datastore = input("Enter the datastore name: ")
                cluster = input("Enter the cluster name: ")
                network = input("Enter the network name: ")
                create_vm_from_template(si, template_name, vm_name, datastore, cluster, network)
            elif choice == '5':
                # Code to delete VM
                vm_names = get_all_vm_names(si)
                if not vm_names:
                    print("No VMs found in the vCenter.")
                else:
                    selected_vm = select_vm_to_view_info(vm_names)
                    delete_vm(si, selected_vm)
            elif choice == '6':
                # Code to change VM network
                vm_names = get_all_vm_names(si)
                if not vm_names:
                    print("No VMs found in the vCenter.")
                else:
                    selected_vm = select_vm_to_view_info(vm_names)
                    network = input("Enter the new network name: ")
                    change_vm_network(si, selected_vm, network)
            elif choice == '7':
                break
            else:
                print("Invalid choice. Please select a valid option.")
    else:
        print("Could not connect to vCenter.")

if __name__ == "__main__":
    main()