Создание шаблонов ОС

Материал из ISPWiki
Перейти к: навигация, поиск

Иерархия: VMmanager KVM -> Шаблоны операционных систем
VMmanager Cloud -> Шаблоны операционных систем
DCImanager -> Шаблоны операционных систем
DCImanager Enterprise -> Шаблоны операционных систем

Шаблон ОС представляет из себя xml файл metainfo.xml и набор файлов для установки. В metainfo.xml описаны механизмы, которые будут использованы при установке. VMmanager и DCImanager используют данный тип шаблонов. Подготовленные нами шаблоны вы можете увидеть в нашем репозитории.

Список параметров

Все пути указываются относительно директории с шаблоном.

  • <kernel>Имя файла</kernel> - ядро Linux.
  • <initrd>Имя файла</initrd> - initrd
  • <kernelcommand>Параметры</kernelcommand> - параметры загрузки ядра. Пример - <kernelcommand>lang=en_US keymap=us ks=($OSINSTALLINFO_HTTP) method=http://mirror.yandex.ru/centos/6/os/x86_64/ initrd=initrd ip=($IP) netmask=($NETMASK) gateway=($GATEWAY) dns=($NAMESERVER)</kernelcommand>
  • <installdrive>Имя файла</installdrive> - к виртуальной машине присоединяется дополнительный диск, который представляет из себя любой файл, увеличенный до 1 мегабайта. При этом в нем можно использовать макросы. Данным способом мы рекомендуем устанавливать FreeBSD 9. Подробнее в статье по установке FreeBSD.("installdrive" используется только VMmanager-ом)
  • <installcfg>Имя файла</installcfg> - указывает, какой файл будет отдан при запросе по url ($OSINSTALLINFO_HTTP). При этом в нем можно использовать макросы.
  • <image>Имя файла</image> - ISO образ, который будет примонтирован как CDROM.
  • <tempipv4>yes</tempipv4> - для установки ОС с основным IPv6-адресом необходим временный IPv4-адрес.
  • <sharedir>Имя директории</sharedir> - директория внутри шаблона, файлы из которой будут доступны по http протоколу. Узнать ссылку можно через макросы.
  • <support><elem version='5.1.0'>vmmgr</elem><elem>dcimgr</elem></support> - говорит о том, какими продуктами поддерживается данный шаблон. version - минимальная версия панели управления.
  • <rebootcount>1</rebootcount> - количество перезагрузок, после которых VMmanager начинает считать, что операционная система установилась.
  • <illegal_password_characters>Запрещенные символы</illegal_password_characters> - Символы которые запрещено использовать в пароле.
  • <sshpublickey>yes</sshpublickey> - Шаблон поддерживает добавление публичных SSH ключей.
  • <up_mem_on_install>512</up_mem_on_install> - Во время инсталяции увеличивать оперативную память до этого значения. После того как ОС установится, количество памяти вернется к основному значению. Возможность работает только в VMmanager.
  • <virtionet>yes</virtionet> - Шаблон поддерживает работу с virtio сетью. Возможность работает только в VMmanager версии 5.4.0 и выше.
  • <virtiodisk>yes</virtiodisk> - Шаблон поддерживает работу с virtio дисками. Возможность работает только в VMmanager версии 5.4.0 и выше.
  • <chpasswd_method>mount.linux</chpasswd_method> - шаблон поддерживает смену пароля. В настоящее время реализован метод mount.linux для linux-шаблонов.
  • <loaderefi64>pxelinux.efi</loaderefi64> - шаблон поддерживает загрузку через UEFI (с версии 5.127).
  • <ipxeconf>ipxe.conf</ipxeconf> - конфигурационный файл для загрузки через iPXE (с версии 5.127).
  • <ipxeconf type="tftp"> - Привести строку filename для iPXE в конфигурационном файле dhcpd.conf к виду "tftp://10.10.10.10/.../ipxe.conf" (с версии 5.128).

Ограничения

В ноде limit описываются необходимые ограничения шаблона. При этом в VMmanager нельзя будет создать виртуальную машину с этим шаблоном, которая не будет удовлетворять ограничениям. Если лимиты не заданы, то проверка не производится.

  • ipv4 - Поддержка IPv4 как основной IP-адрес. yes/no
  • ipv6 - Поддержка IPv6 как основной IP-адрес. yes/no
  • mem - Минимально необходимый объем оперативной памяти в MiB.
  • disk - Минимально необходимый объем основного диска MB.

Пример:

 <limit>
 	<elem name="ipv4">yes</elem>
 	<elem name="ipv6">no</elem>
 	<elem name="mem">512</elem>
 	<elem name="disk">1500</elem>
 </limit>

Как создать свой шаблон

Для этого нужно создать папку в директории [NFS хранилище]/НАЗВАНИЕ_ВАШЕГО_ШАБЛОНА. Внутри должен обязательно содержаться файл metainfo.xml с XML описанием шаблона. Также в этой директории должны находиться все файлы, которые указаны в параметрах шаблона.

В описании шаблона необходимо добавить:

 <date>2013-04-14 15:37:21</date>
 <install_result>ok</install_result>

Это флаг того, что шаблон уже установлен. В примерах эти поля не указаны, т.к. описание представлено в формате, который используется для шаблонов в репозитории.

После проделанных действий вы увидите свой шаблон в меню добавления шаблонов ОС. Можете его уже добавить и использовать. Все изменения, которые вы сделаете в файлах шаблона, применяются сразу.

Как создать свой репозиторий

Создание собственного репозитория шаблонов ОС описано в соответствующей статье.

Примеры шаблонов

kickstart (Centos, Fedora, RedHat)

Для установки Centos мы рекомендуем использовать технологию kickstart. Она позволяет гибко настраивать параметры установки и легко менять параметры под собственные нужды. Для загрузки указывается kernel и initrd, а в команде ядра ссылка на файл ответов.

