github.com/vmware/govmomi@v0.37.2/scripts/vcsa/create-esxi-vm.sh (about)

     1  #!/bin/bash -e
     2  
     3  # Copyright 2017-2018 VMware, Inc. All Rights Reserved.
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #    http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  #
    17  # Create a VM and boot stateless ESXi via cdrom/iso
    18  
    19  set -o pipefail
    20  
    21  usage() {
    22    cat <<'EOF'
    23  Usage: $0 [-d DISK_GB] [-m MEM_GB] [-i ESX_ISO] [-s] ESX_URL VM_NAME
    24  
    25  GOVC_* environment variables also apply, see https://github.com/vmware/govmomi/tree/main/govc#usage
    26  If GOVC_USERNAME is set, it is used to create an account on the ESX vm.  Default is to use the existing root account.
    27  If GOVC_PASSWORD is set, the account password will be set to this value.  Default is to use the given ESX_URL password.
    28  EOF
    29  }
    30  
    31  disk=48
    32  mem=16
    33  # 6.7 U3 https://docs.vmware.com/en/VMware-vSphere/6.7/rn/vsphere-esxi-vcenter-server-67-release-notes.html
    34  iso=VMware-VMvisor-6.7.0-14320388.x86_64.iso
    35  
    36  while getopts d:hi:m:s flag
    37  do
    38    case $flag in
    39      d)
    40        disk=$OPTARG
    41        ;;
    42      h)
    43        usage
    44        exit
    45        ;;
    46      i)
    47        iso=$OPTARG
    48        ;;
    49      m)
    50        mem=$OPTARG
    51        ;;
    52      s)
    53        standalone=true
    54        ;;
    55      *)
    56        usage 1>&2
    57        exit 1
    58        ;;
    59    esac
    60  done
    61  
    62  shift $((OPTIND-1))
    63  
    64  if [ $# -ne 2 ] ; then
    65    usage
    66    exit 1
    67  fi
    68  
    69  if [[ "$iso" == *"-Installer-"* ]] ; then
    70    echo "Invalid iso name (need stateless, not installer): $iso" 1>&2
    71    exit 1
    72  fi
    73  
    74  export GOVC_INSECURE=1
    75  export GOVC_URL=$1
    76  network=${GOVC_NETWORK:-"VM Network"}
    77  username=$GOVC_USERNAME
    78  password=$GOVC_PASSWORD
    79  unset GOVC_USERNAME GOVC_PASSWORD
    80  
    81  guest=${GUEST:-"vmkernel65Guest"}
    82  
    83  if [ -z "$password" ] ; then
    84    # extract password from $GOVC_URL
    85    password=$(govc env GOVC_PASSWORD)
    86  fi
    87  
    88  shift
    89  
    90  name=$1
    91  shift
    92  
    93  echo -n "Checking govc version..."
    94  govc version -require 0.15.0
    95  
    96  if [ "$(govc env -x GOVC_URL_HOST)" = "." ] ; then
    97    if [ "$(uname -s)" = "Darwin" ]; then
    98      PATH="/Applications/VMware Fusion.app/Contents/Library:$PATH"
    99    fi
   100  
   101    dir="${name}.vmwarevm"
   102    vmx="$dir/${name}.vmx"
   103  
   104    if [ -d "$dir" ] ; then
   105      if vmrun list | grep -q "$vmx" ; then
   106        vmrun stop "$vmx" hard
   107      fi
   108      rm -rf "$dir"
   109    fi
   110  
   111    mkdir "$dir"
   112    vmware-vdiskmanager -c -s "${disk}GB" -a lsilogic -t 1 "$dir/${name}.vmdk" 2>/dev/null
   113  
   114    cat > "$vmx" <<EOF
   115  config.version = "8"
   116  virtualHW.version = "11"
   117  numvcpus = "2"
   118  memsize = "$((mem*1024))"
   119  displayName = "$name"
   120  guestOS = "vmkernel6"
   121  vhv.enable = "TRUE"
   122  scsi0.present = "TRUE"
   123  scsi0.virtualDev = "lsilogic"
   124  scsi0:0.present = "TRUE"
   125  scsi0:0.fileName = "${name}.vmdk"
   126  ide1:0.present = "TRUE"
   127  ide1:0.fileName = "$(realpath "$iso")"
   128  ide1:0.deviceType = "cdrom-image"
   129  ethernet0.present = "TRUE"
   130  ethernet0.connectionType = "nat"
   131  ethernet0.virtualDev = "e1000"
   132  ethernet0.wakeOnPcktRcv = "FALSE"
   133  ethernet0.linkStatePropagation.enable = "TRUE"
   134  vmci0.present = "TRUE"
   135  hpet0.present = "TRUE"
   136  tools.syncTime = "TRUE"
   137  pciBridge0.present = "TRUE"
   138  pciBridge4.present = "TRUE"
   139  pciBridge4.virtualDev = "pcieRootPort"
   140  pciBridge4.functions = "8"
   141  pciBridge5.present = "TRUE"
   142  pciBridge5.virtualDev = "pcieRootPort"
   143  pciBridge5.functions = "8"
   144  pciBridge6.present = "TRUE"
   145  pciBridge6.virtualDev = "pcieRootPort"
   146  pciBridge6.functions = "8"
   147  pciBridge7.present = "TRUE"
   148  pciBridge7.virtualDev = "pcieRootPort"
   149  pciBridge7.functions = "8"
   150  EOF
   151  
   152    vmrun start "$vmx" nogui
   153    vm_ip=$(vmrun getGuestIPAddress "$vmx" -wait)
   154  else
   155    export GOVC_DATASTORE=${GOVC_DATASTORE:-$(basename "$(govc ls datastore)")}
   156    if [ "$(govc about -json | jq -r .About.ProductLineId)" == "embeddedEsx" ] ; then
   157      policy=$(govc host.portgroup.info -json | jq -r ".Portgroup[] | select(.Spec.Name == \"$network\") | .Spec.Policy.Security")
   158      if [ -n "$policy" ] && [ "$(jq -r <<<"$policy" .AllowPromiscuous)" != "true" ] ; then
   159        echo "Enabling promiscuous mode for $network on $(govc env -x GOVC_URL_HOST)..."
   160        govc host.portgroup.change -allow-promiscuous "$network"
   161      fi
   162    fi
   163  
   164    boot=$(basename "$iso")
   165    if ! govc datastore.ls "$boot" > /dev/null 2>&1 ; then
   166      govc datastore.upload "$iso" "$boot"
   167    fi
   168  
   169    echo "Creating vm ${name}..."
   170    govc vm.create -on=false -net "$network" -m $((mem*1024)) -c 2 -g "$guest" -net.adapter=vmxnet3 -disk.controller pvscsi "$name"
   171  
   172    echo "Adding a second nic for ${name}..."
   173    govc vm.network.add -net "$network" -net.adapter=vmxnet3 -vm "$name"
   174  
   175    echo "Enabling nested hv for ${name}..."
   176    govc vm.change -vm "$name" -nested-hv-enabled
   177  
   178    echo "Enabling Mac Learning dvFilter for ${name}..."
   179    seq 0 1 | xargs -I% govc vm.change -vm "$name" \
   180                    -e ethernet%.filter4.name=dvfilter-maclearn \
   181                    -e ethernet%.filter4.onFailure=failOpen
   182  
   183    echo "Adding cdrom device to ${name}..."
   184    id=$(govc device.cdrom.add -vm "$name")
   185  
   186    echo "Inserting $boot into $name cdrom device..."
   187    govc device.cdrom.insert -vm "$name" -device "$id" "$boot"
   188  
   189    if [ -n "$standalone" ] ; then
   190      echo "Creating $name disk for use by ESXi..."
   191      govc vm.disk.create -vm "$name" -name "$name"/disk1 -size "${disk}G"
   192    fi
   193  
   194    echo "Powering on $name VM..."
   195    govc vm.power -on "$name"
   196  
   197    echo "Waiting for $name ESXi IP..."
   198    vm_ip=$(govc vm.ip "$name")
   199  
   200    ! govc events -n 100 "vm/$name" | grep -E 'warning|error'
   201  fi
   202  
   203  esx_url="root:@${vm_ip}"
   204  echo "Waiting for $name hostd (via GOVC_URL=$esx_url)..."
   205  while true; do
   206    if govc about -u "$esx_url" 2>/dev/null; then
   207      break
   208    fi
   209  
   210    printf "."
   211    sleep 1
   212  done
   213  
   214  if [ -z "$standalone" ] ; then
   215    # Create disk for vSAN after boot so they are unclaimed
   216    echo "Creating $name disks for use by vSAN..."
   217    govc vm.disk.create -vm "$name" -name "$name"/vsan-cache -size "$((disk/2))G"
   218    govc vm.disk.create -vm "$name" -name "$name"/vsan-store -size "${disk}G"
   219  fi
   220  
   221  # Set target to the ESXi VM
   222  GOVC_URL="$esx_url"
   223  
   224  if [ -z "$standalone" ] ; then
   225    echo "Rescanning ${name} HBA for new devices..."
   226    disk=($(govc host.storage.info -rescan | grep /vmfs/devices/disks | awk '{print $1}' | sort))
   227  
   228    echo "Marking ${name} disk ${disk[0]} as SSD..."
   229    govc host.storage.mark -ssd "${disk[0]}"
   230  
   231    echo "Marking ${name} disk ${disk[1]} as HDD..."
   232    govc host.storage.mark -ssd=false "${disk[1]}"
   233  fi
   234  
   235  echo "Configuring NTP for ${name}..."
   236  govc host.date.change -server 0.pool.ntp.org
   237  
   238  for id in TSM TSM-SSH ntpd ; do
   239    printf "Enabling service %s for ${name}...\n" $id
   240    govc host.service enable $id
   241    govc host.service start $id
   242  done
   243  
   244  if [ -z "$username" ] ; then
   245    username=root
   246    action="update"
   247  else
   248    action="create"
   249  fi
   250  
   251  echo "Disabling VSAN device monitoring for ${name}..."
   252  govc host.esxcli system settings advanced set -o /LSOM/VSANDeviceMonitoring -i 0
   253  
   254  # A setting of 1 means that vSwp files are created thin, with 0% Object Space Reservation
   255  govc host.esxcli system settings advanced set -o /VSAN/SwapThickProvisionDisabled -i 1
   256  govc host.esxcli system settings advanced set -o /VSAN/FakeSCSIReservations -i 1
   257  
   258  echo "ESX host account $action for user $username on ${name}..."
   259  govc host.account.$action -id $username -password "$password"
   260  
   261  echo "Granting Admin permissions for user $username on ${name}..."
   262  govc permissions.set -principal $username -role Admin
   263  
   264  echo "Enabling guest ARP inspection to get vm IPs without vmtools on ${name}..."
   265  govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1
   266  
   267  echo "Opening firewall for serial port traffic for ${name}..."
   268  govc host.esxcli network firewall ruleset set -r remoteSerialPort -e true
   269  
   270  echo "Setting hostname for ${name}..."
   271  govc host.esxcli system hostname set -H "$name"
   272  
   273  echo "Enabling MOB for ${name}..."
   274  govc host.option.set Config.HostAgent.plugins.solo.enableMob true
   275  
   276  if which sshpass >/dev/null && [ -e ~/.ssh/id_rsa.pub ] ; then
   277    echo "Adding ssh authorized key to ${name}..."
   278    sshpass -p "$password" scp \
   279            -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oLogLevel=error \
   280            ~/.ssh/id_rsa.pub "root@$vm_ip:/etc/ssh/keys-root/authorized_keys"
   281  fi
   282  
   283  echo "Done: GOVC_URL=${username}:${password}@${vm_ip}"