Hi there, I've a very strange that I can't explain concerning an atomated ESX host installation. So my installation workflow is as follow: I insert a custom ISO file on CD-drive with a custom kic...
See more...
Hi there, I've a very strange that I can't explain concerning an atomated ESX host installation. So my installation workflow is as follow: I insert a custom ISO file on CD-drive with a custom kickstart This kickstart will setup a temporary fixed IP and a temporary DNS name (no DHCP available) to allow downloads The kickstart will configure several network component and download/run 2 scripts for further configuration Script one configure the right DNS name and IP, according to a CSV file with checks on MAC addresses Script two will join the vCenter (Thanks @lamw !) The problem : the first time installation is started, I see on vCenter side that the join tries to contact the temporary host name/IP which is not valid anymore and this will of course fail. If I restart the installation from scratch, the installation will use the correct DNS name/IP and the join will success. It is the same behavior on nested hosts or on physical servers. I have to add that when I try in my nested home lab, I reset the VM with an empty hard disk and it stills works the 2nd and the next tries but not the 1st!!! I just can't understand because if the "logic" was wrong, it should fail every single time but it is not the case. Thanks in advance for you help Kickstart: ##### Stage 01 - Pre installation:
### Accept the VMware End User License Agreement
vmaccepteula
### Set the root password for the DCUI and Tech Support Mode
rootpw mypass
### The install media (priority: local / remote / USB)
install --firstdisk=local --overwritevmfs --ignoreprereqwarnings --ignoreprereqerrors --forceunsupportedinstall --novmfsondisk
### Set the keyboard layout
keyboard "Swiss German"
### Set the network to DHCP on the first network adapter
## network --bootproto=dhcp --device=vmnic0
### Set the network to static IP on the first network adapter
network --bootproto=static --ip=X.X.X.X --netmask=255.255.255.0 --gateway=X.X.X.X --hostname=my.temp.fqdn --nameserver=X.X.X.X,X.X.X.X --device=vmnic2 --addvmportgroup=1
### Reboot ESXi Host
reboot
##### Stage 02 - First boot:
### Open busybox and launch commands
%firstboot --interpreter=busybox
### Suppress ESXi Shell warning
esxcli system settings advanced set -o /UserVars/SuppressShellWarning -i 1
### Set Search Domain
esxcli network ip dns search add --domain=fqdn.suffix
### Add second NIC & configure policies on
esxcli network vswitch standard uplink add --uplink-name=vmnic3 --vswitch-name=vSwitch0
esxcli network vswitch standard policy failover set --standby-uplinks=vmnic2,vmnic3 --vswitch-name=vSwitch0
esxcli network vswitch standard portgroup policy failover set -p "Management Network" -u
esxcli network vswitch standard portgroup policy failover set --active-uplinks=vmnic2 -p "Management Network" -u
esxcli network vswitch standard portgroup policy failover set --standby-uplinks=vmnic3 -p "Management Network" -u
## Add and configure vMotion vmk
esxcli network vswitch standard portgroup add -v vSwitch0 -p "vMotion Network"
esxcli network ip interface add --interface-name vmk1 --mtu 9000 -p "vMotion Network"
esxcli network vswitch standard portgroup policy failover set --active-uplinks=vmnic3 -p "vMotion Network" -u
esxcli network vswitch standard portgroup policy failover set --standby-uplinks=vmnic2 -p "vMotion Network" -u
esxcli network vswitch standard portgroup set -p "vMotion Network" --vlan-id XXXX
## Configure MTU & CDP
esxcli network vswitch standard set --mtu 9000 --cdp-status listen --vswitch-name vSwitch0
esxcli network ip interface set --interface-name vmk0 --mtu 9000
## Configure VMkernel traffic type
esxcli network ip interface tag add -i vmk0 -t faultToleranceLogging
esxcli network ip interface tag add -i vmk0 -t vSphereBackupNFC
esxcli network ip interface tag add -i vmk1 -t VMotion
esxcli network ip interface tag add -i vmk1 -t vSphereReplication
esxcli network ip interface tag add -i vmk1 -t vSphereProvisioning
## Cleanup unnecessary portgroup
esxcli network vswitch standard portgroup remove --portgroup-name="VM Network" --vswitch-name=vSwitch0
### Disable IPv6 support (reboot is required)
esxcli network ip set --ipv6-enabled=false
### Add NTP Server addresses
echo "server ntp.server.fqdn" >> /scratch/ntpconfig.txt;
echo "tos maxdist 30" >> /scratch/ntpconfig.txt;
esxcli system ntp set -f /scratch/ntpconfig.txt
esxcli system ntp set -e 1
### Disable CEIP
#esxcli system settings advanced set -o /UserVars/HostClientCEIPOptIn -i 2
### Enable maintaince mode
esxcli system maintenanceMode set -e true
### Download Host Config CSV, host configuration script, and execute the host configuration script
esxcli network firewall ruleset set -e true -r httpClient
wget --no-check-certificate -O ListOfProdHosts.csv http://X.X.X.X/Deploy/ListOfProdHosts.csv
wget --no-check-certificate -O ConfigureProdHostNetwork.py http://X.X.X.X/Deploy/ConfigureProdHostNetwork.py
chmod u+x ConfigureProdHostNetwork.py
/bin/python ConfigureProdHostNetwork.py
## register with vcenter
wget --no-check-certificate -O vCenterJoinProd.py http://X.X.X.X/Deploy/vCenterJoinProd.py
chmod u+x vCenterJoinProd.py
/bin/python vCenterJoinProd.py
### Reboot
esxcli system shutdown reboot -d 15 -r "Rebooting after ESXi 8.0 host configuration" ConfigureProdHostNetwork.py import os, csv, subprocess, time
CSVPATH = '/ListOfProdHosts.csv'
#Gets all mac addresses of interfaces
MAC=subprocess.check_output("esxcli network ip interface list |grep MAC | cut -d ' ' -f 6",shell=True)
MACADDR = MAC.split()
print("MAC Addresses:")
print(MACADDR)
#Open the CSV file
with open(CSVPATH, 'rt') as csvFile:
csvReader = csv.reader(csvFile)
#Process the CSV file, row by row
for csvRow in csvReader:
#Check to see if the Mac Address of vmnic2 (IE: MACADDR[0]) matches the row in the CSV we are looking at
if ((MACADDR[0]).decode('utf-8')) == csvRow[1]:
#print("esxcli system hostname set --fqdn=" + csvRow[0])
#print("esxcli network ip interface ipv4 set --interface-name=vmk0 --ipv4=" + csvRow[2] + " --netmask=" + csvRow[3] + " --type=static")
#Set the hostname to the value in the CSV
os.system("esxcli system hostname set --host=" + csvRow[6])
os.system("esxcli system hostname set --fqdn=" + csvRow[0])
#Set the IP Address and Netmask of vmk0
os.system("esxcli network ip interface ipv4 set --interface-name=vmk0 --ipv4=" + csvRow[2] + " --netmask=" + csvRow[3] + " --type=static")
#Add the default gateway
# os.system("esxcfg-route " + csvRow[4])
#Add the desired VLAN for the Management Network on the vSwitch that gets created by default (vSwitch0)
# os.system("esxcfg-vswitch -p 'Management Network' -v " + csvRow[5] + " vSwitch0")
#Set the IP Address and Netmask of vmk0
os.system("esxcli network ip interface ipv4 set --interface-name=vmk1 --ipv4=" + csvRow[7] + " --netmask=" + csvRow[8] + " --gateway=" + csvRow[9] + " --type=static")
#Sleep to let ESX server time
time.sleep(60) vCenterJoinProd.py import sys,re,os,urllib,base64,syslog,socket,time
import urllib.request as request
import ssl
# used for unverified SSL/TLS certs. Insecure, not good for public.
ssl._create_default_https_context = ssl._create_unverified_context
## Variables that need to be filled out for different environments ##
# URL of vcenter, just the IP address
vcenter = "vcenter.server.fqdn"
# Data center
#cluster = "<datacenter>/host/<cluster>"
cluster = "My/Cluster/Name"
# vCenter credentials
user = "vcenterjoin"
password = "mypass"
# host ESXi credentials
host_username = "root"
host_password = "esxpass"
url = "https://" + vcenter + "/mob/?moid=SearchIndex&method=findByInventoryPath"
passman = request.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None,url, user, password)
authhandler = request.HTTPBasicAuthHandler(passman)
opener = request.build_opener(authhandler)
request.install_opener(opener)
#cont = ssl._create_unverified_context()
#ssl._create_default_https_context = ssl._create_unverified_context()
req = request.Request(url)
#cont = ssl._create_unverified_context()
#page = request.urlopen(req, context=context)
page = request.urlopen(req)
page_content = page.read().decode('utf-8')
#print(page_content)
reg = re.compile('name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"')
nonce = reg.search(page_content).group(1)
headers = page.info()
cookie = headers.get("Set-Cookie")
params = {'vmware-session-nonce':nonce,'inventoryPath':cluster}
e_params = urllib.parse.urlencode(params)
#print(e_params)
bin_data = e_params.encode('utf8')
req = request.Request(url, bin_data, headers={"Cookie":cookie})
page = request.urlopen(req)
page_content = page.read().decode('utf-8')
#print(page_content)
clusterMoRef = re.search('domain-c[0-9]*',page_content)
if clusterMoRef:
print("Found cluster: " + cluster)
else:
opener.close()
sys.exit(1)
# cert stuff
cmd = "openssl x509 -sha1 -in /etc/vmware/ssl/rui.crt -noout -fingerprint"
tmp = os.popen(cmd)
tmp_sha1 = tmp.readline()
tmp.close()
s1 = re.split('=',tmp_sha1)
s2 = s1[1]
s3 = re.split('\n', s2)
sha1 = s3[0]
if sha1:
print("Hash: ", sha1)
else:
opener.close()
sys.exit(1)
xml = '<spec xsi:type="HostConnectSpec"><hostName>%hostname</hostName><sslThumbprint>%sha</sslThumbprint><userName>%user</userName><password>%pass</password><force>1</force></spec>'
# Code to extract IP Address to perform DNS lookup to add FQDN to vCenter
hostip = socket.gethostbyname(socket.gethostname())
if hostip:
print("Successfully extracted IP Address - %s" % hostip.strip())
else:
opener.close()
print("Failed to extract IP Address!")
sys.exit(1)
try:
host = socket.getnameinfo((hostip, 0), 0)[0]
print("Successfully performed DNS lookup - %s" % host)
except IOError:
print("Failed to perform DNS lookup for %s, host will be added to vCenter using IP Address" % hostipt.strip())
host = hostip
# could add logic to do DNS lookup, but no dns in our environment.
xml = xml.replace("%hostname",host)
xml = xml.replace("%sha",sha1)
xml = xml.replace("%user",host_username)
xml = xml.replace("%pass",host_password)
print(xml)
# now join to vcenter cluster
try:
url = "https://" + vcenter + "/mob/?moid=" + clusterMoRef.group() + "&method=addHost"
params = {'vmware-session-nonce':nonce,'spec':xml,'asConnected':'1','resourcePool':'','license':''}
e_params = urllib.parse.urlencode(params)
bin_data = e_params.encode('utf8')
req = request.Request(url, bin_data, headers={"Cookie":cookie})
page = request.urlopen(req).read()
except IOError as e:
opener.close()
print("Couldn't join cluster", e)
sys.exit(1)
else:
print("Joined vcenter cluster!")
url = "https://" + vcenter + "/mob/?moid=SessionManager&method=logout"
params = {'vmware-session-nonce':nonce}
e_params = urllib.parse.urlencode(params)
bin_data = e_params.encode('utf8')
req = request.Request(url, bin_data, headers={"Cookie":cookie})
page = request.urlopen(req).read()
sys.exit(0)
#Sleep to let ESX server time
time.sleep(60)