├── .gitignore ├── prepare_iso ├── support │ ├── vagrant.jpg │ ├── OSInstall.collection │ ├── minstallconfig.xml │ ├── user.plist │ ├── generate_shadowhash │ └── pkg-postinstall └── prepare_iso.sh ├── scripts ├── system-update.sh ├── autologin.sh ├── chef-omnibus.sh ├── shrink.sh ├── parallels.sh ├── vagrant.sh ├── add-network-interface-detection.sh ├── vmware.sh ├── support │ └── set_kcpassword.py ├── post-install.sh ├── xcode-cli-tools.sh └── puppet.sh ├── LICENSE.md ├── README.md ├── vagrant.json └── standalone.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | packer_cache 3 | *.dmg 4 | *.box 5 | AutoPartition-* 6 | packer/output-* 7 | *.pvm 8 | -------------------------------------------------------------------------------- /prepare_iso/support/vagrant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickcharlton/packer-macos/HEAD/prepare_iso/support/vagrant.jpg -------------------------------------------------------------------------------- /scripts/system-update.sh: -------------------------------------------------------------------------------- 1 | if [ "$UPDATE_SYSTEM" != "true" ] && [ "$UPDATE_SYSTEM" != "1" ]; then 2 | exit 3 | fi 4 | 5 | echo "Downloading and installing system updates..." 6 | softwareupdate -i -a 7 | -------------------------------------------------------------------------------- /scripts/autologin.sh: -------------------------------------------------------------------------------- 1 | if [ "$AUTOLOGIN" != "true" ] && [ "$AUTOLOGIN" != "1" ]; then 2 | exit 3 | fi 4 | 5 | echo "Enabling automatic GUI login for the '$USERNAME' user.." 6 | 7 | python /private/tmp/set_kcpassword.py "$PASSWORD" 8 | 9 | /usr/bin/defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser "$USERNAME" 10 | -------------------------------------------------------------------------------- /scripts/chef-omnibus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${CHEF_VERSION}" == "none" ]; then 4 | exit 5 | fi 6 | 7 | INSTALL_ARGS="" 8 | 9 | if [ "${CHEF_VERSION}" != "latest" ]; then 10 | INSTALL_ARGS="-v ${CHEF_VERSION}" 11 | fi 12 | 13 | curl -LO https://www.chef.io/chef/install.sh 14 | chmod +x ./install.sh 15 | ./install.sh "${INSTALL_ARGS}" 16 | rm install.sh 17 | -------------------------------------------------------------------------------- /prepare_iso/support/OSInstall.collection: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | /System/Installation/Packages/OSInstall.mpkg 6 | /System/Installation/Packages/OSInstall.mpkg 7 | /System/Installation/Packages/veewee-config.pkg 8 | 9 | 10 | -------------------------------------------------------------------------------- /prepare_iso/support/minstallconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | InstallType 6 | automated 7 | Language 8 | en 9 | Package 10 | /System/Installation/Packages/OSInstall.collection 11 | Target 12 | /Volumes/Macintosh HD 13 | TargetName 14 | Macintosh HD 15 | 16 | 17 | -------------------------------------------------------------------------------- /scripts/shrink.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OSX_VERS=$(sw_vers -productVersion | awk -F "." '{print $2}') 4 | 5 | # Turn off hibernation and get rid of the sleepimage 6 | pmset hibernatemode 0 7 | rm -f /var/vm/sleepimage 8 | 9 | # Stop the pager process and drop swap files. These will be re-created on boot. 10 | # Starting with El Cap we can only stop the dynamic pager if SIP is disabled. 11 | if [ "$OSX_VERS" -lt 11 ] || $(csrutil status | grep -q disabled); then 12 | launchctl unload /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist 13 | sleep 5 14 | fi 15 | rm -rf /private/var/vm/swap* 16 | 17 | # VMware Fusion specific items 18 | if [ -e .vmfusion_version ] || [[ "$PACKER_BUILDER_TYPE" == vmware* ]]; then 19 | # Shrink the disk 20 | /Library/Application\ Support/VMware\ Tools/vmware-tools-cli disk shrink / 21 | fi 22 | -------------------------------------------------------------------------------- /scripts/parallels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eo pipefail 4 | 5 | TOOLS_PATH="/Users/$USERNAME/prl-tools-mac.iso" 6 | # Parallels Tools specific items 7 | if [ -e .PACKER_BUILDER_TYPE ] || [[ "$PACKER_BUILDER_TYPE" == parallels* ]]; then 8 | if [ ! -e "$TOOLS_PATH" ]; then 9 | echo "Couldn't locate uploaded tools iso at $TOOLS_PATH!" 10 | exit 1 11 | fi 12 | 13 | TMPMOUNT=`/usr/bin/mktemp -d /tmp/parallels-tools.XXXX` 14 | hdiutil attach "$TOOLS_PATH" -mountpoint "$TMPMOUNT" 15 | 16 | INSTALLER_PKG="$TMPMOUNT/Install.app/Contents/Resources/Install.mpkg" 17 | if [ ! -e "$INSTALLER_PKG" ]; then 18 | echo "Couldn't locate Parallels Tools installer pkg at $INSTALLER_PKG!" 19 | exit 1 20 | fi 21 | 22 | echo "Installing Parallels Tools..." 23 | installer -pkg "$INSTALLER_PKG" -target / 24 | 25 | # This usually fails 26 | hdiutil detach "$TMPMOUNT" 27 | rm -rf "$TMPMOUNT" 28 | rm -f "$TOOLS_PATH" 29 | fi 30 | -------------------------------------------------------------------------------- /scripts/vagrant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | date > /etc/box_build_time 3 | OSX_VERS=$(sw_vers -productVersion | awk -F "." '{print $2}') 4 | 5 | # Set computer/hostname 6 | COMPNAME=osx-10_${OSX_VERS} 7 | scutil --set ComputerName ${COMPNAME} 8 | scutil --set HostName ${COMPNAME}.vagrantup.com 9 | 10 | # Packer passes boolean user variables through as '1', but this might change in 11 | # the future, so also check for 'true'. 12 | if [ "$INSTALL_VAGRANT_KEYS" = "true" ] || [ "$INSTALL_VAGRANT_KEYS" = "1" ]; then 13 | echo "Installing vagrant keys for $USERNAME user" 14 | mkdir "/Users/$USERNAME/.ssh" 15 | chmod 700 "/Users/$USERNAME/.ssh" 16 | curl -L 'https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub' > "/Users/$USERNAME/.ssh/authorized_keys" 17 | chmod 600 "/Users/$USERNAME/.ssh/authorized_keys" 18 | chown -R "$USERNAME" "/Users/$USERNAME/.ssh" 19 | fi 20 | 21 | # Create a group and assign the user to it 22 | dseditgroup -o create "$USERNAME" 23 | dseditgroup -o edit -a "$USERNAME" "$USERNAME" 24 | -------------------------------------------------------------------------------- /prepare_iso/support/user.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | authentication_authority 6 | 7 | ;ShadowHash; 8 | 9 | generateduid 10 | 11 | 11112222-3333-4444-AAAA-BBBBCCCCDDDD 12 | 13 | gid 14 | 15 | 20 16 | 17 | home 18 | 19 | /Users/${USER} 20 | 21 | jpegphoto 22 | 23 | 24 | ${BASE64_IMAGE} 25 | 26 | 27 | name 28 | 29 | ${USER} 30 | 31 | passwd 32 | 33 | ******** 34 | 35 | realname 36 | 37 | ${USER} 38 | 39 | shell 40 | 41 | /bin/bash 42 | 43 | uid 44 | 45 | 501 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /scripts/add-network-interface-detection.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script adds a Mac OS Launch Daemon, which runs every time the 4 | # machine is booted. The daemon will re-detect the attached network 5 | # interfaces. If this is not done, network devices may not work. 6 | PLIST=/Library/LaunchDaemons/com.github.timsutton.osx-vm-templates.detectnewhardware.plist 7 | cat < "${PLIST}" 8 | 9 | 10 | 11 | 12 | Label 13 | com.github.timsutton.osx-vm-templates.detectnewhardware 14 | ProgramArguments 15 | 16 | /usr/sbin/networksetup 17 | -detectnewhardware 18 | 19 | RunAtLoad 20 | 21 | 22 | 23 | EOF 24 | 25 | # These should be already set as follows, but since they're required 26 | # in order to load properly, we set them explicitly. 27 | /bin/chmod 644 "${PLIST}" 28 | /usr/sbin/chown root:wheel "${PLIST}" 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2015 Timothy Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/vmware.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TOOLS_PATH="/Users/$USERNAME/darwin.iso" 4 | # VMware Fusion specific items 5 | if [ -e .vmfusion_version ] || [[ "$PACKER_BUILDER_TYPE" == vmware* ]]; then 6 | if [ ! -e "$TOOLS_PATH" ]; then 7 | echo "Couldn't locate uploaded tools iso at $TOOLS_PATH!" 8 | exit 1 9 | fi 10 | 11 | TMPMOUNT=`/usr/bin/mktemp -d /tmp/vmware-tools.XXXX` 12 | hdiutil attach "$TOOLS_PATH" -mountpoint "$TMPMOUNT" 13 | 14 | INSTALLER_PKG="$TMPMOUNT/Install VMware Tools.app/Contents/Resources/VMware Tools.pkg" 15 | if [ ! -e "$INSTALLER_PKG" ]; then 16 | echo "Couldn't locate VMware installer pkg at $INSTALLER_PKG!" 17 | exit 1 18 | fi 19 | 20 | echo "Installing VMware tools.." 21 | installer -pkg "$TMPMOUNT/Install VMware Tools.app/Contents/Resources/VMware Tools.pkg" -target / 22 | 23 | # This usually fails 24 | hdiutil detach "$TMPMOUNT" 25 | rm -rf "$TMPMOUNT" 26 | rm -f "$TOOLS_PATH" 27 | 28 | # Point Linux shared folder root to that used by OS X guests, 29 | # useful for the Hashicorp vmware_fusion Vagrant provider plugin 30 | mkdir /mnt 31 | ln -sf /Volumes/VMware\ Shared\ Folders /mnt/hgfs 32 | fi 33 | -------------------------------------------------------------------------------- /scripts/support/set_kcpassword.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Port of Gavin Brock's Perl kcpassword generator to Python, by Tom Taylor 4 | # . 5 | # Perl version: http://www.brock-family.org/gavin/perl/kcpassword.html 6 | 7 | import sys 8 | import os 9 | 10 | 11 | def kcpassword(passwd): 12 | # The magic 11 bytes - these are just repeated 13 | # 0x7D 0x89 0x52 0x23 0xD2 0xBC 0xDD 0xEA 0xA3 0xB9 0x1F 14 | key = [125, 137, 82, 35, 210, 188, 221, 234, 163, 185, 31] 15 | key_len = len(key) 16 | 17 | passwd = [ord(x) for x in list(passwd)] 18 | # pad passwd length out to an even multiple of key length 19 | r = len(passwd) % key_len 20 | if (r > 0): 21 | passwd = passwd + [0] * (key_len - r) 22 | 23 | for n in range(0, len(passwd), len(key)): 24 | ki = 0 25 | for j in range(n, min(n+len(key), len(passwd))): 26 | passwd[j] = passwd[j] ^ key[ki] 27 | ki += 1 28 | 29 | passwd = [chr(x) for x in passwd] 30 | return "".join(passwd) 31 | 32 | if __name__ == "__main__": 33 | passwd = kcpassword(sys.argv[1]) 34 | fd = os.open('/etc/kcpassword', os.O_WRONLY | os.O_CREAT, 0o600) 35 | file = os.fdopen(fd, 'w') 36 | file.write(passwd) 37 | file.close() 38 | -------------------------------------------------------------------------------- /scripts/post-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Adding default SSH key for $USERNAME user.." 4 | mkdir -p "/Users/$USERNAME/.ssh" 5 | 6 | cat << EOF > "/Users/$USERNAME/.ssh/authorized_keys" 7 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDY/apwGMmA6ZBnN7ezuNlpEhCmET1bkuyy1oKNo4/xDCyE2i8KAKBrSzKOGnjNNCtcQmVcslfJBizY0atX2o19WauZtgbNSsT8qCqqHZ3ha9riJW7ypxLh2wpTtFMfc78Sna+yA/ErWuQNMgKOFW7KU5S+sXtls1IfXloDSRm+q7GhmuwjLlN4Mk8y43mhyFe0ZO+NY09Xmc1yyy5w1urJuykFs6zcUkjQ5l3H5ZBPGJjDJ6KHXYsEcE6zDaa+4lZiWb7MaamU37W0Zm/ntIQUzDEP/XPOAC0NTdAsXI1dSltVX6NCLFUO9qHSSv9N9wPECuimJUt4wyYU4P1e//o5Gq0EIpNpiswEaJtlc9f0AEyzuQLdWYwtLW+ncIdK2Bm2nVCBYvBqQ2bB9cMdShVTEvTAlnSb3tavETxPTjXBefQaugsPeV67eEQhmeWValnQIcLtjd2JnktVHLw3bdH4cIUKsauE07TQzdkTyWRs9eyygz0kNMTtCq/wcMMuTGDv0Yhrc4lFNZ9OeHPmuMpx5CbnPhexaUXjqJq+KjLkBJ3DeWkS3anbYoK7UJrEQYYWPQjZcPj3vLHu4n1preO3uZ0fcrgtlwato20n83+sn0ieOgBz6t+jqekRyUFLCe/A401vUUlflGAm3N4UvbZfiLKq3qk2EPkKL+p4cC2ZPw== 8 | EOF 9 | 10 | chmod 700 "/Users/$USERNAME/.ssh" 11 | chmod 600 "/Users/$USERNAME/.ssh/authorized_keys" 12 | chown -R "$USERNAME" "/Users/$USERNAME/.ssh" 13 | 14 | echo "Enabling password-less sudo..." 15 | mkdir -p /etc/sudoers.d 16 | 17 | cat << EOF > /etc/sudoers.d/password_less 18 | ALL ALL = (ALL) NOPASSWD: ALL 19 | EOF 20 | 21 | chmod 440 /etc/sudoers.d/password_less 22 | 23 | echo "Creating a group for the user..." 24 | dseditgroup -o create "$USERNAME" 25 | dseditgroup -o edit -a "$USERNAME" "$USERNAME" 26 | -------------------------------------------------------------------------------- /prepare_iso/support/generate_shadowhash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | C78F3A60-FC1D-4377-AD7D-DBAD5A6B8B2C 12 | # 13 | # 2008 Pete Akins, Cincinnati, OH . pete.akins@uc.edu 14 | 15 | /********************* 16 | 17 | FORMAT OF SHADOW FILE 18 | 19 | Offsets and length (hex values) 20 | 0-63 NTLM Password (64) 21 | 64-103 SHA1 Digest (40) 22 | 104-167 CRAM-MD5 (64) 23 | 168-215 Salted SHA1 (48, 8+40) 24 | 216-1239 Recoverable (1024) 25 | 26 | *********************/ 27 | 28 | if (!isset($argv[1])) { 29 | fprintf(STDERR, "Enter password: "); 30 | $password = trim(fgets(STDIN)); 31 | } else { 32 | // get the password as an arg 33 | $password = $argv[1]; 34 | } 35 | 36 | if (empty($password)) { 37 | die("Invalid password"); 38 | } 39 | 40 | do { 41 | 42 | /* make sure we get a big random number, but not too big */ 43 | $randmax = getrandmax(); 44 | $max = pow(2, 31)-1; 45 | if ($max>$randmax) { 46 | $max = $randmax; 47 | } 48 | 49 | /* get our salt integer, and it's hex value */ 50 | $salt = rand(1, $max); 51 | $saltHex = decHex($salt); 52 | 53 | /* get string representation of bytes */ 54 | $saltStr = pack("N", $salt); 55 | 56 | /* compute salted hash. get uppercase values */ 57 | $sha1_salt = sprintf("%08s%s", strtoupper($saltHex), strtoupper(sha1($saltStr . $password))); 58 | 59 | } while (strlen($sha1_salt)!=48); //just in case we have odd ball integers that result in non standard hex. 60 | 61 | /* blank out other hashes */ 62 | $NTLM = str_repeat("0", 64); 63 | $sha1 = str_repeat("0", 40); 64 | $cram_md5 = str_repeat("0", 64); 65 | $recoverable = str_repeat("0", 1024); 66 | 67 | /* put it all together */ 68 | $string = $NTLM . $sha1 . $cram_md5 . $sha1_salt . $recoverable; 69 | 70 | echo $string; 71 | exit(0); 72 | 73 | ?> -------------------------------------------------------------------------------- /scripts/xcode-cli-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [[ ! "$INSTALL_XCODE_CLI_TOOLS" =~ ^(true|yes|on|1|TRUE|YES|ON])$ ]]; then 4 | exit 5 | fi 6 | 7 | # Get and install Xcode CLI tools 8 | OSX_VERS=$(sw_vers -productVersion | awk -F "." '{print $2}') 9 | 10 | # on 10.9+, we can leverage SUS to get the latest CLI tools 11 | if [ "$OSX_VERS" -ge 9 ]; then 12 | # create the placeholder file that's checked by CLI updates' .dist code 13 | # in Apple's SUS catalog 14 | touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress 15 | # find the CLI Tools update 16 | PROD=$(softwareupdate -l | grep "\*.*Command Line" | head -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | tr -d '\n') 17 | # install it 18 | softwareupdate -i "$PROD" --verbose 19 | rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress 20 | 21 | # on 10.7/10.8, we instead download from public download URLs, which can be found in 22 | # the dvtdownloadableindex: 23 | # https://devimages.apple.com.edgekey.net/downloads/xcode/simulators/index-3905972D-B609-49CE-8D06-51ADC78E07BC.dvtdownloadableindex 24 | else 25 | [ "$OSX_VERS" -eq 7 ] && DMGURL=http://devimages.apple.com.edgekey.net/downloads/xcode/command_line_tools_for_xcode_os_x_lion_april_2013.dmg 26 | [ "$OSX_VERS" -eq 8 ] && DMGURL=http://devimages.apple.com.edgekey.net/downloads/xcode/command_line_tools_for_osx_mountain_lion_april_2014.dmg 27 | 28 | TOOLS=clitools.dmg 29 | curl "$DMGURL" -o "$TOOLS" 30 | TMPMOUNT=`/usr/bin/mktemp -d /tmp/clitools.XXXX` 31 | hdiutil attach "$TOOLS" -mountpoint "$TMPMOUNT" 32 | if [ "$OSX_VERS" -eq 7 ]; then 33 | # using '-allowUntrusted' because Lion CLI tools are so old Apple never built another 34 | # package that doesn't have an expired CA cert. (Expired February 15, 2015) 35 | installer -pkg "$(find $TMPMOUNT -name '*.mpkg')" -allowUntrusted -target / 36 | else 37 | installer -pkg "$(find $TMPMOUNT -name '*.mpkg')" -target / 38 | fi 39 | hdiutil detach "$TMPMOUNT" 40 | rm -rf "$TMPMOUNT" 41 | rm "$TOOLS" 42 | exit 43 | fi 44 | -------------------------------------------------------------------------------- /scripts/puppet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install the specified version of Puppet and tools 4 | # 5 | # PUPPET_VERSION, FACTER_VERSION and HIERA_VERSION are set to either 6 | # 'latest' or specific versions via the Packer template 7 | # 8 | # install function mostly borrowed dmg function from hashicorp/puppet-bootstrap, 9 | # except we just take an already-downloaded dmg 10 | 11 | if [[ "${PUPPET_VERSION}" == "none" && \ 12 | "${FACTER_VERSION}" == "none" && \ 13 | "${HIERA_VERSION}" == "none" && \ 14 | "${PUPPET_AGENT_VERSION}" == "none" ]]; then 15 | exit 16 | fi 17 | 18 | install_dmg() { 19 | local name="$1" 20 | local dmg_path="$2" 21 | 22 | echo "Installing: ${name}" 23 | 24 | # Mount the DMG 25 | echo "-- Mounting DMG..." 26 | tmpmount=$(/usr/bin/mktemp -d /tmp/puppet-dmg.XXXX) 27 | hdiutil attach "${dmg_path}" -mountpoint "${tmpmount}" 28 | 29 | echo "-- Installing pkg..." 30 | pkg_path=$(find "${tmpmount}" -name '*.pkg' -mindepth 1 -maxdepth 1) 31 | installer -pkg "${pkg_path}" -tgt / 32 | 33 | # Unmount 34 | echo "-- Unmounting and ejecting DMG..." 35 | hdiutil eject "${tmpmount}" 36 | } 37 | 38 | get_dmg() { 39 | local recipe_name="$1" 40 | local version="$2" 41 | local report_path=$(mktemp /tmp/autopkg-report-XXXX) 42 | 43 | # Run AutoPkg setting VERSION, and saving the results as a plist 44 | "${AUTOPKG}" run --report-plist "${report_path}" -k VERSION="${version}" "${recipe_name}" > \ 45 | "$(mktemp "/tmp/autopkg-runlog-${recipe_name}")" 46 | /usr/libexec/PlistBuddy -c \ 47 | 'Print :summary_results:url_downloader_summary_result:data_rows:0:download_path' \ 48 | "${report_path}" 49 | } 50 | 51 | # Default to installing the current version of Puppet - it's not 2013 anymore. 52 | PUPPET_VERSION=${PUPPET_VERSION:-none} 53 | FACTER_VERSION=${FACTER_VERSION:-none} 54 | HIERA_VERSION=${HIERA_VERSION:-none} 55 | PUPPET_AGENT_VERSION=${PUPPET_AGENT_VERSION:-latest} 56 | 57 | # Get AutoPkg 58 | AUTOPKG_DIR=$(mktemp -d /tmp/autopkg-XXXX) 59 | git clone https://github.com/autopkg/autopkg "$AUTOPKG_DIR" 60 | AUTOPKG="$AUTOPKG_DIR/Code/autopkg" 61 | 62 | # Add the recipes repo containing Puppet/Facter 63 | "${AUTOPKG}" repo-add recipes 64 | 65 | # Redirect AutoPkg cache to a temp location 66 | defaults write com.github.autopkg CACHE_DIR -string "$(mktemp -d /tmp/autopkg-cache-XXX)" 67 | 68 | if [ "${PUPPET_VERSION}" != "none" ]; then 69 | # Hide all users from the loginwindow with uid below 500, which will include the puppet user 70 | defaults write /Library/Preferences/com.apple.loginwindow Hide500Users -bool YES 71 | PUPPET_DMG=$(get_dmg Puppet.download "${PUPPET_VERSION}") 72 | install_dmg "Puppet" "${PUPPET_DMG}" 73 | fi 74 | 75 | if [ "${PUPPET_AGENT_VERSION}" != "none" ]; then 76 | # Hide all users from the loginwindow with uid below 500, which will include the puppet user 77 | defaults write /Library/Preferences/com.apple.loginwindow Hide500Users -bool YES 78 | PUPPET_AGENT_DMG=$(get_dmg Puppet-Agent.download "${PUPPET_AGENT_VERSION}") 79 | install_dmg "Puppet Agent" "${PUPPET_AGENT_DMG}" 80 | fi 81 | 82 | if [ "${FACTER_VERSION}" != "none" ]; then 83 | FACTER_DMG=$(get_dmg Facter.download "${FACTER_VERSION}") 84 | install_dmg "Facter" "${FACTER_DMG}" 85 | fi 86 | 87 | if [ "${HIERA_VERSION}" != "none" ]; then 88 | HIERA_DMG=$(get_dmg Hiera.download "${HIERA_VERSION}") 89 | install_dmg "Hiera" "${HIERA_DMG}" 90 | fi 91 | 92 | 93 | # Clean up 94 | rm -rf "${PUPPET_DMG}" "${FACTER_DMG}" "${HIERA_DMG}" "${PUPPET_AGENT_DMG}" "${AUTOPKG_DIR}" "~/Library/AutoPkg" 95 | 96 | defaults delete com.github.autopkg 97 | -------------------------------------------------------------------------------- /prepare_iso/support/pkg-postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | USER="__USER__PLACEHOLDER__" 3 | OSX_VERS=$(sw_vers -productVersion | awk -F "." '{print $2}') 4 | PlistBuddy="/usr/libexec/PlistBuddy" 5 | 6 | target_ds_node="${3}/private/var/db/dslocal/nodes/Default" 7 | # Override the default behavior of sshd on the target volume to be not disabled 8 | if [ "$OSX_VERS" -ge 10 ]; then 9 | OVERRIDES_PLIST="$3/private/var/db/com.apple.xpc.launchd/disabled.plist" 10 | $PlistBuddy -c 'Delete :com.openssh.sshd' "$OVERRIDES_PLIST" 11 | $PlistBuddy -c 'Add :com.openssh.sshd bool False' "$OVERRIDES_PLIST" 12 | if [ __DISABLE_SCREEN_SHARING__ = 0 ]; then 13 | $PlistBuddy -c 'Delete :com.apple.screensharing' "$OVERRIDES_PLIST" 14 | $PlistBuddy -c 'Add :com.apple.screensharing bool False' "$OVERRIDES_PLIST" 15 | fi 16 | else 17 | OVERRIDES_PLIST="$3/private/var/db/launchd.db/com.apple.launchd/overrides.plist" 18 | $PlistBuddy -c 'Delete :com.openssh.sshd' "$OVERRIDES_PLIST" 19 | $PlistBuddy -c 'Add :com.openssh.sshd:Disabled bool False' "$OVERRIDES_PLIST" 20 | if [ __DISABLE_SCREEN_SHARING__ = 0 ]; then 21 | $PlistBuddy -c 'Delete :com.apple.screensharing' "$OVERRIDES_PLIST" 22 | $PlistBuddy -c 'Add :com.apple.screensharing:Disabled bool False' "$OVERRIDES_PLIST" 23 | fi 24 | fi 25 | 26 | # Add user to sudoers 27 | cp "$3/etc/sudoers" "$3/etc/sudoers.orig" 28 | echo "$USER ALL=(ALL) NOPASSWD: ALL" >> "$3/etc/sudoers" 29 | 30 | # Add user to admin group memberships (even though GID 80 is enough for most things) 31 | USER_GUID=$($PlistBuddy -c 'Print :generateduid:0' "$target_ds_node/users/$USER.plist") 32 | USER_UID=$($PlistBuddy -c 'Print :uid:0' "$target_ds_node/users/$USER.plist") 33 | $PlistBuddy -c 'Add :groupmembers: string '"$USER_GUID" "$target_ds_node/groups/admin.plist" 34 | 35 | # Add user to SSH SACL group membership 36 | ssh_group="${target_ds_node}/groups/com.apple.access_ssh.plist" 37 | $PlistBuddy -c 'Add :groupmembers array' "${ssh_group}" 38 | $PlistBuddy -c 'Add :groupmembers:0 string '"$USER_GUID"'' "${ssh_group}" 39 | $PlistBuddy -c 'Add :users array' "${ssh_group}" 40 | $PlistBuddy -c 'Add :users:0 string '$USER'' "${ssh_group}" 41 | 42 | # Enable Remote Desktop and configure user with full privileges 43 | if [ __DISABLE_REMOTE_MANAGEMENT__ = 0 ]; then 44 | echo "enabled" > "$3/private/etc/RemoteManagement.launchd" 45 | $PlistBuddy -c 'Add :naprivs array' "$target_ds_node/users/$USER.plist" 46 | $PlistBuddy -c 'Add :naprivs:0 string -1073741569' "$target_ds_node/users/$USER.plist" 47 | fi 48 | 49 | if [ __DISABLE_SIP__ = 1 ]; then 50 | csrutil disable 51 | fi 52 | 53 | # Pre-create user folder so veewee will have somewhere to scp configinfo to 54 | mkdir -p "$3/Users/$USER/Library/Preferences" 55 | 56 | # Suppress annoying iCloud welcome on a GUI login 57 | $PlistBuddy -c 'Add :DidSeeCloudSetup bool true' "$3/Users/$USER/Library/Preferences/com.apple.SetupAssistant.plist" 58 | $PlistBuddy -c 'Add :LastSeenCloudProductVersion string 10.'"$OSX_VERS" "$3/Users/$USER/Library/Preferences/com.apple.SetupAssistant.plist" 59 | $PlistBuddy -c 'Add :DidSeeSiriSetup bool true' "$3/Users/$USER/Library/Preferences/com.apple.SetupAssistant.plist" 60 | 61 | # Fix ownership now that the above has made a Library folder as root 62 | chown -R "$USER_UID":20 "$3/Users/$USER" 63 | 64 | # Disable Diagnostics submissions prompt if 10.10 65 | # http://macops.ca/diagnostics-prompt-yosemite 66 | if [ "$OSX_VERS" -ge 10 ]; then 67 | # Apple's defaults 68 | SUBMIT_TO_APPLE=YES 69 | SUBMIT_TO_APP_DEVELOPERS=NO 70 | 71 | CRASHREPORTER_SUPPORT="$3/Library/Application Support/CrashReporter" 72 | CRASHREPORTER_DIAG_PLIST="${CRASHREPORTER_SUPPORT}/DiagnosticMessagesHistory.plist" 73 | if [ ! -d "${CRASHREPORTER_SUPPORT}" ]; then 74 | mkdir "${CRASHREPORTER_SUPPORT}" 75 | chmod 775 "${CRASHREPORTER_SUPPORT}" 76 | chown root:admin "${CRASHREPORTER_SUPPORT}" 77 | fi 78 | for key in AutoSubmit AutoSubmitVersion ThirdPartyDataSubmit ThirdPartyDataSubmitVersion; do 79 | $PlistBuddy -c "Delete :$key" "${CRASHREPORTER_DIAG_PLIST}" 2> /dev/null 80 | done 81 | $PlistBuddy -c "Add :AutoSubmit bool ${SUBMIT_TO_APPLE}" "${CRASHREPORTER_DIAG_PLIST}" 82 | $PlistBuddy -c "Add :AutoSubmitVersion integer 4" "${CRASHREPORTER_DIAG_PLIST}" 83 | $PlistBuddy -c "Add :ThirdPartyDataSubmit bool ${SUBMIT_TO_APP_DEVELOPERS}" "${CRASHREPORTER_DIAG_PLIST}" 84 | $PlistBuddy -c "Add :ThirdPartyDataSubmitVersion integer 4" "${CRASHREPORTER_DIAG_PLIST}" 85 | fi 86 | 87 | # Disable loginwindow screensaver to save CPU cycles 88 | $PlistBuddy -c 'Add :loginWindowIdleTime integer 0' "$3/Library/Preferences/com.apple.screensaver.plist" 89 | 90 | # Disable the welcome screen 91 | touch "$3/private/var/db/.AppleSetupDone" 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # packer-osx 2 | 3 | This is a set of [Packer][] templates and scripts to help automate the 4 | installation of OS X. It's based off of [timsutton/osx-vm-templates][]. 5 | 6 | ## Usage 7 | 8 | This set of scripts supports all versions of OS X that are distributed through 9 | the App Store: OS X Lion (10.7) through El Capitan (10.11), and macOS Sierra 10 | (10.12). 11 | 12 | This fork has a few templates to support different use cases: 13 | 14 | * `vagrant.json` 15 | * `standalone.json` 16 | 17 | ### Preparing the ISO 18 | 19 | `prepare_iso.sh` builds a custom ISO image which has been modified to automate 20 | the install. 21 | 22 | Run the `prepare_iso.sh` script with two arguments: the path to an `Install OS 23 | X.app` or the `InstallESD.dmg` contained within, and an output directory. Root 24 | privileges are required in order to write a new DMG with the correct file 25 | ownerships. For example, with a 10.8.4 Mountain Lion installer: 26 | 27 | ``` 28 | sudo prepare_iso/prepare_iso.sh "/Applications/Install OS X El Capitan.app" iso 29 | ``` 30 | 31 | ...should output progress information ending in something this: 32 | 33 | ``` 34 | -- MD5: dc93ded64396574897a5f41d6dd7066c 35 | -- Done. Built image is located at iso/OSX_InstallESD_10.11.6_15G31.dmg. 36 | ``` 37 | 38 | `prepare_iso.sh` accepts command line switches to modify the details of the 39 | admin user installed by the script. 40 | 41 | * `-u` modifies the name of the admin account, defaults to `vagrant` 42 | * `-p` modifies the password of the same account, defaults to `vagrant` 43 | * `-i` sets the path of the account's avatar image, defaults to 44 | `prepare_iso/support/vagrant.jpg` 45 | 46 | For example: 47 | 48 | ``` 49 | sudo prepare_iso/prepare_iso.sh -u admin -p password -i /path/to/image.jpg \ 50 | "/Applications/Install OS X El Capitan.app" iso 51 | ``` 52 | 53 | Additionally, flags can be set to disable certain default configuration options. 54 | 55 | * `-D DISABLE_REMOTE_MANAGEMENT` disables the Remote Management service. 56 | * `-D DISABLE_SCREEN_SHARING` disables the Screen Sharing service. 57 | 58 | ### Building with Packer 59 | 60 | The templates include a set of additional VM options that are needed for OS X 61 | guests. The output ISO can be passed to Packer in a user variable. 62 | 63 | ```sh 64 | packer build \ 65 | -var iso_url=iso/OSX_InstallESD_10.11.6_15G31.dmg \ 66 | template.json 67 | ``` 68 | 69 | You might also use the `-only` option to restrict to either the `vmware-iso` or 70 | `virtualbox-iso` builders. 71 | 72 | #### Configuration Options 73 | 74 | The installation is automated inside the disk image, so there is little inside 75 | the Packer template itself. However, the provisioning scripts have a few 76 | options: 77 | 78 | ##### Username & Password 79 | 80 | ``` 81 | -var username=youruser \ 82 | -var password=yourpassword \ 83 | ``` 84 | 85 | ##### Automated GUI logins 86 | 87 | If you need to attach to a login session, this will cause the user to 88 | automatically login: 89 | 90 | `packer build -var autologin=true template.json` 91 | 92 | ##### Vagrant 93 | 94 | ``` 95 | packer build -var install_vagrant_keys=false template.json 96 | ``` 97 | 98 | ##### Chef & Puppet 99 | 100 | By default, the template doesn't install Chef or Puppet. To enable this, set 101 | the version to `latest`, or to a specific version: 102 | 103 | ``` 104 | packer build -var chef_version=latest template.json 105 | ``` 106 | 107 | ``` 108 | packer build -var puppet_version=latest template.json 109 | ``` 110 | 111 | ##### Xcode CLI Tools 112 | 113 | The Xcode CLI tools are installed by the packer template by default. To disable 114 | the installation, set the `install_xcode_cli_tools` variable to `false`: 115 | 116 | ``` 117 | packer build -var install_xcode_cli_tools=false template.json 118 | ``` 119 | 120 | ##### System updates 121 | 122 | Packer will instruct the system to download and install all available OS X 123 | updates, if you want to disable this default behaviour, use `update_system` 124 | variable: 125 | 126 | ``` 127 | packer build -var update_system=0 template.json 128 | ``` 129 | 130 | ##### Provisioning delay 131 | 132 | In some cases, it may be helpful to insert a delay into the beginning of the 133 | provisioning process. Adding a delay of about 30 seconds may help subsequent 134 | provisioning steps that install software from the internet complete 135 | successfully. By default, the delay is set to `0`, but you can change the delay 136 | by setting the `provisioning_delay` variable: 137 | 138 | ``` 139 | packer build -var provisioning_delay=30 template.json` 140 | ``` 141 | 142 | [Packer]: https://packer.io 143 | [timsutton/osx-vm-templates]: https://github.com/timsutton/osx-vm-templates 144 | -------------------------------------------------------------------------------- /vagrant.json: -------------------------------------------------------------------------------- 1 | { 2 | "builders": [ 3 | { 4 | "boot_wait": "5s", 5 | "disk_size": 40960, 6 | "guest_os_type": "win-8", 7 | "iso_checksum_type": "none", 8 | "iso_url": "{{user `iso_url`}}", 9 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 10 | "ssh_port": 22, 11 | "ssh_username": "{{user `username`}}", 12 | "ssh_password": "{{user `password`}}", 13 | "ssh_wait_timeout": "10000s", 14 | "parallels_tools_flavor": "mac", 15 | "type": "parallels-iso", 16 | "prlctl": [ 17 | ["set", "{{.Name}}", "--memsize", "4096"], 18 | ["set", "{{.Name}}", "--cpus", "2"], 19 | ["set", "{{.Name}}", "--distribution", "macosx"], 20 | ["set", "{{.Name}}", "--3d-accelerate", "highest"], 21 | ["set", "{{.Name}}", "--high-resolution", "off"], 22 | ["set", "{{.Name}}", "--auto-share-camera", "off"], 23 | ["set", "{{.Name}}", "--auto-share-bluetooth", "off"], 24 | ["set", "{{.Name}}", "--on-window-close", "keep-running"], 25 | ["set", "{{.Name}}", "--shf-host", "off"] 26 | ] 27 | }, 28 | { 29 | "boot_wait": "2s", 30 | "disk_size": 40960, 31 | "guest_os_type": "darwin12-64", 32 | "iso_checksum_type": "none", 33 | "iso_url": "{{user `iso_url`}}", 34 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 35 | "skip_compaction": true, 36 | "ssh_port": 22, 37 | "ssh_username": "{{user `username`}}", 38 | "ssh_password": "{{user `password`}}", 39 | "ssh_wait_timeout": "10000s", 40 | "tools_upload_flavor": "darwin", 41 | "type": "vmware-iso", 42 | "vmx_data": { 43 | "cpuid.coresPerSocket": "1", 44 | "memsize": "4096", 45 | "numvcpus": "2", 46 | "firmware": "efi", 47 | "keyboardAndMouseProfile": "macProfile", 48 | "smc.present": "TRUE", 49 | "hpet0.present": "TRUE", 50 | "ich7m.present": "TRUE", 51 | "ehci.present": "TRUE", 52 | "usb.present": "TRUE" 53 | } 54 | }, 55 | { 56 | "boot_wait": "2s", 57 | "disk_size": 40960, 58 | "guest_additions_mode": "disable", 59 | "guest_os_type": "MacOS1011_64", 60 | "hard_drive_interface": "sata", 61 | "iso_checksum_type": "none", 62 | "iso_interface": "sata", 63 | "iso_url": "{{user `iso_url`}}", 64 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 65 | "ssh_port": 22, 66 | "ssh_username": "{{user `username`}}", 67 | "ssh_password": "{{user `password`}}", 68 | "ssh_wait_timeout": "10000s", 69 | "type": "virtualbox-iso", 70 | "vboxmanage": [ 71 | ["modifyvm", "{{.Name}}", "--audiocontroller", "hda"], 72 | ["modifyvm", "{{.Name}}", "--boot1", "dvd"], 73 | ["modifyvm", "{{.Name}}", "--boot2", "disk"], 74 | ["modifyvm", "{{.Name}}", "--chipset", "ich9"], 75 | ["modifyvm", "{{.Name}}", "--firmware", "efi"], 76 | ["modifyvm", "{{.Name}}", "--hpet", "on"], 77 | ["modifyvm", "{{.Name}}", "--keyboard", "usb"], 78 | ["modifyvm", "{{.Name}}", "--memory", "4096"], 79 | ["modifyvm", "{{.Name}}", "--cpus", "2"] 80 | ["modifyvm", "{{.Name}}", "--mouse", "usbtablet"], 81 | ["modifyvm", "{{.Name}}", "--usbehci", "on"], 82 | ["modifyvm", "{{.Name}}", "--vram", "128"], 83 | ["storagectl", "{{.Name}}", "--name", "IDE Controller", "--remove"] 84 | ] 85 | } 86 | ], 87 | "min_packer_version": "0.7.0", 88 | "post-processors": [ 89 | "vagrant" 90 | ], 91 | "provisioners": [ 92 | { 93 | "type": "shell-local", 94 | "command": "sleep {{user `provisioning_delay`}}" 95 | }, 96 | { 97 | "destination": "/private/tmp/set_kcpassword.py", 98 | "source": "scripts/support/set_kcpassword.py", 99 | "type": "file" 100 | }, 101 | { 102 | "execute_command": "chmod +x {{ .Path }}; sudo {{ .Vars }} {{ .Path }}", 103 | "scripts": [ 104 | "scripts/vagrant.sh", 105 | "scripts/vmware.sh", 106 | "scripts/parallels.sh", 107 | "scripts/xcode-cli-tools.sh", 108 | "scripts/chef-omnibus.sh", 109 | "scripts/puppet.sh", 110 | "scripts/add-network-interface-detection.sh", 111 | "scripts/autologin.sh", 112 | "scripts/system-update.sh", 113 | "scripts/shrink.sh" 114 | ], 115 | "environment_vars": [ 116 | "AUTOLOGIN={{user `autologin`}}", 117 | "CHEF_VERSION={{user `chef_version`}}", 118 | "FACTER_VERSION={{user `facter_version`}}", 119 | "HIERA_VERSION={{user `hiera_version`}}", 120 | "INSTALL_VAGRANT_KEYS={{user `install_vagrant_keys`}}", 121 | "NOCM={{user `nocm`}}", 122 | "INSTALL_XCODE_CLI_TOOLS={{user `install_xcode_cli_tools`}}", 123 | "PASSWORD={{user `password`}}", 124 | "PUPPET_VERSION={{user `puppet_version`}}", 125 | "PUPPET_AGENT_VERSION={{user `puppet_agent_version`}}", 126 | "UPDATE_SYSTEM={{user `update_system`}}", 127 | "USERNAME={{user `username`}}" 128 | ], 129 | "type": "shell" 130 | } 131 | ], 132 | "variables": { 133 | "autologin": "false", 134 | "chef_version": "none", 135 | "facter_version": "none", 136 | "hiera_version": "none", 137 | "install_vagrant_keys": "true", 138 | "install_xcode_cli_tools": "true", 139 | "iso_url": "OSX_InstallESD_10.11.1_15B42.dmg", 140 | "password": "vagrant", 141 | "provisioning_delay": "0", 142 | "puppet_version": "none", 143 | "puppet_agent_version": "none", 144 | "update_system": "true", 145 | "username": "vagrant" 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /standalone.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": { 3 | "iso_url": "OSX_InstallESD_10.11.1_15B42.dmg", 4 | "provisioning_delay": "0", 5 | "username": "vagrant", 6 | "password": "vagrant", 7 | "autologin": "false", 8 | "update_system": "true", 9 | "install_xcode_cli_tools": "true", 10 | 11 | "chef_version": "none", 12 | "facter_version": "none", 13 | "hiera_version": "none", 14 | "puppet_version": "none", 15 | "puppet_agent_version": "none" 16 | }, 17 | 18 | "builders": [ 19 | { 20 | "vm_name": "osx-standalone-parallels", 21 | "type": "parallels-iso", 22 | "guest_os_type": "win-8", 23 | "parallels_tools_flavor": "mac", 24 | 25 | "iso_url": "{{user `iso_url`}}", 26 | "iso_checksum_type": "none", 27 | 28 | "ssh_username": "{{user `username`}}", 29 | "ssh_password": "{{user `password`}}", 30 | "ssh_wait_timeout": "10000s", 31 | 32 | "boot_wait": "5s", 33 | "disk_size": 40960, 34 | 35 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 36 | 37 | "keep_registered": true, 38 | 39 | "prlctl": [ 40 | ["set", "{{.Name}}", "--memsize", "4096"], 41 | ["set", "{{.Name}}", "--cpus", "2"], 42 | ["set", "{{.Name}}", "--distribution", "macosx"], 43 | ["set", "{{.Name}}", "--3d-accelerate", "highest"], 44 | ["set", "{{.Name}}", "--high-resolution", "off"], 45 | ["set", "{{.Name}}", "--auto-share-camera", "off"], 46 | ["set", "{{.Name}}", "--auto-share-bluetooth", "off"], 47 | ["set", "{{.Name}}", "--on-window-close", "keep-running"], 48 | ["set", "{{.Name}}", "--shf-host", "off"] 49 | ] 50 | }, 51 | { 52 | "vm_name": "osx-standalone-vmware", 53 | "type": "vmware-iso", 54 | "guest_os_type": "darwin12-64", 55 | "tools_upload_flavor": "darwin", 56 | 57 | "iso_url": "{{user `iso_url`}}", 58 | "iso_checksum_type": "none", 59 | 60 | "ssh_username": "{{user `username`}}", 61 | "ssh_password": "{{user `password`}}", 62 | "ssh_wait_timeout": "10000s", 63 | 64 | "boot_wait": "2s", 65 | "disk_size": 40960, 66 | 67 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 68 | 69 | "keep_registered": true, 70 | "skip_compaction": true, 71 | 72 | "vmx_data": { 73 | "cpuid.coresPerSocket": "1", 74 | "memsize": "4096", 75 | "numvcpus": "2", 76 | "firmware": "efi", 77 | "keyboardAndMouseProfile": "macProfile", 78 | "smc.present": "TRUE", 79 | "hpet0.present": "TRUE", 80 | "ich7m.present": "TRUE", 81 | "ehci.present": "TRUE", 82 | "usb.present": "TRUE" 83 | } 84 | }, 85 | { 86 | "vm_name": "osx-standalone-virtualbox", 87 | "type": "virtualbox-iso", 88 | "guest_os_type": "MacOS1011_64", 89 | "guest_additions_mode": "disable", 90 | 91 | "iso_url": "{{user `iso_url`}}", 92 | "iso_checksum_type": "none", 93 | 94 | "ssh_username": "{{user `username`}}", 95 | "ssh_password": "{{user `password`}}", 96 | 97 | "ssh_wait_timeout": "10000s", 98 | "boot_wait": "2s", 99 | "disk_size": 40960, 100 | "iso_interface": "sata", 101 | "hard_drive_interface": "sata", 102 | 103 | "shutdown_command": "echo '{{user `username`}}'|sudo -S shutdown -h now", 104 | 105 | "keep_registered": true, 106 | 107 | "vboxmanage": [ 108 | ["modifyvm", "{{.Name}}", "--audiocontroller", "hda"], 109 | ["modifyvm", "{{.Name}}", "--boot1", "dvd"], 110 | ["modifyvm", "{{.Name}}", "--boot2", "disk"], 111 | ["modifyvm", "{{.Name}}", "--chipset", "ich9"], 112 | ["modifyvm", "{{.Name}}", "--firmware", "efi"], 113 | ["modifyvm", "{{.Name}}", "--hpet", "on"], 114 | ["modifyvm", "{{.Name}}", "--keyboard", "usb"], 115 | ["modifyvm", "{{.Name}}", "--memory", "4096"], 116 | ["modifyvm", "{{.Name}}", "--cpus", "2"], 117 | ["modifyvm", "{{.Name}}", "--mouse", "usbtablet"], 118 | ["modifyvm", "{{.Name}}", "--usbehci", "on"], 119 | ["modifyvm", "{{.Name}}", "--vram", "128"], 120 | ["storagectl", "{{.Name}}", "--name", "IDE Controller", "--remove"] 121 | ] 122 | } 123 | ], 124 | 125 | "provisioners": [ 126 | { 127 | "type": "shell-local", 128 | "command": "sleep {{user `provisioning_delay`}}" 129 | }, 130 | { 131 | "destination": "/private/tmp/set_kcpassword.py", 132 | "source": "scripts/support/set_kcpassword.py", 133 | "type": "file" 134 | }, 135 | { 136 | "type": "shell", 137 | "environment_vars": [ 138 | "USERNAME={{user `username`}}", 139 | "PASSWORD={{user `password`}}", 140 | "AUTOLOGIN={{user `autologin`}}", 141 | "UPDATE_SYSTEM={{user `update_system`}}", 142 | "INSTALL_XCODE_CLI_TOOLS={{user `install_xcode_cli_tools`}}", 143 | "CHEF_VERSION={{user `chef_version`}}", 144 | "FACTER_VERSION={{user `facter_version`}}", 145 | "HIERA_VERSION={{user `hiera_version`}}", 146 | "PUPPET_VERSION={{user `puppet_version`}}", 147 | "PUPPET_AGENT_VERSION={{user `puppet_agent_version`}}" 148 | ], 149 | "scripts": [ 150 | "scripts/post-install.sh", 151 | "scripts/vmware.sh", 152 | "scripts/parallels.sh", 153 | 154 | "scripts/xcode-cli-tools.sh", 155 | "scripts/chef-omnibus.sh", 156 | "scripts/puppet.sh", 157 | 158 | "scripts/add-network-interface-detection.sh", 159 | "scripts/autologin.sh", 160 | "scripts/system-update.sh", 161 | "scripts/shrink.sh" 162 | ], 163 | 164 | "execute_command": "chmod +x {{ .Path }}; sudo {{ .Vars }} {{ .Path }}" 165 | } 166 | ] 167 | } 168 | -------------------------------------------------------------------------------- /prepare_iso/prepare_iso.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # Preparation script for an OS X automated installation for use with VeeWee/Packer/Vagrant 4 | # 5 | # What the script does, in more detail: 6 | # 7 | # 1. Mounts the InstallESD.dmg using a shadow file, so the original DMG is left 8 | # unchanged. 9 | # 2. Modifies the BaseSystem.dmg within in order to add an additional 'rc.cdrom.local' 10 | # file in /etc, which is a supported local configuration sourced in at boot time 11 | # by the installer environment. This file contains instructions to erase and format 12 | # 'disk0', presumably the hard disk attached to the VM. 13 | # 3. A 'veewee-config.pkg' installer package is built, which is added to the OS X 14 | # install by way of the OSInstall.collection file. This package creates the 15 | # 'vagrant' user, configures sshd and sudoers, and disables setup assistants. 16 | # 4. veewee-config.pkg and the various support utilities are copied, and the disk 17 | # image is saved to the output path. 18 | # 19 | # Thanks: 20 | # Idea and much of the implementation thanks to Pepijn Bruienne, who's also provided 21 | # some process notes here: https://gist.github.com/4542016. The sample minstallconfig.xml, 22 | # use of OSInstall.collection and readme documentation provided with Greg Neagle's 23 | # createOSXInstallPkg tool also proved very helpful. (http://code.google.com/p/munki/wiki/InstallingOSX) 24 | # 25 | # User creation via package install method also credited to Greg, and made easy with Per 26 | # Olofsson's CreateUserPkg (http://magervalp.github.io/CreateUserPkg) 27 | # 28 | # Antony Blakey for updates to support OS X 10.11: 29 | # https://github.com/timsutton/osx-vm-templates/issues/40 30 | 31 | usage() { 32 | cat < 44 | Sets the username of the root user, defaults to 'vagrant'. 45 | 46 | -p 47 | Sets the password of the root user, defaults to 'vagrant'. 48 | 49 | -i 50 | Sets the path of the avatar image for the root user, defaulting to the vagrant icon. 51 | 52 | -D 53 | Sets the specified flag. Valid flags are: 54 | DISABLE_REMOTE_MANAGEMENT 55 | DISABLE_SCREEN_SHARING 56 | DISABLE_SIP 57 | 58 | EOF 59 | } 60 | 61 | cleanup() { 62 | hdiutil detach -quiet -force "$MNT_ESD" || echo > /dev/null 63 | hdiutil detach -quiet -force "$MNT_BASE_SYSTEM" || echo > /dev/null 64 | rm -rf "$MNT_ESD" "$MNT_BASE_SYSTEM" "$BASE_SYSTEM_DMG_RW" "$SHADOW_FILE" 65 | } 66 | 67 | trap cleanup EXIT INT TERM 68 | 69 | 70 | msg_status() { 71 | echo "\033[0;32m-- $1\033[0m" 72 | } 73 | msg_error() { 74 | echo "\033[0;31m-- $1\033[0m" 75 | } 76 | 77 | render_template() { 78 | eval "echo \"$(cat "$1")\"" 79 | } 80 | 81 | if [ $# -eq 0 ]; then 82 | usage 83 | exit 1 84 | fi 85 | 86 | SCRIPT_DIR="$(cd "$(dirname "$0")"; pwd)" 87 | SUPPORT_DIR="$SCRIPT_DIR/support" 88 | 89 | # Parse the optional command line switches 90 | USER="vagrant" 91 | PASSWORD="vagrant" 92 | IMAGE_PATH="$SUPPORT_DIR/vagrant.jpg" 93 | 94 | # Flags 95 | DISABLE_REMOTE_MANAGEMENT=0 96 | DISABLE_SCREEN_SHARING=0 97 | DISABLE_SIP=0 98 | 99 | while getopts u:p:i:D: OPT; do 100 | case "$OPT" in 101 | u) 102 | USER="$OPTARG" 103 | ;; 104 | p) 105 | PASSWORD="$OPTARG" 106 | ;; 107 | i) 108 | IMAGE_PATH="$OPTARG" 109 | ;; 110 | D) 111 | if [ x${!OPTARG} = x0 ]; then 112 | eval $OPTARG=1 113 | elif [ x${!OPTARG} != x1 ]; then 114 | msg_error "Unknown flag: ${OPTARG}" 115 | usage 116 | exit 1 117 | fi 118 | ;; 119 | \?) 120 | usage 121 | exit 1 122 | ;; 123 | esac 124 | done 125 | 126 | # Remove the switches we parsed above. 127 | shift $(expr $OPTIND - 1) 128 | 129 | if [ $(id -u) -ne 0 ]; then 130 | msg_error "This script must be run as root, as it saves a disk image with ownerships enabled." 131 | exit 1 132 | fi 133 | 134 | ESD="$1" 135 | if [ ! -e "$ESD" ]; then 136 | msg_error "Input installer image $ESD could not be found! Exiting.." 137 | exit 1 138 | fi 139 | 140 | if [ -d "$ESD" ]; then 141 | # we might be an install .app 142 | if [ -e "$ESD/Contents/SharedSupport/InstallESD.dmg" ]; then 143 | ESD="$ESD/Contents/SharedSupport/InstallESD.dmg" 144 | else 145 | msg_error "Can't locate an InstallESD.dmg in this source location $ESD!" 146 | fi 147 | fi 148 | 149 | VEEWEE_DIR="$(cd "$SCRIPT_DIR/../../../"; pwd)" 150 | VEEWEE_UID=$(/usr/bin/stat -f %u "$VEEWEE_DIR") 151 | VEEWEE_GID=$(/usr/bin/stat -f %g "$VEEWEE_DIR") 152 | DEFINITION_DIR="$(cd "$SCRIPT_DIR/.."; pwd)" 153 | 154 | if [ "$2" = "" ]; then 155 | msg_error "Currently an explicit output directory is required as the second argument." 156 | exit 1 157 | # The rest is left over from the old prepare_veewee_iso.sh script. Not sure if we 158 | # should leave in this functionality to automatically locate the veewee directory. 159 | DEFAULT_ISO_DIR=1 160 | OLDPWD=$(pwd) 161 | cd "$SCRIPT_DIR" 162 | # default to the veewee/iso directory 163 | if [ ! -d "../../../iso" ]; then 164 | mkdir "../../../iso" 165 | chown $VEEWEE_UID:$VEEWEE_GID "../../../iso" 166 | fi 167 | OUT_DIR="$(cd "$SCRIPT_DIR"; cd ../../../iso; pwd)" 168 | cd "$OLDPWD" # Rest of script depends on being in the working directory if we were passed relative paths 169 | else 170 | OUT_DIR="$2" 171 | fi 172 | 173 | if [ ! -d "$OUT_DIR" ]; then 174 | msg_status "Destination dir $OUT_DIR doesn't exist, creating.." 175 | mkdir -p "$OUT_DIR" 176 | fi 177 | 178 | if [ -e "$ESD.shadow" ]; then 179 | msg_status "Removing old shadow file.." 180 | rm "$ESD.shadow" 181 | fi 182 | 183 | MNT_ESD=$(/usr/bin/mktemp -d /tmp/veewee-osx-esd.XXXX) 184 | SHADOW_FILE=$(/usr/bin/mktemp /tmp/veewee-osx-shadow.XXXX) 185 | rm "$SHADOW_FILE" 186 | msg_status "Attaching input OS X installer image with shadow file.." 187 | hdiutil attach "$ESD" -mountpoint "$MNT_ESD" -shadow "$SHADOW_FILE" -nobrowse -owners on 188 | if [ $? -ne 0 ]; then 189 | [ ! -e "$ESD" ] && msg_error "Could not find $ESD in $(pwd)" 190 | msg_error "Could not mount $ESD on $MNT_ESD" 191 | exit 1 192 | fi 193 | 194 | msg_status "Mounting BaseSystem.." 195 | BASE_SYSTEM_DMG="$MNT_ESD/BaseSystem.dmg" 196 | MNT_BASE_SYSTEM=$(/usr/bin/mktemp -d /tmp/veewee-osx-basesystem.XXXX) 197 | [ ! -e "$BASE_SYSTEM_DMG" ] && msg_error "Could not find BaseSystem.dmg in $MNT_ESD" 198 | hdiutil attach "$BASE_SYSTEM_DMG" -mountpoint "$MNT_BASE_SYSTEM" -nobrowse -owners on 199 | if [ $? -ne 0 ]; then 200 | msg_error "Could not mount $BASE_SYSTEM_DMG on $MNT_BASE_SYSTEM" 201 | exit 1 202 | fi 203 | SYSVER_PLIST_PATH="$MNT_BASE_SYSTEM/System/Library/CoreServices/SystemVersion.plist" 204 | 205 | DMG_OS_VERS=$(/usr/libexec/PlistBuddy -c 'Print :ProductVersion' "$SYSVER_PLIST_PATH") 206 | DMG_OS_VERS_MAJOR=$(echo $DMG_OS_VERS | awk -F "." '{print $2}') 207 | DMG_OS_VERS_MINOR=$(echo $DMG_OS_VERS | awk -F "." '{print $3}') 208 | DMG_OS_BUILD=$(/usr/libexec/PlistBuddy -c 'Print :ProductBuildVersion' "$SYSVER_PLIST_PATH") 209 | msg_status "OS X version detected: 10.$DMG_OS_VERS_MAJOR.$DMG_OS_VERS_MINOR, build $DMG_OS_BUILD" 210 | 211 | OUTPUT_DMG="$OUT_DIR/OSX_InstallESD_${DMG_OS_VERS}_${DMG_OS_BUILD}.dmg" 212 | if [ -e "$OUTPUT_DMG" ]; then 213 | msg_error "Output file $OUTPUT_DMG already exists! We're not going to overwrite it, exiting.." 214 | hdiutil detach -force "$MNT_ESD" 215 | exit 1 216 | fi 217 | 218 | # Build our post-installation pkg that will create a user and enable ssh 219 | msg_status "Making firstboot installer pkg.." 220 | 221 | # payload items 222 | mkdir -p "$SUPPORT_DIR/pkgroot/private/var/db/dslocal/nodes/Default/users" 223 | mkdir -p "$SUPPORT_DIR/pkgroot/private/var/db/shadow/hash" 224 | BASE64_IMAGE=$(openssl base64 -in "$IMAGE_PATH") 225 | # Replace USER and BASE64_IMAGE in the user.plist file with the actual user and image 226 | render_template "$SUPPORT_DIR/user.plist" > "$SUPPORT_DIR/pkgroot/private/var/db/dslocal/nodes/Default/users/$USER.plist" 227 | USER_GUID=$(/usr/libexec/PlistBuddy -c 'Print :generateduid:0' "$SUPPORT_DIR/user.plist") 228 | # Generate a shadowhash from the supplied password 229 | "$SUPPORT_DIR/generate_shadowhash" "$PASSWORD" > "$SUPPORT_DIR/pkgroot/private/var/db/shadow/hash/$USER_GUID" 230 | 231 | # postinstall script 232 | mkdir -p "$SUPPORT_DIR/tmp/Scripts" 233 | cat "$SUPPORT_DIR/pkg-postinstall" \ 234 | | sed -e "s/__USER__PLACEHOLDER__/${USER}/" \ 235 | | sed -e "s/__DISABLE_REMOTE_MANAGEMENT__/${DISABLE_REMOTE_MANAGEMENT}/" \ 236 | | sed -e "s/__DISABLE_SCREEN_SHARING__/${DISABLE_SCREEN_SHARING}/" \ 237 | | sed -e "s/__DISABLE_SIP__/${DISABLE_SIP}/" \ 238 | > "$SUPPORT_DIR/tmp/Scripts/postinstall" 239 | chmod a+x "$SUPPORT_DIR/tmp/Scripts/postinstall" 240 | 241 | # build it 242 | BUILT_COMPONENT_PKG="$SUPPORT_DIR/tmp/veewee-config-component.pkg" 243 | BUILT_PKG="$SUPPORT_DIR/tmp/veewee-config.pkg" 244 | pkgbuild --quiet \ 245 | --root "$SUPPORT_DIR/pkgroot" \ 246 | --scripts "$SUPPORT_DIR/tmp/Scripts" \ 247 | --identifier com.vagrantup.veewee-config \ 248 | --version 0.1 \ 249 | "$BUILT_COMPONENT_PKG" 250 | productbuild \ 251 | --package "$BUILT_COMPONENT_PKG" \ 252 | "$BUILT_PKG" 253 | rm -rf "$SUPPORT_DIR/pkgroot" 254 | 255 | # We'd previously mounted this to check versions 256 | hdiutil detach "$MNT_BASE_SYSTEM" 257 | 258 | BASE_SYSTEM_DMG_RW="$(/usr/bin/mktemp /tmp/veewee-osx-basesystem-rw.XXXX).dmg" 259 | 260 | msg_status "Creating empty read-write DMG located at $BASE_SYSTEM_DMG_RW.." 261 | hdiutil create -o "$BASE_SYSTEM_DMG_RW" -size 10g -layout SPUD -fs HFS+J 262 | hdiutil attach "$BASE_SYSTEM_DMG_RW" -mountpoint "$MNT_BASE_SYSTEM" -nobrowse -owners on 263 | 264 | msg_status "Restoring ('asr restore') the BaseSystem to the read-write DMG.." 265 | # This asr restore was needed as of 10.11 DP7 and up. See 266 | # https://github.com/timsutton/osx-vm-templates/issues/40 267 | # 268 | # Note that when the restore completes, the volume is automatically re-mounted 269 | # and not with the '-nobrowse' option. It's an annoyance we could possibly fix 270 | # in the future.. 271 | asr restore --source "$BASE_SYSTEM_DMG" --target "$MNT_BASE_SYSTEM" --noprompt --noverify --erase 272 | rm -r "$MNT_BASE_SYSTEM" 273 | 274 | if [ $DMG_OS_VERS_MAJOR -ge 9 ]; then 275 | MNT_BASE_SYSTEM="/Volumes/OS X Base System" 276 | BASESYSTEM_OUTPUT_IMAGE="$OUTPUT_DMG" 277 | PACKAGES_DIR="$MNT_BASE_SYSTEM/System/Installation/Packages" 278 | 279 | rm "$PACKAGES_DIR" 280 | msg_status "Moving 'Packages' directory from the ESD to BaseSystem.." 281 | mv -v "$MNT_ESD/Packages" "$MNT_BASE_SYSTEM/System/Installation/" 282 | 283 | # This isn't strictly required for Mavericks, but Yosemite will consider the 284 | # installer corrupt if this isn't included, because it cannot verify BaseSystem's 285 | # consistency and perform a recovery partition verification 286 | msg_status "Copying in original BaseSystem dmg and chunklist.." 287 | cp "$MNT_ESD/BaseSystem.dmg" "$MNT_BASE_SYSTEM/" 288 | cp "$MNT_ESD/BaseSystem.chunklist" "$MNT_BASE_SYSTEM/" 289 | else 290 | MNT_BASE_SYSTEM="/Volumes/Mac OS X Base System" 291 | BASESYSTEM_OUTPUT_IMAGE="$MNT_ESD/BaseSystem.dmg" 292 | rm "$BASESYSTEM_OUTPUT_IMAGE" 293 | PACKAGES_DIR="$MNT_ESD/Packages" 294 | fi 295 | 296 | msg_status "Adding automated components.." 297 | CDROM_LOCAL="$MNT_BASE_SYSTEM/private/etc/rc.cdrom.local" 298 | cat > $CDROM_LOCAL << EOF 299 | diskutil eraseDisk jhfs+ "Macintosh HD" GPTFormat disk0 300 | if [ "\$?" == "1" ]; then 301 | diskutil eraseDisk jhfs+ "Macintosh HD" GPTFormat disk1 302 | fi 303 | EOF 304 | chmod a+x "$CDROM_LOCAL" 305 | mkdir "$PACKAGES_DIR/Extras" 306 | cp "$SUPPORT_DIR/minstallconfig.xml" "$PACKAGES_DIR/Extras/" 307 | cp "$SUPPORT_DIR/OSInstall.collection" "$PACKAGES_DIR/" 308 | cp "$BUILT_PKG" "$PACKAGES_DIR/" 309 | rm -rf "$SUPPORT_DIR/tmp" 310 | 311 | msg_status "Unmounting BaseSystem.." 312 | hdiutil detach "$MNT_BASE_SYSTEM" 313 | 314 | if [ $DMG_OS_VERS_MAJOR -lt 9 ]; then 315 | msg_status "Pre-Mavericks we save back the modified BaseSystem to the root of the ESD." 316 | hdiutil convert -format UDZO -o "$MNT_ESD/BaseSystem.dmg" "$BASE_SYSTEM_DMG_RW" 317 | fi 318 | 319 | msg_status "Unmounting ESD.." 320 | hdiutil detach "$MNT_ESD" 321 | 322 | if [ $DMG_OS_VERS_MAJOR -ge 9 ]; then 323 | msg_status "On Mavericks and later, the entire modified BaseSystem is our output dmg." 324 | hdiutil convert -format UDZO -o "$OUTPUT_DMG" "$BASE_SYSTEM_DMG_RW" 325 | else 326 | msg_status "Pre-Mavericks we're modifying the original ESD file." 327 | hdiutil convert -format UDZO -o "$OUTPUT_DMG" -shadow "$SHADOW_FILE" "$ESD" 328 | fi 329 | rm -rf "$MNT_ESD" "$SHADOW_FILE" 330 | 331 | if [ -n "$SUDO_UID" ] && [ -n "$SUDO_GID" ]; then 332 | msg_status "Fixing permissions.." 333 | chown -R $SUDO_UID:$SUDO_GID \ 334 | "$OUT_DIR" 335 | fi 336 | 337 | if [ -n "$DEFAULT_ISO_DIR" ]; then 338 | DEFINITION_FILE="$DEFINITION_DIR/definition.rb" 339 | msg_status "Setting ISO file in definition $DEFINITION_FILE.." 340 | ISO_FILE=$(basename "$OUTPUT_DMG") 341 | # Explicitly use -e in order to use double quotes around sed command 342 | sed -i -e "s/%OSX_ISO%/${ISO_FILE}/" "$DEFINITION_FILE" 343 | fi 344 | 345 | msg_status "Checksumming output image.." 346 | MD5=$(md5 -q "$OUTPUT_DMG") 347 | msg_status "MD5: $MD5" 348 | 349 | msg_status "Done. Built image is located at $OUTPUT_DMG. Add this iso and its checksum to your template." 350 | --------------------------------------------------------------------------------