The Windows OS template for the repository must contain:

  • OS disk image;
  • initial setup script;
  • metadata file.

This article describes the stages of template preparation.

OS disk image


Preparing the image

To prepare the image, install the required version of Windows.

To prepare an image, you can:

  • install the required version of Windows OS on the physical server;
  • use the VM in the platform.

To prepare an image from a VM:

  1. Create a VM without an operating system.
  2. Change the disk connection type to IDE: Virtual machines section → select VM → Parameters button → Virtual disk menu → Edit disk → select the ide Connection typeChange and restart button.
  3. Install Windows from an ISO image: Virtual Machines section → select VM →  menu → Mount ISO image → select local file or enter image URL → Upload image button.
  4. Download and install the Virtio drivers.
  5. Download and install QEMU Guest Agent.
  6. Change the disk connection type to Virtio: Virtual machines section → select VM → Parameters button → Virtual disk menu → Edit disk → select the virtio Connection typeChange and restart button.
  7. Check that all hardware in Device Manager is installed correctly.

Image configuration

The first time you start the OS from the template, the initial setup script must run on it. VMmanager creates a separate virtual disk to store this script. The script is loaded from the virtual disk using the dd utility. To configure the script to run:

  1. Create the C:\vmmgr\ directory in the OS.
  2. In the C:\vmmgr\ directory, create firstrun.cmd, firstrun.ps1, ddwrap.cmd scripts

    Script files must be in Windows format. Line translations must be performed using CR LF control characters.

    firstrun.cmd

    @echo off
    powershell.exe C:\vmmgr\firstrun.ps1 >NUL
    CODE

    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
    CODE

    ddwrap.cmd

    c:\vmmgr\dd.exe --list 2>&1
    CODE
  3. Download the dd utility, unpack the archive and copy the dd.exe file to the C:\vmmgr\ directory.
  4. Allow running unsigned scripts in PowerShell. To do this, enter PowerShell and run the command:

    Set-ExecutionPolicy RemoteSigned
    BASH
  5. Add the C:\vmmgr\firstrun.cmd script to autorun. To do this, create a job in the scheduler named vmmgr_firstrun to be executed at system startup. Enable the "Execute regardless of user registration" security setting for the job.
  6. Shut down the OS.

Image creation

If you prepared the image on a physical server:

  1. Boot from any Live CD.
  2. Create a disk image of the OS. You can do this with the dd or virt-sparcify utility.

    An example of creating an image using dd

    dd.exe if=\\?\Device\Harddisk0\DR0 of=c:\vmmgr\tempdisk1.img bs=8M
    CODE

    if — the path to the disk with the OS. The list can be viewed by the command "dd --list"

    of — path to the output image file

    bs — block size in megabytes (M) or kilobytes (k)

    An example of creating an image using virt-sparsify

    virt-sparsify /path/to/device disk.img
    BASH

    /path/to/device — the path to the disk with the OS

    disk.img — output image file

If you prepared the image using VMmanager, the order in which the image is created depends on the storage type:

  • file storage, NAS:
    1. Connect to the VMmanager cluster node via SSH.
    2. Convert the VM disk file to RAW format:

      qemu-img convert -f qcow2 -O raw <qcow_input> <raw_output> 
      BASH

      <qcow_input> — Qcow2 input file

      <raw_output> — RAW output file

  • LVM:
    1. Connect to the VMmanager cluster node via SSH.
    2. Export the VM disk file:

      qemu-img convert -f raw -O raw <path_to_vm/raw_input> <raw_output>
      BASH

      <path_to_vm/raw_input> — path and name of the VM disk source file in RAW format

      <raw_output> — RAW output file

  • Ceph:
    1. Connect to the Ceph monitor server with the source VM.

    2. Export the VM disk file:

      rbd export <pool_name>/<disk_name> <raw_output>
      BASH

      <pool_name> — Ceph pool name

      <disk_name> — VM disk name

      <raw_output> — RAW output file

Initial setup script


For the initial OS setup, you can use the script below. 

The script file must be saved in Windows format. Line translations must be performed using CR LF control characters.


windows.cmd

@echo off
setlocal EnableDelayedExpansion

set logfile=C:\setup.log

del /f c:\ifacename.txt

for /f "skip=2 tokens=2,4*" %%A in ('netsh interface show interface') do (
  if "%%A" == "Connected" (
    echo %%B %%C>> c:\ifacename.txt
  )
)

set /P IFACENAME=< c:\ifacename.txt

echo Trimming

set IFACENAME=%IFACENAME%##
set IFACENAME=%IFACENAME:    ##=##%
set IFACENAME=%IFACENAME:  ##=##%
set IFACENAME=%IFACENAME: ##=##%
set IFACENAME=%IFACENAME:##=%

del /f c:\ifacename.txt

echo --- Interface name: %IFACENAME% >> %logfile%

echo --- set Administartor password >> %logfile%

net user Administrator ($PASS)  >> %logfile%
echo ------Set static IP-------------------------------------[%DATE%-%TIME%]      > %logfile%
echo --- IP/NM=($IP)/($NETMASK)  GW=($GATEWAY)      >> %logfile%
echo --- NS1=($NAMESERVER)                                                   >> %logfile%

set "nexthop=($NEXTHOPIPv4)"