metainfo.xml

 <?xml version="1.0"?>
 <doc>
   <osname>CentOS-6-amd64</osname>
   <support>
     <elem>VMmgr</elem>
     <elem>IFXmgr</elem>
   </support>
   <rebootcount>1</rebootcount>
   <kernel>vmlinuz</kernel>
   <initrd>initrd.img</initrd>
   <type>ostemplate</type>
   <loader>pxelinux.0</loader>
   <pxelinuxcfg>pxelinux.conf</pxelinuxcfg>
   <tempipv4>yes</tempipv4>
   <kernelcommand>lang=en_US keymap=us ks=($OSINSTALLINFO_HTTPv4) ksdevice=link method=http://mirror.yandex.ru/centos/6/os/x86_64/ ip=($IPv4) netmask=($NETMASKv4) gateway=($GATEWAYv4) dns=($NAMESERVERv4) proxy=($HTTPPROXYv4) text</kernelcommand>
   <installcfg>install.cfg</installcfg>
   <limit>
     <elem name="ipv4">yes</elem>
     <elem name="ipv6">yes</elem>
     <elem name="mem">512</elem>
     <elem name="disk">2000</elem>
   </limit>
 </doc>

install.cfg

 %pre
 
 #!/bin/sh
 
 for disk in `ls -la /dev/sd?`; do
 	dd if=/dev/zero of=$disk bs=512 count=32
 done
 
 SWSIZE=$(grep MemTotal /proc/meminfo  | awk '{print int($2/1024)+1}')
 if [ ${SWSIZE} -gt 2048 ]; then
 	SWSIZE=2048
 fi
 
 if [ `cat /proc/scsi/scsi | grep -wc ATA` -eq 2 ]; then
  	set $(fdisk -l 2>/dev/null | grep -vi mapper | grep Disk | grep dev |  sed 's/://' | awk '{print $2}' | tr '\n' ' ')
  	HD1=$1
 	HD2=$2
 	if [ -b ${HD2} ]; then
 		SIZE1=$(fdisk -l "${HD1}"  2>/dev/null  | grep Disk | grep dev |  sed 's/://'|awk '{print $5}')
 		SIZE2=$(fdisk -l "${HD2}"  2>/dev/null  | grep Disk | grep dev |  sed 's/://'|awk '{print $5}')
 		if [ -n "${SIZE1}" ] && [ -n "${SIZE2}" ] && [ "${SIZE1}" = "${SIZE2}" ]; then
 			USE_MIRROR=yes
 		fi
 	fi
 fi
 
 if [ -n "${USE_MIRROR}" ]; then
 cat > /tmp/part-include << EOF
 part raid.11 --size=256 --asprimary --ondisk=sda
 part raid.12 --size=${SWSIZE} --asprimary --ondisk=sda 
 part raid.13 --size=1 --grow --asprimary --ondisk=sda 
 part raid.21 --size=256 --asprimary --ondisk=sdb
 part raid.22 --size=${SWSIZE} --asprimary --ondisk=sdb 
 part raid.23 --size=1 --grow --asprimary --ondisk=sdb
 raid /boot --fstype ext4 --device md0 --level=RAID1 raid.11 raid.21
 raid swap --fstype swap --device md1 --level=RAID1 raid.12 raid.22
 raid / --fstype ext4 --device md2 --level=RAID1 raid.13 raid.23
 EOF
 else
 cat > /tmp/part-include << EOF
 part /boot --fstype ext4 --size=256 --asprimary --ondisk=sda
 part swap --size=${SWSIZE} --asprimary --ondisk=sda
 part / --fstype ext4 --size=1 --grow --asprimary --ondisk=sda
 EOF
 fi
 
 %end
 auth --useshadow --enablemd5
 # Crete partition map
 bootloader --location=mbr
 zerombr
 clearpart --all --initlabel
 firstboot --disable
 # Disk partitioning information
 %include /tmp/part-include
 # System keyboard
 keyboard us
 # System language
 lang en_US.UTF-8
 # Installation logging level
 logging --level=info
 # Use NFS installation media
 url --url http://mirror.yandex.ru/centos/6/os/x86_64/
 #Root password
 rootpw ($PASS)
 # SELinux configuration
 selinux --disabled
 # Text installation
 text
 # System timezone
 timezone --utc Europe/Moscow
 
 # Network
 network --bootproto=static --ip=($IPv4) --netmask=($NETMASK)  --gateway=($GATEWAYv4) --nameserver=($NAMESERVERv4) --hostname=($HOSTNAME) --device=link
 
 # Install OS instead of upgrade
 install
 %packages
 @core
 %end
 
 %post
 # Настройка сети
 #echo "NETWORKING=yes" > /etc/sysconfig/network
 #echo "HOSTNAME=($HOSTNAME)"
 ETHDEV=$(ip route show | grep default | grep -Eo 'dev\ .+\ ' | awk '{print $2}')
 HWADDR=$(cat /etc/sysconfig/network-scripts/ifcfg-eth0 | awk -F= '/HWADDR/ {print $2}' | sed 's/"//g')
 UUID=$(cat /etc/sysconfig/network-scripts/ifcfg-eth0 | awk -F= '/UUID/ {print $2}' | sed 's/"//g')
 
 if [ -n "($IPv6)" ]; then
 cat > /etc/sysconfig/network << EOF
 NETWORKING=yes
 NETWORKING_IPV6=yes
 HOSTNAME=($HOSTNAME)
 IPV6_DEFAULTGW=($GATEWAY)
 EOF
 
 cat > /etc/sysconfig/network-scripts/ifcfg-${ETHDEV} << EOF
 DEVICE="${ETHDEV}"
 BOOTPROTO="static"
 DNS1="($NAMESERVER)"
 HWADDR="${HWADDR}"
 IPV6ADDR="($IPv6)/($NETMASKv6)"
 IPV6INIT="yes"
 IPV6_AUTOCONF="no"
 IPV6_DEFAULTGW="($GATEWAY)"
 NM_CONTROLLED="yes"
 ONBOOT="yes"
 TYPE="Ethernet"
 UUID="${UUID}"
 EOF
 
 fi
 %end
 
 %post --nochroot
 wget -O /dev/null --no-check-certificate "($FINISHv4)"
 # Reboot after installation
 %end
 
 reboot

