天天看點

vmware自定義規範定制虛拟機(二)-pyvmomi

上篇博文 vmware自定義規範定制虛拟機(一)-vsphere client 介紹了vsphere client在圖形界面實作了虛拟機的定制,接下來我們繼續介紹下使用python pyvmomi子產品實作虛拟機定制。

環境準備

名稱 版本 備注
vCenter 5.5.0-218311 vCenter Server 5.5 Update 2b
Centos 7.5 192.168.3.253
pyvmomi 6.7.3
python 2.7.15

pyvmomi子產品

功能實作,我們使用了官方執行個體的clone_vm.py

實作

pyvmomi實作自定義規範和vsphere client不同,它的流程是這樣的:

1.從模闆克隆虛拟機,注意克隆完成後不要啟動;

2.克隆完成後,在關機狀态下實作自定義規範的定制;

3.自定義完成後,虛拟機是關閉的,需要通過指令啟動;

以上過程完成後,最終會實作和vsphere client一樣的效果。

1.實作主機名、IP、子網路遮罩、網管、DNS的自定義代碼

def ip_assign(vm, vm_ip, vm_name):
    """設定IP位址"""
    adaptermap = vim.vm.customization.AdapterMapping()
    adaptermap.adapter = vim.vm.customization.IPSettings()
    adaptermap.adapter.ip = vim.vm.customization.FixedIp()
    adaptermap.adapter.ip.ipAddress = vm_ip
    adaptermap.adapter.subnetMask = "255.255.255.0"
    adaptermap.adapter.gateway = "192.168.3.1"
    #adaptermap.adapter.dnsDomain = "localhost"
    """dns設定"""
    globalip = vim.vm.customization.GlobalIPSettings()
    globalip.dnsServerList = "114.114.114.114"
    """設定主機名"""
    ident = vim.vm.customization.LinuxPrep()
    #ident.domain = "localhost"
    ident.hostName = vim.vm.customization.FixedName()
    ident.hostName.name = vm_name
    customspec = vim.vm.customization.Specification()
    customspec.nicSettingMap = [adaptermap]
    customspec.globalIPSettings = globalip
    customspec.identity = ident
    print "Reconfiguring VM Networks . . ."
    task = vm.Customize(spec=customspec)
    wait_for_task(task)
           

如上總共分三部分,IP位址設定、dns設定、主機名設定,由于我們在模闆中對CPU、MEMORY、DISK等已經定義完畢,是以沒有此方面的定義。

2.虛拟機啟動

預設自定義完成後,虛拟機是關機狀态的,我們需要開機操作才能和其他流程整合。

#根據虛拟機名擷取obj
vm = get_obj(content, [vim.VirtualMachine], args.vm_name)
#執行開機操作
task = vm.PowerOn()
wait_for_task(task)
           

3.clone_vm_customize.py實作

clone_vm.py 是對虛拟機模闆的克隆,不具有自定義規範的功能,是以我們通過對其進行合并自定義規範的代碼、啟動虛拟機整合,實作自定義克隆模闆

#!/usr/bin/env python
#-*- coding: utf-8 -*-
"""
Written by Dann Bohn
Github: https://github.com/whereismyjetpack
Email: [email protected]

Clone a VM from template example
"""

from pyVmomi import vim
from pyVim.connect import SmartConnect, SmartConnectNoSSL, Disconnect
import atexit
import argparse
import getpass

from add_nic_to_vm import add_nic


