在 VMware 環境中,管理大量虛擬機器及其相關資源時,手動組態 Terraform 檔案顯得繁瑣且容易出錯。因此,自動化匯入現有虛擬機器成為提升效率的關鍵。本文將介紹如何利用 Python 指令碼與 vCenter MOB 互動,自動生成 Terraform 組態檔案,簡化匯入流程。透過 Python 指令碼,我們可以從 vCenter 取得虛擬機器的詳細資訊,例如網路設定、資源池、儲存區等,並將這些資訊轉換成 Terraform 可讀的組態檔案。如此一來,便可避免手動組態的繁瑣步驟,並確保組態檔案的準確性。此外,自動化匯入指令碼還能提高靈活性,方便我們根據需求調整匯入流程,例如批次匯入虛擬機器或根據特定條件篩選匯入物件。
Terraform 在 VMware 環境中的資源管理
在使用 Terraform 管理 VMware 環境中的資源時,資源區段(Resource Section)是最關鍵的部分。它定義了我們需要管理的資源,並包含若干必須和選擇性的引數。例如,若要管理一個虛擬機器(VM),我們需要在資原始碼塊中定義像是 VM 名稱、儲存區詳細資料、CPU、記憶體詳細資料、網路和儲存詳細資料等基本引數。
以下是一個 JSON 格式的範例程式碼,供參考:
"resource": {
"vsphere_virtual_machine": {
"VMresource": {
"network_interface": {
"adapter_type": "vmxnet3",
"network_id": "${data.vsphere_network.network0.id}"
},
"name": "UbantuTest",
"resource_pool_id": "${data.vsphere_resource_pool.pool.id}",
"datastore_id": "${data.vsphere_datastore.datastore.id}",
"boot_retry_enabled": false,
"enable_disk_uuid": false,
"enable_logging": false,
"num_cores_per_socket": 1,
"num_cpus": 3,
"guest_id": "ubuntu64Guest",
"memory": 12288,
"cpu_hot_add_enabled": true,
"memory_hot_add_enabled": true,
"firmware": "bios",
"scsi_type": "${data.vsphere_virtual_machine.template.scsi_type}",
"lifecycle": {
"ignore_changes": [
"custom_attributes",
"tags"
]
},
"disk": {
"label": "disk0",
"size": 16,
"unit_number": 0,
"thin_provisioned": false,
"path": "[Datastore name] UbantuTest/UbantuTest.vmdk",
"keep_on_remove": true
}
}
}
}
構建組態檔案
這個範例展示了一個基本的組態檔案,這些組態檔案可以被擴充套件以滿足不同的需求。這裡的範例主要用於匯入 VMware 的虛擬機器。當然,除了資源區段外,組態檔案還可能包含輸入變數、輸出變數、本地變數等。但是在這裡,我們的重點是這些組態檔案如何幫助自動化匯入過程。
使用 Python 指令碼生成組態檔案
在實際操作中,我們可以使用一個 Python 指令碼(稱為匯入指令碼)來從 VMware vCenter 中取得所需引數,並生成這些組態檔案。這樣可以大大簡化組態檔案的編寫過程。
使用 Terraform 匯入現有資源
Terraform 提供了一個強大的功能來匯入現有的基礎設施,讓我們可以將不由 Terraform 管理的資源納入管理範圍。以下是匯入過程中的幾個關鍵步驟:
- 準備組態檔案:確保組態檔案中包含所有必要的引數。
- 執行匯入命令:使用
terraform import命令來匯入現有資源。
以下是一個匯入 VMware 虛擬機器的範例命令:
terraform import vsphere_virtual_machine.VMresource /<Cluster>/vm/UbantuTest
如果組態檔案正確填寫且包含所有必要引數,則會成功匯入。
內容解密:
- 介面卡型別:指定虛擬機器網路介面卡(NIC)的型別,這裡選擇
vmxnet3是因為它在效能上更優越。 - 網路 ID:指向已經存在於 vSphere 中的網路。
- VM 名稱:虛擬機器的名稱。
- 資源池 ID:虛擬機器所屬的資源池。
- 儲存區 ID:虛擬機器使用的儲存區。
- 啟動重試:設為
false表示不啟用啟動重試。 - 磁碟 UUID:設為
false表示不啟用磁碟 UUID。 - 記錄啟用:設為
false表示不啟用記錄功能。 - CPU 組態:設定每個插槽的核心數和總 CPU 數量。
- 記憶體大小:設定虛擬機器的記憶體大小為 12GB。
- 熱插拔功能:允許 CPU 和記憶體在執行時進行調整。
- 韌體型別:選擇 BIOS 作為韌體型別。
- SCSI 控制器型別:根據範本設定。
- 忽略變更:設定忽略自定義屬性和標籤的變更。
驗證匯入結果
成功匯入後,Terraform 會生成一個狀態檔案(state file),這個檔案記錄了 Terraform 對該資源的理解狀態。我們需要透過 terraform plan 命令來驗證匯入結果。如果 terraform plan 沒有建議任何修改,則表示匯入成功。
自動化 VMware 環境中虛擬機器匯入
在這個實作練習中,玄貓將展示如何利用反向工程的概念,自動化地從 VMware 環境中匯入範例虛擬機器。這個匯入指令碼會從管理物件瀏覽器(MOB)取得詳細資料,並建立一個組態檔案,讓虛擬機器能夠成功匯入。最新的匯入指令碼可以在玄貓維護的 GitHub 儲存函式庫中找到,連結如下:GitHub 儲存函式庫。
接下來,玄貓將複製並解說這段範例程式碼,展示如何使用 Python 語言撰寫一個典型的匯入指令碼,與 MOB 互動並自動生成組態檔案。
檔案開頭設定
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 7 17:42:16 2022
@author: Sbhatia3
"""
import json
import requests
import sys
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from pyVim import connect
import ssl
from pyVmomi import vim
import re
import collections
內容解密:
這段程式碼首先定義了檔案編碼格式和作者資訊。接著匯入了所需的 Python 模組,包括用於處理 JSON 資料的 json、進行 HTTP 請求的 requests、處理不安全請求警告的 InsecureRequestWarning、用於連線 VMware MOB 的 pyVim 和 pyVmomi、以及用於正規表示式操作的 re 和用於有序字典的 collections。
應用程式設定及函式定義
# 定義一個類別來結構化地收集組態檔案引數
class OrderedConfig(collections.OrderedDict):
pass
app_settings = {
'api_pass': "XXXX",
'api_user': "administrator@vsphere.local",
'api_url': "https://<vCenter FQDN>/rest/",
'vcenter_ip': "xx.xx.xx.xx",
'VM_name': "UbantuTest", # 欲查詢詳細資料的虛擬機器名稱(區分大小寫)
'vsphere_datacenter': "ECM"
}
# 與 vCenter 驗證以取得 VM ID
def auth_vcenter(username, password):
resp = requests.post(
'{}/com/vmware/cis/session'.format(app_settings['api_url']),
auth=(app_settings['api_user'], app_settings['api_pass']),
verify=False
)
if resp.status_code != 200:
print('錯誤!API 傳回狀態碼:{}'.format(resp.status_code))
return
return resp.json()['value']
def get_api_data(req_url):
sid = auth_vcenter(app_settings['api_user'], app_settings['api_pass'])
resp = requests.get(req_url, verify=False, headers={'vmware-api-session-id': sid})
if resp.status_code != 200:
print('錯誤!API 傳回狀態碼:{}'.format(resp.status_code))
return
return resp
# 取得虛擬機器詳細資料,包括 VM ID,以便瀏覽 MOB
def get_vm(vm_name):
resp = get_api_data('{}/vcenter/vm?filter.names={}'.format(app_settings['api_url'], vm_name))
j = resp.json()
return j
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
vmdetails = get_vm(app_settings['VM_name'])
vmid = vmdetails['value'][0]['vm']
s = ssl._create_unverified_context()
service_instance = connect.SmartConnect(
host=app_settings['vcenter_ip'], user=app_settings['api_user'],
pwd=app_settings['api_pass'], sslContext=s
)
content = service_instance.RetrieveContent()
container = content.rootFolder # 開始點來檢視虛擬機器環境
viewType = [vim.VirtualMachine] # 欲查詢的物件型別
recursive = True # 是否遞迴查詢虛擬機器環境
containerView = content.viewManager.CreateContainerView(container, viewType, recursive)
children = containerView.view
for child in children:
if str(vmid) in str(child):
vm_summary = child.summary # 欲匯入之虛擬機器摘要
vm_config = child.config # 虛擬機器完整組態資料,層級及子專案值載入至變數中
vm_resourcepool = child.resourcePool # 資源池詳細資料
vm_network = child.network # 虛擬機器網路詳細資料
vm_datastore = child.datastore
vm_parent = child.parent
# 組態檔案結構及填充相應值,從 MOB 拿到資料
data = OrderedConfig()
data["provider"] = OrderedConfig()
data["provider"]["vsphere"] = OrderedConfig()
data["provider"]["vsphere"]["user"] = "sampleuser"
data["provider"]["vsphere"]["password"] = "samplepassword"
data["provider"]["vsphere"]["allow_unverified_ssl"] = "true"
resourcepool_string = str(vm_resourcepool.owner.name) + '/' + str(vm_resourcepool.name)
data["data"] = OrderedConfig()
data["data"]["vsphere_datacenter"] = OrderedConfig()
data["data"]["vsphere_datacenter"]["dc"] = OrderedConfig()
data["data"]["vsphere_datacenter"]["dc"]["name"] = app_settings['vsphere_datacenter']
data["data"]["vsphere_resource_pool"] = OrderedConfig()
data["data"]["vsphere_resource_pool"]["pool"] = OrderedConfig()
data["data"]["vsphere_resource_pool"]["pool"]["name"] = resourcepool_string
data["data"]["vsphere_resource_pool"]["pool"]["datacenter_id"] = "${data.vsphere_datacenter.dc.id}"
datastore_string = str(vm_datastore[0].name)
data["data"]["vsphere_datastore"] = OrderedConfig()
data["data"]["vsphere_datastore"]["datastore"] = OrderedConfig()
data["data"]["vsphere_datastore"]["datastore"]["name"] = datastore_string
data["data"]["vsphere_datastore"]["datastore"]["datacenter_id"] = "${data.vsphere_datacenter.dc.id}"
datastore_string = str(vm_datastore[0].name)
data["data"]["vsphere_virtual_machine"] = OrderedConfig()
data["data"]["vsphere_virtual_machine"]["template"] = OrderedConfig()
data["data"]["vsphere_virtual_machine"]["template"]["name"] = str(vm_config.name)
data["data"]["vsphere_virtual_machine"]["template"]["datacenter_id"] = "${data.vsphere_datacenter.dc.id}"
network_adapter = []
for item_netadapter in vm_config.hardware.device:
if "Network adapter" in str(item_netadapter.deviceInfo.label):
vm_networkadapter = item_netadapter
if "E1000e" in str(type(vm_networkadapter)):
network_adapter.append("e1000e")
if "Vmxnet3" in str(type(vm_networkadapter)):
network_adapter.append("vmxnet3")
內容解密:
這段程式碼定義了一個 OrderedConfig 類別來結構化地收集組態檔案引數。接著設定了應用程式引數,如 API 帳密、URL、vCenter IP、虛擬機器名稱等。函式 auth_vcenter 用來與 vCenter 驗證以取得 VM ID;get_api_data 用來從 API 取得資料;get_vm 用來取得虛擬機器詳細資料。
接著透過連線到 vCenter,並使用 CreateContainerView 功能查詢特定虛擬機器的詳細資訊。這些資訊包括虛擬機器摘要、組態資料、資源池詳細資料、網路詳細資料和儲存函式庫詳細資料。最後將這些資訊填充到有序字典中,準備好生成組態檔案。
網路介面卡及其他組態
for index, nic in enumerate(vm_network):
由於這段程式碼過長且已經超出了指定範圍內容量限制,玄貓將在後續篇章中繼續解說與驗證完整性。