FreeBSD 9

Установка производится за счет модифицированного образа установочного диска. В основе лежит bootonly.iso. Модифицируется файл /etc/rc.local который загружается после загрузки OS с диска.

Чтобы изменить настройки установленной системы (пароль, сеть, пакеты и т.п.) и чтобы при этом пользователям не приходилось самостоятельно модифицировать образ, мы используем следующий механизм. К виртуальной машине присоединяется дополнительный диск, который представляет из себя shell скрипт, увеличенный до 1 мегабайта. После запуска OS с диска запускается rc.local, который считывает все данные со второго жесткого диска и кладет их в /tmp/install.sh После чего запускает этот install.sh. В install.sh могут быть описаны любые действия.

Шаблон OS включает в себя скрипт install.sh, при этом в скрипте можно использовать макросы, вместо которых VMmanager подставит значения.

metainfo.xml

 <?xml version="1.0"?>
 <doc>
   <osname>FreeBSD-9-amd64</osname>
   <support>
     <elem>VMmgr</elem>
     <elem>IFXmgr</elem>
   </support>
   <image>freebsd.iso</image>
   <rebootcount>1</rebootcount>
   <type>ostemplate</type>
   <installdrive>freebsdinstall.sh</installdrive>
   <loader>pxelinux.0</loader>
   <pxelinuxcfg>pxelinux.conf</pxelinuxcfg>
   <installcfg>freebsdinstall.sh</installcfg>
   <initrd>freebsd.iso</initrd>
   <kernel>memdisk</kernel>
   <kernelcommand>iso raw</kernelcommand>
   <limit>
     <elem name="ipv4">yes</elem>
     <elem name="ipv6">yes</elem>
     <elem name="mem">512</elem>
     <elem name="disk">1500</elem>
   </limit>
 </doc>