IF "%nexthop%"=="()" (
        set "nexthop=NONE"
)
echo %nexthop% | findstr /c:( 1>nul
IF NOT ERRORLEVEL 1 (
        set "nexthop=NONE"
)

IF (%nexthop%) == () (
        set "nexthop=NONE"
)

if (%nexthop%) == (NONE) (
        netsh interface ip set address    "%IFACENAME%" static ($IP) ($NETMASK) ($GATEWAY)  >> %logfile%
) ELSE (
        netsh interface ip set address    "%IFACENAME%" static ($IP) 255.255.255.255 ($NEXTHOPIPv4)  >> %logfile%
)

netsh interface ip add dnsservers "%IFACENAME%" ($NAMESERVER)          >> %logfile%

set "nslist=($NAMESERVERS)"

IF "%nslist%"=="()" (
        set "nslist=NEX"
)
echo %nslist% | findstr /c:( 1>nul
IF NOT ERRORLEVEL 1 (
        set "nslist=NEX"
)

if NOT "%nslist%"=="" ( 
        IF NOT "%nslist%"=="NEX" (
                set flist=%nslist:"=%
                echo NAMESERVERS: !flist! >> %logfile%
REM                netsh interface ip delete dnsservers "%IFACENAME%" all >> %logfile%
                FOR %%i IN (!flist!) DO (
                        echo %%i >> %logfile%
                        echo %%i | findstr /c:: 1>nul
                        if ERRORLEVEL 1 (
                                echo ipv4 >> %logfile%
                                netsh interface ip add dnsservers "%IFACENAME%" %%i >> %logfile%
                        ) ELSE (
                                echo ipv6 >> %logfile%
                                netsh interface ipv6 add dnsservers "Ethernet" %%i >> %logfile%
                        )
                )
        ) ELSE (
                echo BRACERS >> %logfile%
        )
) ELSE (
        echo EMPTY >> %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%

set "pkey=($PRODUCTKEY)"

IF NOT "%pkey%" == "" (
        IF NOT "%pkey%" == "()" (
                echo "PKEY is not null. Activating license"
                echo activate windows >> %logfile%
                cscript %windir%\system32\slmgr.vbs -ipk %pkey%
                cscript %windir%\system32\slmgr.vbs -ato
        ) ELSE (
                echo "PKEY is bracers" >> %logfile%
        )
) ELSE (
        echo "PKEY is EMPTY" >> %logfile%
)

echo remove task vmmgr_firstrun >> %logfile%
schtasks /Delete /TN "vmmgr_firstrun" /F  >> %logfile%
echo restart OS >> %logfile%
echo ------END--------------------------------------------------[%DATE%-%TIME%]     >> %logfile%

REM Enable RDP
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
netsh firewall set service remotedesktop enable

echo RMDIR /s /Q  C:\vmmgr >> c:\del.cmd
echo shutdown /r >> c:\del.cmd
cmd /c c:\del.cmd
BASH

Metadata file


The metainfo.xml metadata file contains information about the template:

  • <osname> — OS name;
  • <limit> — template limits. If the VM does not meet the limits, it will not be created. Limit parameters:
    • <elem name="ipv4"> — using an IPv4 address as the primary address. Possible values: yes — supported, no — not supported;
    • <elem name="ipv6"> — using an IPv6 address as the primary address. Possible values: yes — supported, no — not supported;
    • <elem name="mem"> — minimum amount of RAM in MiB;
    • <elem name="disk"> — minimum disk space in MB;
  • <support> — Software that supports the template. For VMmanager, specify <elem>VMmgr</elem>;
  • <tags> — template tags. Used for compatibility with scripts;
  • <version> — template version;
  • <hddimage> — image file name;
  • <rebootcount> — the number of reboots after which VMmanager will consider that the OS is installed;
  • <type> — template type. For the OS template, specify <type>ostemplate</type>;
  • <installdrive> — the name of the initial setup script;
  • <virtionet>yes</virtionet> — support of virtio network;
  • <virtiodisk>yes</virtiodisk> — support of virtio disks;
  • <macro> — macros for passing to the template. To pass the value of the license key, specify <elem name="($PRODUCTKEY)"/>.

Example of metainfo.xml file

<?xml version="1.0"?>
<doc>
  <osname>Windows-Server-2019</osname>
  <limit>
    <elem name="ipv4">yes</elem>
    <elem name="ipv6">no</elem>
    <elem name="mem">1024</elem>
    <elem name="disk">15000</elem>
  </limit>
  <support>
    <elem>VMmgr</elem>
  </support>
  <tags>windows,windows2019</tags>
  <version>5</version>
  <hddimage>win2019.hddimage</hddimage>
  <rebootcount>1</rebootcount>
  <type>ostemplate</type>
  <installdrive>windows.cmd</installdrive>
  <virtiodisk>yes</virtiodisk>
  <virtionet>yes</virtionet>
  <macro>
    <elem name="($PRODUCTKEY)"/>
  </macro>
</doc>
CODE

Loading the template into the repository


To load a template:

  1. Create a .tar.gz archive including the OS disk image, the initial setup script, and a metadata file.
  2. Copy the archive to the repository directory.
  3. Add the template information to the metadata.json repository description file. Read more in OS templates repositories.