-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
332 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
__pycache__ | ||
*.orig | ||
output-qemu | ||
*~ | ||
\#*\# | ||
.#* | ||
*.*.swp | ||
*.gz | ||
*.xz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[submodule "vmware-esxi/pyyaml"] | ||
path = vmware-esxi/pyyaml | ||
url = https://github.com/yaml/pyyaml | ||
[submodule "vmware-esxi/oauthlib"] | ||
path = vmware-esxi/oauthlib | ||
url = https://github.com/oauthlib/oauthlib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
# Packer MAAS | ||
|
||
[Packer](http://packer.io) [templates](https://www.packer.io/docs/templates/index.html), assoicated scripts, and configuration for creating deployable OS images for [MAAS](http://maas.io). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# VMware ESXi Packer Template for MAAS | ||
|
||
## Prerequisites | ||
|
||
The VMware ESXi installation ISO must be downloaded manually. You can download it [here.](https://www.vmware.com/go/get-free-esxi) | ||
|
||
## Building an image | ||
Your current working directory must be in packer-maas/vmware-esxi, where this file is located. Once in packer-maas/vmware-esxi you can generate an image with: | ||
``` | ||
$ sudo packer build -var 'vmware_esxi_iso_path=/path/to/VMware-VMvisor-Installer-6.7.0-8169922.x86_64.iso' vmware-esxi.json | ||
``` | ||
Installation is non-interactive. | ||
|
||
## Uploading an image to MAAS | ||
``` | ||
$ maas $PROFILE boot-resources create name='vmware-esxi-6.7' title='VMware ESXi 6.7' architecture='amd64/generic' filetype='ddgz' content@=vmware-esxi.dd.gz | ||
``` | ||
|
||
## Customization | ||
The deployment image may be customized by modifying packer-maas/vmware-esxi/http/vmware-esxi-ks.cfg see Installation and Upgrade Scripts in the [VMware ESXi installation and Setup manual](https://docs.vmware.com/en/VMware-vSphere/6.7/vsphere-esxi-67-installation-setup-guide.pdf) for more information. | ||
|
||
## Requirements | ||
VMware ESXi has a specific set of [hardware requirements](https://www.vmware.com/resources/compatibility/search.php) which are more stringent then MAAS. | ||
|
||
The machine building the deployment image must be a GNU/Linux host with a dual core x86_64 processor supporting hardware virtualization with at least 4GB of RAM and 10GB of disk space available. Additionally the qemu-kvm and qemu-utils packages must be installed on the build system. | ||
|
||
### libvirt testing | ||
While VMware ESXi does not support running in any virtual machine it is possible to deploy to one. The libvirt machine must be a KVM instance with at least CPU 2 cores and 4GB of RAM. To give VMware ESXi access to hardware virtualization go into machine settings, CPUs, and select 'copy host CPU configuration.' VMware ESXi has no support for libvirt drivers, instead an emulated IDE disk, and an emulated e1000 NIC must be used. | ||
|
||
## Known limitations | ||
|
||
### Only the deployment storage device is used | ||
Custom storage configuration is not supported as VMware ESXi has specific requirements for how files are written to the disk. MAAS will extend datastore1 to the full size of the deployment disk. After deployment VMware tools may be used to access the other disks. | ||
|
||
### IP Address not assoicated with machine | ||
VMware ESXi connects the physical NIC to a vSphere Standard Switch and creates a new VMkernel adapter for networking. The VMkernel adapter has its own MAC address which is recognized by MAAS as a new device. Custom network configuration is not supported. | ||
|
||
### Image fails to build due to qemu-nbd error | ||
If the image fails to build due to a qemu-nbd error try disconnecting the device with | ||
``` | ||
$ sudo qemu-nbd -d /dev/nbd4 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from curtin.config import load_command_config | ||
from curtin.util import load_command_environment | ||
|
||
from subprocess import check_call | ||
import os | ||
import sys | ||
import tempfile | ||
|
||
|
||
def find_altbootbank_blkdev(target): | ||
with open('/proc/mounts', 'r') as mounts: | ||
for line in mounts.readlines(): | ||
mount = line.split() | ||
blkdev = mount[0] | ||
mount_point = mount[1] | ||
if mount_point == target: | ||
return '%s6' % blkdev[0:-1] | ||
|
||
print('ERROR: Unable to find /altbootbank block device!') | ||
sys.exit(1) | ||
|
||
|
||
def mount(blkdev): | ||
mount_point = tempfile.mkdtemp(prefix='curtin-hooks-') | ||
check_call(['mount', blkdev, mount_point]) | ||
return mount_point | ||
|
||
|
||
def umount(blkdev): | ||
check_call(['umount', blkdev]) | ||
|
||
def main(): | ||
state = load_command_environment() | ||
config = load_command_config(None, state) | ||
|
||
# Write the MAAS credentials to /altbootbank | ||
altbootbank_blkdev = find_altbootbank_blkdev(state['target']) | ||
altbootbank_mount_point = mount(altbootbank_blkdev) | ||
maas_cfg_path = os.path.join(altbootbank_mount_point, 'maas', 'maas.cfg') | ||
with open(maas_cfg_path, 'w') as f: | ||
f.write(config['cloudconfig']['maas-cloud-config']['content']) | ||
umount(altbootbank_blkdev) | ||
|
||
|
||
if __name__ =="__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
vmaccepteula | ||
|
||
# The root password for the deployed image | ||
rootpw password123! | ||
|
||
install --firstdisk | ||
|
||
# Sets VMware ESXi licensing key. If not included installs in | ||
# evaluation mode. | ||
# serialnum --esx=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX | ||
|
||
network --bootproto=dhcp | ||
|
||
%post --interpreter=busybox | ||
# The install reboots by default, when creating an image halt so Packer can | ||
# run post-processors and finish. | ||
halt | ||
|
||
%firstboot --interpreter=busybox | ||
# Enable SSH | ||
vim-cmd hostsvc/enable_ssh | ||
vim-cmd hostsvc/start_ssh | ||
|
||
# Enable ESXi shell | ||
# vim-cmd hostsvc/enable_esx_shell | ||
# vim-cmd hostsvc/start_esx_shell | ||
|
||
# Extend VMFS to the size of the disk. This is normally done by Curtin but | ||
# must be done here due to VMFS requiring proprietary tools. | ||
BLK_DEV=$(esxcli storage vmfs extent list | awk '/datastore1/ { print $4 }') | ||
BLK_DEV="/dev/disks/$BLK_DEV" | ||
printf 'Y\nFix\n' | partedUtil fixGpt $BLK_DEV | ||
PART_START=$(partedUtil get $BLK_DEV | awk '/^3 / { print $2 }') | ||
END_DISK=$(partedUtil getUsableSectors $BLK_DEV | cut -d ' ' -f2) | ||
partedUtil resize $BLK_DEV 3 $PART_START $END_DISK | ||
vmkfstools --growfs $BLK_DEV:3 $BLK_DEV:3 | ||
|
||
# Temporarily disable firewall so we can communicate with MAAS | ||
esxcli network firewall set --enabled=false | ||
|
||
# Copy SSH keys from MAAS | ||
/altbootbank/maas/maas-md-get -c /altbootbank/maas/maas.cfg \ | ||
latest/meta-data/public-keys >> /etc/ssh/keys-root/authorized_keys | ||
|
||
# Tell MAAS deployment has finished by retrieving user-data. user-data is not | ||
# currently executed. | ||
/altbootbank/maas/maas-md-get -c /altbootbank/maas/maas.cfg latest/user-data | ||
|
||
# Reenable firewall | ||
esxcli network firewall set --enabled=true | ||
|
||
# Cleanup MAAS first boot files. | ||
#rm -rf /altbootbank/maas |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from argparse import ArgumentParser | ||
import http.client | ||
import socket | ||
import sys | ||
import time | ||
import urllib.error | ||
import urllib.parse | ||
import urllib.request | ||
|
||
import oauthlib.oauth1 as oauth | ||
import yaml | ||
|
||
|
||
def authenticate_headers(url, headers, creds, clockskew=0): | ||
"""Update and sign a dict of request headers.""" | ||
if creds.get('consumer_key', None) is not None: | ||
timestamp = int(time.time()) + clockskew | ||
client = oauth.Client( | ||
client_key=creds['consumer_key'], | ||
client_secret=creds['consumer_secret'], | ||
resource_owner_key=creds['token_key'], | ||
resource_owner_secret=creds['token_secret'], | ||
signature_method=oauth.SIGNATURE_PLAINTEXT, | ||
timestamp=str(timestamp)) | ||
_, signed_headers, _ = client.sign(url) | ||
headers.update(signed_headers) | ||
|
||
|
||
def geturl(url, creds, headers=None, data=None): | ||
# Takes a dict of creds to be passed through to oauth_headers, | ||
# so it should have consumer_key, token_key, ... | ||
if headers is None: | ||
headers = {} | ||
else: | ||
headers = dict(headers) | ||
|
||
clockskew = 0 | ||
|
||
error = Exception("Unexpected Error") | ||
for naptime in (1, 1, 2, 4, 8, 16, 32): | ||
authenticate_headers(url, headers, creds, clockskew) | ||
try: | ||
req = urllib.request.Request(url=url, data=data, headers=headers) | ||
ret = urllib.request.urlopen(req) | ||
return ret.read().decode() | ||
except urllib.error.HTTPError as exc: | ||
error = exc | ||
if 'date' not in exc.headers: | ||
print("date field not in %d headers" % exc.code) | ||
pass | ||
elif exc.code in (http.client.UNAUTHORIZED, http.client.FORBIDDEN): | ||
date = exc.headers['date'] | ||
try: | ||
ret_time = time.mktime(parsedate(date)) | ||
clockskew = int(ret_time - time.time()) | ||
print("updated clock skew to %d" % clockskew) | ||
except: | ||
print("failed to convert date '%s'" % date) | ||
elif exc.code == http.client.NOT_FOUND: | ||
# Nothing to download. | ||
return '' | ||
|
||
except Exception as exc: | ||
error = exc | ||
|
||
print("request to %s failed. sleeping %d.: %s" % (url, naptime, error)) | ||
time.sleep(naptime) | ||
|
||
raise error | ||
|
||
|
||
def main(): | ||
parser = ArgumentParser( | ||
description='Get data from the MAAS metadata server') | ||
parser.add_argument( | ||
'-c', '--config', help='Path to the MAAS metadata credentials file', | ||
required=True) | ||
parser.add_argument('entry', help='The metadata path to get') | ||
|
||
args = parser.parse_args() | ||
|
||
with open(args.config, 'r') as f: | ||
cfg = yaml.safe_load(f) | ||
|
||
if 'datasource' in cfg: | ||
cfg = cfg['datasource']['MAAS'] | ||
|
||
if 'consumer_secret' not in cfg: | ||
cfg['consumer_secret'] = '' | ||
|
||
if cfg['metadata_url'].endswith('/'): | ||
url = '%s%s' % (cfg['metadata_url'], args.entry) | ||
else: | ||
url = '%s/%s' % (cfg['metadata_url'], args.entry) | ||
|
||
try: | ||
print(geturl(url, creds=cfg)) | ||
except urllib.error.HTTPError as exc: | ||
print("HTTP error [%s]" % exc.code) | ||
sys.exit(1) | ||
except urllib.error.URLError as exc: | ||
print("URL error [%s]" % exc.reason) | ||
sys.exit(1) | ||
except socket.timeout as exc: | ||
print("Socket timeout [%s]" % exc) | ||
sys.exit(1) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"variables": { | ||
"vmware_esxi_iso_path": "{{env `VMWARE_ESXI_ISO_PATH`}}" | ||
}, | ||
"builders": [ | ||
{ | ||
"type": "qemu", | ||
"communicator": "none", | ||
"iso_url": "{{user `vmware_esxi_iso_path`}}", | ||
"iso_checksum_type": "none", | ||
"accelerator": "kvm", | ||
"boot_wait": "3s", | ||
"boot_command": [ | ||
"<enter><wait>", | ||
"<leftShift>O", | ||
" ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/vmware-esxi-ks.cfg<enter>" | ||
], | ||
"disk_interface": "ide", | ||
"disk_size": 10240, | ||
"http_directory": "http", | ||
"format": "raw", | ||
"net_device": "e1000", | ||
"qemuargs": [ | ||
[ "-m", "4096m" ], | ||
[ "-cpu", "host" ], | ||
[ "-smp", "2,sockets=2,cores=1,threads=1" ] | ||
] | ||
} | ||
], | ||
"post-processors": [ | ||
{ | ||
"type": "shell-local", | ||
"inline_shebang": "/bin/bash -e", | ||
"inline": [ | ||
"TMP_DIR=$(mktemp -d)", | ||
"qemu-nbd -c /dev/nbd4 -f raw -n output-qemu/packer-qemu", | ||
"sleep 1", | ||
"mount /dev/nbd4p1 $TMP_DIR", | ||
"mkdir -p $TMP_DIR/curtin", | ||
"cp curtin-hooks $TMP_DIR/curtin", | ||
"sync $TMP_DIR/curtin", | ||
"umount $TMP_DIR", | ||
"mount /dev/nbd4p6 $TMP_DIR", | ||
"mkdir -p $TMP_DIR/maas", | ||
"cp maas-md-get $TMP_DIR/maas", | ||
"cp -r pyyaml/lib3/yaml $TMP_DIR/maas", | ||
"cp -r oauthlib/oauthlib $TMP_DIR/maas", | ||
"sync $TMP_DIR/maas", | ||
"umount $TMP_DIR", | ||
"qemu-nbd -d /dev/nbd4", | ||
"rmdir $TMP_DIR" | ||
] | ||
}, | ||
{ | ||
"type": "compress", | ||
"output": "vmware-esxi.dd.gz" | ||
} | ||
] | ||
} |