freebsdinstall.sh

 #!/bin/sh
 
 WGET="fetch -o- -q "
 
 if [ "$START_BSD_INSTALL" != "yes" ]; then
 export START_BSD_INSTALL="yes"
 bsdinstall ../../../$0
 
 exit 0
 fi
 
 clear
 echo "Begin Installation at $(date)" | tee -a $BSDINSTALL_LOG
 
 2>>$BSDINSTALL_LOG
 
 error() {
 	${WGET} "($FAILURL)?error=$1"
 	exit 1
 } 
 
 rm -rf $BSDINSTALL_TMPETC
 mkdir $BSDINSTALL_TMPETC
 
 echo "Setting hostname..."
 HOSTNAME=($HOSTNAME)
 echo "hostname=\"$HOSTNAME\"" > $BSDINSTALL_TMPETC/rc.conf.hostname
 hostname -s "$HOSTNAME"
 
 echo "Configuring interfaces"
 echo "Detecting..."
 INTERFACES="${IFACE}"
 if [ -z "${INTERFACES}" ]; then
 	for IF in `ifconfig -l`; do
        test "$IF" = "lo0" && continue
        INTERFACES="$IF"
 	done
 fi
 if [ -z "$INTERFACES" ]; then
        dialog --backtitle 'FreeBSD Installer' \
            --title 'Network Configuration Error' \
            --msgbox 'No network interfaces present to configure.' 0 0
        exit 1
 fi
 
 if [ -n "($IPv6)" ]; then
 	echo "Configuring IPv6"
 	export http_proxy="($HTTPPROXYv6)"
 	export HTTP_PROXY="($HTTPPROXYv6)"
 	ifconfig $INTERFACES inet6 ($IPv6) prefixlen ($NETMASKv6)
 	route add -inet6 default ($GATEWAYv6)
 	echo "nameserver ($NAMESERVERv6)" >> /etc/resolv.conf
 
 	cat >> $BSDINSTALL_TMPETC/rc.conf.network << EOF
 ipv6_defaultrouter="($GATEWAYv6)"
 ifconfig_${INTERFACES}_ipv6="inet6 ($IPv6) prefixlen ($NETMASKv6)" 
 sshd_enable="YES"
 ipv6_all_interfaces="YES"
 EOF
 	echo "nameserver ($NAMESERVERv6)" >> $BSDINSTALL_TMPETC/resolv.conf
 elif [ -n "($IPv4)" ]; then
 	echo "Configuring IPv4"
 	export http_proxy="($HTTPPROXYv4)"
 	export HTTP_PROXY="($HTTPPROXYv4)"
 	ifconfig $INTERFACES inet ($IPv4) netmask ($NETMASKv4)
 	route add default ($GATEWAYv4)
 	echo "nameserver ($NAMESERVERv4)" >> /etc/resolv.conf
 	echo "name_servers=($NAMESERVERv4)" >> /etc/resolvconf.conf
 
 	cat >> $BSDINSTALL_TMPETC/rc.conf.network << EOF
 defaultrouter="($GATEWAYv4)"
 ifconfig_${INTERFACES}="inet ($IPv4) netmask ($NETMASKv4)" 
 sshd_enable="YES"
 EOF
 
 	echo "nameserver ($NAMESERVERv4)" >> $BSDINSTALL_TMPETC/resolv.conf
 fi
 sleep 5
 
 echo "Setting files for download"
 if [ "#$(uname -m)" = "#amd64" ]; then
        export DISTRIBUTIONS="base.txz kernel.txz lib32.txz"
 else
         export DISTRIBUTIONS="base.txz kernel.txz"
 fi
 
 FETCH_DISTRIBUTIONS=""
 for dist in $DISTRIBUTIONS; do
        if [ ! -f $BSDINSTALL_DISTDIR/$dist ]; then
                FETCH_DISTRIBUTIONS="$FETCH_DISTRIBUTIONS $dist"
        fi
 done
 FETCH_DISTRIBUTIONS=`echo $FETCH_DISTRIBUTIONS` # Trim white space
 
 MIRROR="http://mirror.yandex.ru/freebsd/snapshots"
 BSDVER="9.1-STABLE"
 
 BSDINSTALL_DISTSITE="$MIRROR/`uname -m`/`uname -p`/${BSDVER}"
 
 export BSDINSTALL_DISTSITE
 
 
 echo "Detecting disks"
 rm $PATH_FSTAB
 touch $PATH_FSTAB
 
 DISKS=`/sbin/sysctl -n kern.disks`
 if [ -n ${SKIP_HD} ]; then
 	DISKS=$(echo ${DISKS} | sed "s/${SKIP_HD}[ ]\{0,\}//")
 fi
 
 
 HD=${HD:-empty}
 if [ $HD = "empty" ]; then
  HD=`echo $DISKS | xargs -n1 echo | grep ar | sort -tr -k2 -n | head -1`
  if [ -z "$HD" ]; then
    HD=`echo $DISKS | xargs -n1 echo | grep ad | sort -td -k2 -n | head -1`
    if [ -z "$HD" ]; then
      HD=`echo $DISKS | xargs -n1 echo | grep da | sort -ta -k2 -n | head -1`
      if [ -z "$HD" ]; then
        HD=`echo $DISKS | /usr/bin/cut -d ' ' -f1`
        if [ -z "$HD" ]; then
          exit 1
        fi
      fi
    fi
  fi
 else
  if [ ! -b /dev/$HD ]; then
    # Hard disk device with this name not found
    # Terminate install with error
    error "disknodetect"
  fi
 fi
 
 DISK_TYPE=$(echo ${HD} | sed -e 's/[0-9]\{1,\}.*$//g')
 echo "Disk type: ${DISK_TYPE}"
 
 if [ $(echo ${DISKS} | grep -Eo "${DISK_TYPE}[0-9]" | wc -l) -eq 2 ]; then
 # Mirror
 	HDDS=$(echo ${DISKS} | grep -Eo "${DISK_TYPE}[0-9]")
 	echo "${HDDS}"
 	set ${HDDS}
 	HD1=$1
 	HD2=$2
 	echo "Disk1: ${HD1}"
 	echo "Disk2: ${HD2}"
 	SIZE1=$(grep -Eio "^${HD1}: [0-9]{1,}(mb|gb|tb|b) " /var/run/dmesg.boot | awk '{print $2}')
 	SIZE2=$(grep -Eio "^${HD2}: [0-9]{1,}(mb|gb|tb|b) " /var/run/dmesg.boot | awk '{print $2}')
 
 	grep -Eio "^${HD1}: [0-9]{1,}(mb|gb|tb|b) " /var/run/dmesg.boot
 	echo "Disk1 size: ${SIZE1}"
 	grep -Eio "^${HD2}: [0-9]{1,}(mb|gb|tb|b) " /var/run/dmesg.boot
 	echo "Disk2 size: ${SIZE2}"
 
 	if [ -n "${SIZE1}" ] && [ -n "${SIZE2}" ] && [ "${SIZE1}" = "${SIZE2}" ]; then
 		echo "This is miroor system"
 		GMIRROR=yes
 	else
 		echo "Disks size is differ"
 		echo "This is single system"
 		HDDS=${HD}
 	fi
 else
 # single
 	echo "This is single system"
 	HDDS=${HD}
 fi
 
 #exec 1>&2
 echo "Formatting disks"
 
 clear_disks() {
 	# $1 - disk
 	# $2 - disk-label-ending
         gpart delete -i 2 $1
         gpart delete -i 3 $1
         gpart delete -i 4 $1
         gpart delete -i 5 $1
         gpart delete -i 6 $1
         echo "destroy" | tee -a $BSDINSTALL_LOG
         gpart destroy -F $1
         echo "create GPT" | tee -a $BSDINSTALL_LOG
         gpart create -s GPT $1
         echo "add boot" | tee -a $BSDINSTALL_LOG
         gpart add -t freebsd-boot -l gpboot$2 -s 256K $1
         echo "set bootcode" | tee -a $BSDINSTALL_LOG
         gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 $1
         echo "add swap" >> $BSDINSTALL_LOG
         SWSIZE=$(sysctl -n hw.realmem | awk '{print int($1/1024/1024)+1}')
 		if [ ${SWSIZE} -gt 2048 ]; then
 			SWSIZE=2048
 		fi
         gpart add -t freebsd-swap -l swap$2 -s ${SWSIZE}M $1
         echo "add root" | tee -a $BSDINSTALL_LOG
 
         # calculating size (not neded now)
         #let "ROOT_PART = ($VOL_SIZE_M) - 1"
         #echo "$ROOT_PART"
         #gpart add -t freebsd-ufs -l rootfs -s "$ROOT_PART"M $HD
         gpart add -t freebsd-ufs -l rootfs$2 $1 
 
 }
 
 if [ -n "${GMIRROR}" ]; then
 	clear_disks ${HD1} ${HD1}
 	clear_disks ${HD2} ${HD2}
 else
 	clear_disks ${HD}
 fi
 
 if [ -n "${GMIRROR}" ]; then
 	echo "Creating mirror"
 	gmirror load
 	gmirror label -v rootfs /dev/gpt/rootfs${HD1} /dev/gpt/rootfs${HD2}
 	gmirror label -v swap /dev/gpt/swap${HD1} /dev/gpt/swap${HD2}
 
 	echo "newfs root" | tee -a $BSDINSTALL_LOG
 	newfs -U /dev/mirror/rootfs
 
 	echo "mount" | tee -a $BSDINSTALL_LOG
 	mount /dev/mirror/rootfs $BSDINSTALL_CHROOT
 
 	echo "# Device                Mountpoint      FStype  Options         Dump    Pass#" > $PATH_FSTAB
 	echo "/dev/mirror/swap        none    swap    sw      0       0"    >> $PATH_FSTAB
 	echo "/dev/mirror/rootfs       /               ufs     rw      1       1" >> $PATH_FSTAB
 else
 
 	echo "newfs root" | tee -a $BSDINSTALL_LOG
 	newfs -U /dev/gpt/rootfs
 
 	echo "mount" | tee -a $BSDINSTALL_LOG
 	mount /dev/gpt/rootfs $BSDINSTALL_CHROOT
 
 	echo "# Device                Mountpoint      FStype  Options         Dump    Pass#" > $PATH_FSTAB
 	echo "/dev/gpt/swap        none    swap    sw      0       0"    >> $PATH_FSTAB
 	echo "/dev/gpt/rootfs       /               ufs     rw      1       1" >> $PATH_FSTAB
 fi
 
 if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
        ALL_DISTRIBUTIONS="$DISTRIBUTIONS"
 
        # Download to a directory in the new system as scratch space
        BSDINSTALL_FETCHDEST="$BSDINSTALL_CHROOT/usr/freebsd-dist"
        mkdir -p "$BSDINSTALL_FETCHDEST" || error
 
        export DISTRIBUTIONS="$FETCH_DISTRIBUTIONS"
        # Try to use any existing distfiles
        if [ -d $BSDINSTALL_DISTDIR ]; then
                DISTDIR_IS_UNIONFS=1
                mount_nullfs -o union "$BSDINSTALL_FETCHDEST" "$BSDINSTALL_DISTDIR"
        else
                export DISTRIBUTIONS="MANIFEST $ALL_DISTRIBUTIONS"
                export BSDINSTALL_DISTDIR="$BSDINSTALL_FETCHDEST"
        fi
 
        export FTP_PASSIVE_MODE=YES
        bsdinstall distfetch || error fetch
        export DISTRIBUTIONS="$ALL_DISTRIBUTIONS"
         clear
 fi
 
 bsdinstall checksum || error checksummincorrect
 bsdinstall distextract || error distextractfail
 clear
 
 echo "Setting password"
 PASSWORD="($PASS)"
 
 echo $PASSWORD | pw -V "$BSDINSTALL_CHROOT/etc" usermod root -h0
 
 echo "Configuring services"
 echo "PermitRootLogin yes" >> "$BSDINSTALL_CHROOT/etc/ssh/sshd_config"
 
 #echo sshd_enable=\"YES\" >> $BSDINSTALL_TMPETC/rc.conf.services
 echo dumpdev=\"AUTO\" >> $BSDINSTALL_TMPETC/rc.conf.services
 
 if [ -n "${GMIRROR}" ]; then
 	echo geom_mirror_load="YES" >> $BSDINSTALL_CHROOT/boot/loader.conf
 fi
 
 echo "Installing configs"
 bsdinstall config  || error
 
 echo "Installing vim"
 chroot $BSDINSTALL_CHROOT pkg_add -r vim-lite
 sed -i "" -E 's/EDITOR(.*)vi/EDITOR\1vim/g' $BSDINSTALL_CHROOT/root/.cshrc
 cat >> $BSDINSTALL_CHROOT/root/.vimrc << EOF
 set nocompatible
 set encoding=utf8
 syntax on
 EOF
 
 cp $BSDINSTALL_LOG $BSDINSTALL_CHROOT/root/
 dmesg > $BSDINSTALL_CHROOT/root/dmesg
 if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
        [ "$BSDINSTALL_FETCHDEST" != "$BSDINSTALL_DISTDIR" ] && \
            umount "$BSDINSTALL_DISTDIR"
        rm -rf "$BSDINSTALL_FETCHDEST"
 fi
 
 echo "Installation complete"
 $WGET "($FINISH)"
 
 echo "Installation Completed at $(date)" | tee -a $BSDINSTALL_LOG
 cp $BSDINSTALL_LOG $BSDINSTALL_CHROOT/root