def get_args():
    """ Get arguments from CLI """
    parser = argparse.ArgumentParser(
        description='Arguments for talking to vCenter')

    parser.add_argument('-s', '--host',
                        required=True,
                        action='store',
                        help='vSpehre service to connect to')

    parser.add_argument('-o', '--port',
                        type=int,
                        default=443,
                        action='store',
                        help='Port to connect on')

    parser.add_argument('-u', '--user',
                        required=True,
                        action='store',
                        help='Username to use')

    parser.add_argument('-p', '--password',
                        required=False,
                        action='store',
                        help='Password to use')

    parser.add_argument('-v', '--vm-name',
                        required=True,
                        action='store',
                        help='Name of the VM you wish to make')

    parser.add_argument('--no-ssl',
                        action='store_true',
                        help='Skip SSL verification')

    parser.add_argument('--template',
                        required=True,
                        action='store',
                        help='Name of the template/VM \
                            you are cloning from')

    parser.add_argument('--datacenter-name',
                        required=False,
                        action='store',
                        default=None,
                        help='Name of the Datacenter you\
                            wish to use. If omitted, the first\
                            datacenter will be used.')

    parser.add_argument('--vm-folder',
                        required=False,
                        action='store',
                        default=None,
                        help='Name of the VMFolder you wish\
                            the VM to be dumped in. If left blank\
                            The datacenter VM folder will be used')

    parser.add_argument('--datastore-name',
                        required=False,
                        action='store',
                        default=None,
                        help='Datastore you wish the VM to end up on\
                            If left blank, VM will be put on the same \
                            datastore as the template')

    parser.add_argument('--datastorecluster-name',
                        required=False,
                        action='store',
                        default=None,
                        help='Datastorecluster (DRS Storagepod) you wish the VM to end up on \
                            Will override the datastore-name parameter.')

    parser.add_argument('--cluster-name',
                        required=False,
                        action='store',
                        default=None,
                        help='Name of the cluster you wish the VM to\
                            end up on. If left blank the first cluster found\
                            will be used')

    parser.add_argument('--resource-pool',
                        required=False,
                        action='store',
                        default=None,
                        help='Resource Pool to use. If left blank the first\
                            resource pool found will be used')

    parser.add_argument('--power-on',
                        dest='power_on',
                        action='store_true',
                        help='power on the VM after creation')

    parser.add_argument('--opaque-network',
                        required=False,
                        help='Name of the opaque network to add to the VM')

    args = parser.parse_args()

    if not args.password:
        args.password = getpass.getpass(
            prompt='Enter password')

    return args

def wait_for_task(task):
    """ wait for a vCenter task to finish """
    task_done = False
    while not task_done:
        if task.info.state == 'success':
            return task.info.result

        if task.info.state == 'error':
            print("there was an error")
            task_done = True


def get_obj(content, vimtype, name):
    """
    Return an object by name, if name is None the
    first found object is returned
    """
    obj = None
    container = content.viewManager.CreateContainerView(
        content.rootFolder, vimtype, True)
    for c in container.view:
        if name:
            if c.name == name:
                obj = c
                break
        else:
            obj = c
            break

    return obj


def ip_assign(vm, vm_ip, vm_name):
    """自定義規範設定"""
    """設定IP位址"""
    adaptermap = vim.vm.customization.AdapterMapping()
    adaptermap.adapter = vim.vm.customization.IPSettings()
    adaptermap.adapter.ip = vim.vm.customization.FixedIp()
    adaptermap.adapter.ip.ipAddress = vm_ip
    adaptermap.adapter.subnetMask = "255.255.255.0"
    adaptermap.adapter.gateway = "192.168.3.1"
    #adaptermap.adapter.dnsDomain = "localhost"
    """dns設定"""
    globalip = vim.vm.customization.GlobalIPSettings()
    globalip.dnsServerList = "114.114.114.114"
    """設定主機名"""
    ident = vim.vm.customization.LinuxPrep()
    #ident.domain = "localhost"
    ident.hostName = vim.vm.customization.FixedName()
    ident.hostName.name = vm_name
    customspec = vim.vm.customization.Specification()
    customspec.nicSettingMap = [adaptermap]
    customspec.globalIPSettings = globalip
    customspec.identity = ident
    print "Reconfiguring VM Networks . . ."
    #task = get_obj([vim.VirtualMachine],vm).Customize(spec=customspec)
    task = vm.Customize(spec=customspec)
    wait_for_task(task)