preseed (Debian, Ubuntu)

Этот механизм очень похож на kickstart.

metainfo.xml

 <?xml version="1.0"?>
 <doc>
   <osname>Debian-7-amd64</osname>
   <support>
     <elem>IFXmgr</elem>
     <elem>VMmgr</elem>
   </support>
   <rebootcount>1</rebootcount>
   <kernel>linux</kernel>
   <initrd>initrd.gz</initrd>
   <type>ostemplate</type>
   <loader>pxelinux.0</loader>
   <pxelinuxcfg>pxelinux.conf</pxelinuxcfg>
   <tempipv4>yes</tempipv4>
   <kernelcommand>url=($OSINSTALLINFO_HTTPv4) language=en debian-installer/country=RU locale=en_US keyboard-configuration/xkb-keymap=us console-keymaps-at/keymap=us interface=auto netcfg/disable_dhcp=true netcfg/get_ipaddress=($IPv4) netcfg/get_netmask=($NETMASKv4) netcfg/get_gateway=($GATEWAYv4) netcfg/get_nameservers=($NAMESERVERv4) hostname=($HOSTNAME) domain=($HOSTNAME)</kernelcommand>
   <installcfg>install.cfg</installcfg>
   <limit>
     <elem name="ipv4">yes</elem>
     <elem name="ipv6">yes</elem>
     <elem name="mem">512</elem>
     <elem name="disk">1000</elem>
   </limit>
 </doc>

install.cfg

 d-i keyboard-configuration/xkb-keymap select us
 
 # Mirrors
 #d-i mirror/protocol string ftp
 #d-i mirror/country string manual
 #d-i mirror/ftp/hostname string ftp.ru.debian.org
 #d-i mirror/ftp/directory string /debian
 #d-i mirror/ftp/proxy string
 d-i mirror/country string manual
 d-i mirror/http/hostname string mirror.yandex.ru
 d-i mirror/http/directory string /debian
 d-i mirror/http/proxy string ($HTTPPROXYv4)
 
 d-i passwd/make-user boolean false
 
 d-i passwd/root-password password ($PASS)
 d-i passwd/root-password-again password ($PASS)
 
 d-i clock-setup/utc boolean true
 
 d-i time/zone string Europe/Moscow
 
 d-i preseed/early_command string \
 	anna-install parted-udeb 
 
 # Partitioning
 d-i partman/early_command string \
 for DISK in $(list-devices disk); do \
     dd if=/dev/zero of=${DISK} bs=512 count=1; \
     parted -s ${DISK} mklabel gpt; \
 done; \
 set $(list-devices disk); \
 let numb=$#/2; \
 DISKA=$1; \
 DISKB=$2; \
 if [ -b "${DISKB}" ]; then \
     SIZE1=$(fdisk -l "${DISKA}" 2>/dev/null|grep Disk|grep dev|cut -d' ' -f5); \
     SIZE2=$(fdisk -l "${DISKB}" 2>/dev/null|grep Disk|grep dev|cut -d' ' -f5); \
 	if [ -n ${SIZE1} ] && [ -n ${SIZE2} ] && [ "${SIZE1}" = "${SIZE2}" ]; then \
 	    USE_MIRROR=yes; \
 	else \
 	    USE_MIRROR=no; \
 	fi; \
 fi; \
 if [ "#${USE_MIRROR}" = "#yes" ]; then \
 	debconf-set partman-auto/disk "$DISKA $DISKB";\
 	debconf-set partman-auto/method "raid";\
 	debconf-set partman-auto/expert_recipe "multiraid :: \
 		100 50 100 raid $primary{ } method{ raid } . \
 		128 512 100% raid method{ raid } . \
 		1024 10000 1000000000 raid method{ raid } . ";\
 	debconf-set partman-auto-raid/recipe "1 2 0 ext2 /boot ${DISKA}1#${DISKB}1 . \
 		1 2 0 swap - ${DISKA}5#${DISKB}5 . \
 		1 2 0 ext4 / ${DISKA}6#${DISKB}6 . ";\
 	debconf-set grub-installer/bootdev "$DISKA $DISKB";\
 else \
 	debconf-set partman-auto/disk "$DISKA";\
 	debconf-set partman-auto/method "regular";\
 	debconf-set partman-auto/expert_recipe "boot-root :: \
 		100 50 100 ext2 $primary{ } $bootable{ } method{ format } format{ } use_filesystem{ } filesystem{ ext2 } mountpoint{ /boot } . \
 		128 512 100% linux-swap method{ swap } format{ } . \
 		1024 10000 1000000000 ext4 method{ format } format{ } use_filesystem{ } filesystem{ ext4 } mountpoint{ / } . ";\
 	debconf-set grub-installer/bootdev "$DISKA";\
 fi 
 
 
 #d-i partman-auto/method string regular
 
 #d-i partman-auto/expert_recipe string                         \
 #      boot-root ::                                            \
 #              40 50 100 ext2                                  \
 #                      $primary{ } $bootable{ }                \
 #                      method{ format } format{ }              \
 #                      use_filesystem{ } filesystem{ ext2 }    \
 #                      mountpoint{ /boot }                     \
 #              .                                               \
 #              500 10000 1000000000 ext4                       \
 #                      method{ format } format{ }              \
 #                      use_filesystem{ } filesystem{ ext4 }    \
 #                      mountpoint{ / }                         \
 #              .                                               \
 #              64 512 300% linux-swap                          \
 #                      method{ swap } format{ }                \
 #		.
 
 # Force overwrite partitions
 
 d-i partman-partitioning/choose_label       select gpt
 d-i partman-partitioning/confirm_new_label  boolean true
 d-i partman-partitioning/unknown_label  boolean true
 d-i partman/exception_handler   select  Yes
 partman-partitioning    partman-partitioning/choose_label       select gpt
 partman-partitioning    partman-partitioning/confirm_new_label  boolean true
 partman-partitioning    partman-partitioning/unknown_label  boolean true
 partman-base    partman/exception_handler   select  Yes
 
 d-i partman-auto/purge_lvm_from_device boolean true
 d-i partman-lvm/device_remove_lvm boolean true 
 d-i partman-md/device_remove_md boolean true
 d-i partman-md/confirm boolean true
 d-i partman-md/confirm_nooverwrite boolean true
 d-i partman-partitioning/confirm_write_new_label boolean true
 d-i partman/choose_partition select finish
 d-i partman/confirm boolean true
 d-i partman/confirm_nooverwrite boolean true
 
 d-i partman/mount_style select traditional
 
 # Apt
 
 #d-i base-installer/install-recommends boolean true
 
 #d-i base-installer/kernel/linux/initramfs-generators string initramfs-tools
 #d-i base-installer/kernel/image string linux-image-amd64
 
 d-i apt-setup/contrib boolean true
 #d-i apt-setup/use_mirror boolean true
 
 # Packages
 d-i apt-setup/services-select multiselect security, volatile
 tasksel tasksel/first multiselect standard
 d-i pkgsel/include string openssh-server vim wget
 
 popularity-contest popularity-contest/participate boolean false
 
 # Grub
 d-i grub-installer/only_debian boolean true
 d-i grub-installer/with_other_os boolean true
 
 d-i finish-install/keep-consoles boolean true
 
 d-i preseed/late_command string \
 	in-target rm -f /etc/apt/apt.conf ;\
 	ETHDEV=$(ip route show | grep default | grep -Eo 'dev\ .+\ ' | cut -d' ' -f2) ;\
 	if [ -n "($IPv6)" ]; then \
 		echo "# The loopback network interface" > /target/etc/network/interfaces ;\
 		echo "auto lo" >> /target/etc/network/interfaces ;\
 		echo "iface lo inet loopback" >> /target/etc/network/interfaces ;\
 		echo "" >> /target/etc/network/interfaces ;\
 		echo "# The primary network interface" >> /target/etc/network/interfaces ;\
 		echo "allow-hotplug ${ETHDEV}" >> /target/etc/network/interfaces ;\
 		echo "iface ${ETHDEV} inet6 static" >> /target/etc/network/interfaces ;\
 		echo -e "\taddress ($IPv6)" >> /target/etc/network/interfaces ;\
 		echo -e "\tnetmask ($NETMASKv6)" >> /target/etc/network/interfaces ;\
 		echo -e "\tgateway ($GATEWAYv6)" >> /target/etc/network/interfaces ;\
 		echo -e "\tdns-nameservers ($NAMESERVERv6)" >> /target/etc/network/interfaces ;\
 		echo "nameserver ($NAMESERVERv6)" > /target/etc/resolv.conf ;\
 		sed -i "s/($IPv4)/($IPv6)/" /etc/hosts ;\
 		sed -i "s/($IPv4)/($IPv6)/" /target/etc/hosts ;\
 		echo "# The loopback network interface" > /etc/network/interfaces ;\
 		echo "auto lo" >> /etc/network/interfaces ;\
 		echo "iface lo inet loopback" >> /etc/network/interfaces ;\
 		echo "" >> /etc/network/interfaces ;\
 		echo "# The primary network interface" >> /etc/network/interfaces ;\
 		echo "allow-hotplug ${ETHDEV}" >> /etc/network/interfaces ;\
 		echo "iface ${ETHDEV} inet6 static" >> /etc/network/interfaces ;\
 		echo -e "\taddress ($IPv6)" >> /etc/network/interfaces ;\
 		echo -e "\tnetmask ($NETMASKv6)" >> /etc/network/interfaces ;\
 		echo -e "\tgateway ($GATEWAYv6)" >> /etc/network/interfaces ;\
 		echo -e "\tdns-nameservers ($NAMESERVERv6)" >> /etc/network/interfaces ;\
 		echo "nameserver ($NAMESERVERv6)" > /etc/resolv.conf ;\
 	fi ;\
 	in-target wget --no-check-certificate "($FINISHv4)"
 
 d-i finish-install/reboot_in_progress note