def clone_vm(
        content, template, vm_name, si,
        datacenter_name, vm_folder, datastore_name,
        cluster_name, resource_pool, power_on, datastorecluster_name):
    """
    Clone a VM from a template/VM, datacenter_name, vm_folder, datastore_name
    cluster_name, resource_pool, and power_on are all optional.
    """

    # if none git the first one
    datacenter = get_obj(content, [vim.Datacenter], datacenter_name)

    if vm_folder:
        destfolder = get_obj(content, [vim.Folder], vm_folder)
    else:
        destfolder = datacenter.vmFolder

    if datastore_name:
        datastore = get_obj(content, [vim.Datastore], datastore_name)
    else:
        datastore = get_obj(
            content, [vim.Datastore], template.datastore[0].info.name)

    # if None, get the first one
    cluster = get_obj(content, [vim.ClusterComputeResource], cluster_name)

    if resource_pool:
        resource_pool = get_obj(content, [vim.ResourcePool], resource_pool)
    else:
        resource_pool = cluster.resourcePool

    vmconf = vim.vm.ConfigSpec()

    if datastorecluster_name:
        podsel = vim.storageDrs.PodSelectionSpec()
        pod = get_obj(content, [vim.StoragePod], datastorecluster_name)
        podsel.storagePod = pod

        storagespec = vim.storageDrs.StoragePlacementSpec()
        storagespec.podSelectionSpec = podsel
        storagespec.type = 'create'
        storagespec.folder = destfolder
        storagespec.resourcePool = resource_pool
        storagespec.configSpec = vmconf

        try:
            rec = content.storageResourceManager.RecommendDatastores(
                storageSpec=storagespec)
            rec_action = rec.recommendations[0].action[0]
            real_datastore_name = rec_action.destination.name
        except:
            real_datastore_name = template.datastore[0].info.name

        datastore = get_obj(content, [vim.Datastore], real_datastore_name)

    # set relospec
    relospec = vim.vm.RelocateSpec()
    relospec.datastore = datastore
    relospec.pool = resource_pool

    clonespec = vim.vm.CloneSpec()
    clonespec.location = relospec
    clonespec.powerOn = power_on

    print("cloning VM...")
    task = template.Clone(folder=destfolder, name=vm_name, spec=clonespec)
    wait_for_task(task)


def main():
    """
    Let this thing fly
    """
    args = get_args()

    # connect this thing
    si = None
    if args.no_ssl:
        si = SmartConnectNoSSL(
            host=args.host,
            user=args.user,
            pwd=args.password,
            port=args.port)
    else:
        si = SmartConnect(
            host=args.host,
            user=args.user,
            pwd=args.password,
            port=args.port)
    # disconnect this thing
    atexit.register(Disconnect, si)

    content = si.RetrieveContent()
    template = None

    template = get_obj(content, [vim.VirtualMachine], args.template)

    if template:
        #克隆模闆
        clone_vm(
            content, template, args.vm_name, si,
            args.datacenter_name, args.vm_folder,
            args.datastore_name, args.cluster_name,
            args.resource_pool, args.power_on, args.datastorecluster_name)
        vm = get_obj(content, [vim.VirtualMachine], args.vm_name)
        if args.opaque_network:
            add_nic(si, vm, args.opaque_network)
        
        #自定義規範定制虛拟機     
        ip_assign(vm, "192.168.3.254", args.vm_name)
    else:
        print("template not found")
    
    #啟動虛拟機
    vm = get_obj(content, [vim.VirtualMachine], args.vm_name)
    task = vm.PowerOn()
    wait_for_task(task)

# start this thing
if __name__ == "__main__":
    main()

           

4.執行指令

python clone_vm_customize.py -s 192.168.3.xxx -u [email protected].local -p xxxxxxx -v we123 --template template_centos7 --datacenter-name unicom-idc --vm-folder test --datastore-name vm.datastore1 --cluster-name idc  --no-ssl
           

執行完成後,虛拟機的ip為192.168.3.254,主機名we123,DNS 114.114.114.114,是根據我們的定義的虛拟機。

繼續閱讀