Windows

Данный способ поддерживается пока только VMmanager. Принцип следующий: разворачивается уже готовый образ установленной операционной системы, у которой стоит запуск скрипта C:\vmmgr\firstrun.cmd в автозагрузке. Этот скрипт с помощью dd считывает данные из одномегабайтного виртуального диска, в котором находится скрипт, полученный от VMmanager. Автозапуск рекомендуется настраивать через Task Scheduler.

Скрипты автозагрузки Windows

Данные скрипты нужно расположить в C:\vmmgr\

firstrun.cmd
@echo off
powershell.exe C:\vmmgr\firstrun.ps1 >NUL
firstrun.ps1
 $ddout = C:\vmmgr\ddwrap.cmd
 $ddout
 $list = $ddout | select-string "size is 1048576 bytes" -Context 3,0
 $list
 $context = $list.Context.PreContext | select-string Part
 $str = $context.Line
 $str
 C:\vmmgr\dd.exe if=$str of=C:\vmmgr\vmmgr.cmd bs=512 count=2048
 C:\vmmgr\vmmgr.cmd
ddwrap.cmd
c:\vmmgr\dd.exe --list 2>&1

При использовании наших скриптов загрузки, необходимо разрешить в PowerShell выполнение неподписанных скриптов. Для этого нужно зайти в PowerShell и выполнить команду:

Set-ExecutionPolicy RemoteSigned

Также необходимо положить в C:\vmmgr\ утилиту dd.


Файлы шаблона

metainfo.xml
 <?xml version="1.0"?>
 <doc>
   <osname>Windows-Server-2012</osname>
   <limit>
     <elem name="ipv4">yes</elem>
     <elem name="ipv6">no</elem>
     <elem name="mem">1024</elem>
     <elem name="disk">10000</elem>
   </limit>
   <support>
     <elem>VMmgr</elem>
   </support>
   <hddimage>win_ser_2012_str.hddimage</hddimage>
   <rebootcount>1</rebootcount>
   <type>ostemplate</type>
   <installdrive>win_ser_2012_str.cmd</installdrive>
 </doc>
win_ser_2012_str.cmd

В скрипте установки необходимо раскомментировать строки для активации WIndows и указать свой ключ.

 @echo off
 set logfile=C:\setup.log 
 echo ------Set static IP-------------------------------------[%DATE%-%TIME%]      > %logfile%
 echo --- IP/NM=($IP)/($NETMASK)  GW=($GATEWAY)      >> %logfile%
 echo --- NS1=($NAMESERVER)                                                   >> %logfile%
 netsh interface ip set address    "Ethernet" static ($IP) ($NETMASK) ($GATEWAY)  >> %logfile%
 netsh interface ip add dnsservers "Ethernet" ($NAMESERVER)          >> %logfile%
 echo --- set Administartor password >> %logfile%
 net user Administrator ($PASS)  >> %logfile%
 set extendfile=C:\vmmgr\extend.txt
 echo --- resize disk >> %logfile%
 echo select volume 1 > %extendfile%
 echo extend noerr >> %extendfile%
 diskpart.exe /s %extendfile% >> %logfile%
 
 #Uncomment the following 3 lines and enter your activation key.
 #echo activate windows >> %logfile%
 #cscript %windir%\system32\slmgr.vbs -ipk XXXXX-XXXXX-XXXXX-XXXXX-XXXX
 #cscript %windir%\system32\slmgr.vbs -ato
 
 echo remove task vmmgr_firstrun >> %logfile%
 schtasks /Delete /TN "vmmgr_firstrun" /F  >> %logfile%
 echo restart OS >> %logfile%
 echo ------END--------------------------------------------------[%DATE%-%TIME%]     >> %logfile%
 
 echo RMDIR /s /Q  C:\vmmgr >> c:\del.cmd
 echo shutdown /r >> c:\del.cmd
 cmd /c c:\del.cmd

CentOS с разворачиванием из файла

Возможно сделать Linux шаблон, устанавливающийся не через файл ответов, а разворачивающийся из готового образа диска. Для этого необходимо, чтобы файловая система ОС поддерживала "растягивание на лету", то есть изменение размера на смонтированной ФС (например, ext4).

Данный способо работает только с VMmanager

Для примера используется CentOS 6.

Создание образа диска

Для создания образа нужно создать виртуальную машину с CentOS с небольшим размером диска (2GB)

В данной машине можно установить нужное ПО, сделать нужные настройки.

Разбивка диска:

/dev/vda1 - /boot
/dev/vda2 - swap
/dev/vda3 - / 

Также нужно добавить в /etc/rc.local команду запуска скрипта установки, который будет подключен через опцию installdrive

echo "sh /dev/sda" >> /etc/rc.local

ВАЖНО В debian файл /etc/rc.local заканчивается строкой exit 0 и добавлять нужно не в конец файла, а до строки exit

Если поддержки virtio нет, то установочный диск будет /dev/sdb

После нужно сделать "дамп диска" в файл в директорию шаблона:

Для LVM:

dd if=/dev/MyLvm/VMNAME of=centos_hdd.image

Для RAW формата:

dd if=ПУТЬ_К_ФАЙЛУ of=centos_hdd.image

Скрипт установки

Пример скрипта установки для CentOS. Для Debian скрипт будет отличаться. Название файла указывается в параметре installdrive

#!/bin/sh
 
clean_files() {
        rm -f /etc/ssh/*key*
        sed -r -i '/sh \/dev\/sda/d' /etc/rc.local
}
 
 
disk_format() {
        fdisk /dev/vda <<EOF
c
d
3
n
p
3
 
 
w
EOF
}
 
resize_fs() {
        cat >> /etc/init.d/resize_fs << EOF
#!/bin/bash
#
# Resize fs
#
### BEGIN INIT INFO
# Default-Start:        1 2 3 4 5
# Default-Stop:         0 6
# Required-Start:
# Required-Stop?
# Short-Description:    Resize root filesystem
# Description:          Resize root filesystem
# Provides:             resize_fs
### END INIT INFO
 
. /etc/init.d/functions
 
case "\$1" in
        start|reload)
                resize2fs /dev/root
                chkconfig --del resize_fs
                rm -f /etc/init.d/resize_fs
                exit 0
                ;;
        *)
                echo "service resize_fs start"
                exit 2
esac
 
EOF
chmod +x /etc/init.d/resize_fs
chkconfig --add resize_fs
}
 
network_configure() {
        IPv4=($IPv4)
        NETMASK=($NETMASKv4)
        GATEWAYv4=($GATEWAYv4)
        IPv6=($IPv6)
        PREFIX=($NETMASKv6)
        GATEWAYv6=($GATEWAYv6)
        HOSTNAME=($HOSTNAME)
 
        if [ -n "${GATEWAYv4}" ]; then
                GATEWAY=${GATEWAYv4}
        else
                GATEWAY=${GATEWAYv6}
        fi
 
        # Removing udev rules
        rm -f /etc/udev/rules.d/70-persistent-net.rules
 
 
        # Configuring network
        sed -r -i '/HOSTNAME=.+/d; /GATEWAY=.+/d' /etc/sysconfig/network
cat >> /etc/sysconfig/network << EOF
HOSTNAME=${HOSTNAME}
GATEWAY=${GATEWAY}
EOF
 
        ip link set eth1 name eth0
        HWADDR=$(ip link show eth0 | awk '/link\/ether/ {print $2}' | tr [:lower:] [:upper:])
 
        cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
DEVICE="eth0"
BOOTPROTO="static"
DNS1="($NAMESERVER)"
HWADDR="${HWADDR}"
NM_CONTROLLED="yes"
ONBOOT="yes"
TYPE="Ethernet"
EOF
 
        if [ -n "${IPv4}" ]; then
                cat >> /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
GATEWAY="${GATEWAYv4}"
IPADDR="${IPv4}"
NETMASK="${NETMASK}"
EOF
 
        else
                cat >> /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
IPV6INIT="yes"
IPV6ADDR="${IPv6}/${PREFIX}"
IPV6_DEFAULTGW="${GATEWAYv6}"
EOF
 
        fi
 
        ifup eth0
}
 
clean_files
disk_format
resize_fs
echo "($PASS)" | passwd --stdin root
network_configure
wget -q -O /dev/null --no-check-certificate "($FINISH)"
reboot

Данный скрипт:

  • изменит размер раздела
  • выставит пароль
  • добавит растягивание ФС при следующем запуске. Сразу же после изменения размера раздела сделать это нельзя, так как ядро ОС узнает об изменении разметки только при перезагрузке.
  • удалит из /etc/rc.local запуск себя


metainfo.xml

<?xml version="1.0"?>
<doc>
  <osname>CentOS-6-amd64-fromdisk</osname>
  <limit>
    <elem name="ipv4">yes</elem>
    <elem name="ipv6">yes</elem>
    <elem name="mem">512</elem>
    <elem name="disk">2000</elem>
  </limit>
  <support>
    <elem version="5.4.0">VMmgr</elem>
  </support>
  <hddimage>centos_hdd.image</hddimage>
  <rebootcount>1</rebootcount>
  <type>ostemplate</type>
  <installdrive>install.sh</installdrive>
  <virtiodisk>yes</virtiodisk>
  <virtionet>yes</virtionet>
  <date>2013-09-20 12:59:19</date>
  <install_result>ok</install_result>
</doc>