mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
builder: templates: Add Windows template support.
Provides support for building: - Windows 7 - Windows Server 2008 R2 - Windows Server 2012 - Windows Server 2012 R2 - Windows Server 2016 Note that these images cannot be released to the public because of obvious licensing issues. But this documents how we build them for internal consumption so that others can also build them. Thanks: Christophe Fergeau, Tomáš Golembiovský.
This commit is contained in:
@@ -32,6 +32,8 @@
|
||||
|
||||
open Printf
|
||||
|
||||
let windows_installers = "/mnt/media/installers/Windows"
|
||||
|
||||
let prog = "make-template"
|
||||
|
||||
(* Ensure that a file is deleted on exit. *)
|
||||
@@ -80,6 +82,8 @@ type os =
|
||||
| Ubuntu of string * string
|
||||
| Fedora of int (* version number *)
|
||||
| FreeBSD of int * int (* major, minor *)
|
||||
| Windows of int * int * windows_variant (* major, minor, variant *)
|
||||
and windows_variant = Client | Server
|
||||
type arch = X86_64 | Aarch64 | Armv7 | I686 | PPC64 | PPC64le | S390X
|
||||
|
||||
type boot_media =
|
||||
@@ -102,6 +106,7 @@ let rec main () =
|
||||
(* For OSes which require a kickstart, this generates one.
|
||||
* For OSes which require a preseed file, this returns one (we
|
||||
* don't generate preseed files at the moment).
|
||||
* For Windows this returns an unattend file in an ISO.
|
||||
* For OSes which cannot be automated (FreeBSD), this returns None.
|
||||
*)
|
||||
let ks = make_kickstart os arch in
|
||||
@@ -350,6 +355,7 @@ and os_of_string os ver =
|
||||
| "ubuntu", "18.04" -> Ubuntu (ver, "bionic")
|
||||
| "fedora", ver -> Fedora (int_of_string ver)
|
||||
| "freebsd", ver -> let maj, min = parse_major_minor ver in FreeBSD (maj, min)
|
||||
| "windows", ver -> parse_windows_version ver
|
||||
| _ ->
|
||||
eprintf "%s: unknown or unsupported OS (%s, %s)\n" prog os ver; exit 1
|
||||
|
||||
@@ -364,6 +370,18 @@ and parse_major_minor ver =
|
||||
exit 1
|
||||
)
|
||||
|
||||
(* https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions *)
|
||||
and parse_windows_version = function
|
||||
| "7" -> Windows (6, 1, Client)
|
||||
| "2k8r2" -> Windows (6, 1, Server)
|
||||
| "2k12" -> Windows (6, 2, Server)
|
||||
| "2k12r2" -> Windows (6, 3, Server)
|
||||
| "2k16" -> Windows (10, 0, Server)
|
||||
| _ ->
|
||||
eprintf "%s: cannot parse Windows version, see ‘parse_windows_version’\n"
|
||||
prog;
|
||||
exit 1
|
||||
|
||||
and arch_of_string = function
|
||||
| "x86_64" -> X86_64
|
||||
| "aarch64" -> Aarch64
|
||||
@@ -416,6 +434,14 @@ and filename_of_os os arch ext =
|
||||
| FreeBSD (major, minor) ->
|
||||
if arch = X86_64 then sprintf "freebsd-%d.%d%s" major minor ext
|
||||
else sprintf "freebsd-%d.%d-%s%s" major minor (string_of_arch arch) ext
|
||||
| Windows (major, minor, Client) ->
|
||||
if arch = X86_64 then sprintf "windows-%d.%d-client%s" major minor ext
|
||||
else sprintf "windows-%d.%d-client-%s%s"
|
||||
major minor (string_of_arch arch) ext
|
||||
| Windows (major, minor, Server) ->
|
||||
if arch = X86_64 then sprintf "windows-%d.%d-server%s" major minor ext
|
||||
else sprintf "windows-%d.%d-server-%s%s"
|
||||
major minor (string_of_arch arch) ext
|
||||
|
||||
and string_of_os os arch = filename_of_os os arch ""
|
||||
|
||||
@@ -428,16 +454,18 @@ and string_of_os_noarch = function
|
||||
| Debian (ver, _) -> sprintf "debian-%d" ver
|
||||
| Ubuntu (ver, _) -> sprintf "ubuntu-%s" ver
|
||||
| FreeBSD (major, minor) -> sprintf "freebsd-%d.%d" major minor
|
||||
| Windows (major, minor, Client) -> sprintf "windows-%d.%d-client" major minor
|
||||
| Windows (major, minor, Server) -> sprintf "windows-%d.%d-server" major minor
|
||||
|
||||
(* Does virt-sysprep know how to sysprep this OS? *)
|
||||
and can_sysprep_os = function
|
||||
| RHEL _ | CentOS _ | Fedora _ | Debian _ | Ubuntu _ -> true
|
||||
| FreeBSD _ -> false
|
||||
| FreeBSD _ | Windows _ -> false
|
||||
|
||||
and is_selinux_os = function
|
||||
| RHEL _ | CentOS _ | Fedora _ -> true
|
||||
| Debian _ | Ubuntu _
|
||||
| FreeBSD _ -> false
|
||||
| FreeBSD _ | Windows _ -> false
|
||||
|
||||
and needs_uefi os arch =
|
||||
match os, arch with
|
||||
@@ -445,9 +473,17 @@ and needs_uefi os arch =
|
||||
| RHEL _, Aarch64 -> true
|
||||
| RHEL _, _ | CentOS _, _ | Fedora _, _
|
||||
| Debian _, _ | Ubuntu _, _
|
||||
| FreeBSD _, _ -> false
|
||||
| FreeBSD _, _ | Windows _, _ -> false
|
||||
|
||||
and get_virtual_size_gb os arch = 6
|
||||
and get_virtual_size_gb os arch =
|
||||
match os with
|
||||
| RHEL _ | CentOS _ | Fedora _
|
||||
| Debian _ | Ubuntu _
|
||||
| FreeBSD _ -> 6
|
||||
| Windows (10, _, _) -> 40 (* Windows 10 *)
|
||||
| Windows (6, _, _) -> 10 (* Windows from 2008 - 2012 *)
|
||||
| Windows (5, _, _) -> 6 (* Windows <= 2003 *)
|
||||
| Windows _ -> assert false
|
||||
|
||||
and make_kickstart os arch =
|
||||
match os with
|
||||
@@ -463,6 +499,9 @@ and make_kickstart os arch =
|
||||
(* Not automated. *)
|
||||
| FreeBSD _ -> None
|
||||
|
||||
(* Windows unattend.xml wrapped in an ISO. *)
|
||||
| Windows _ -> Some (make_unattend_iso os arch)
|
||||
|
||||
and make_kickstart_common ks_filename os arch =
|
||||
let buf = Buffer.create 4096 in
|
||||
let bpf fs = bprintf buf fs in
|
||||
@@ -640,6 +679,138 @@ and copy_preseed_to_temporary source =
|
||||
if Sys.command cmd <> 0 then exit 1;
|
||||
f
|
||||
|
||||
(* For Windows:
|
||||
* https://serverfault.com/questions/644437/unattended-installation-of-windows-server-2012-on-kvm
|
||||
*)
|
||||
and make_unattend_iso os arch =
|
||||
printf "enter Windows product key: ";
|
||||
let product_key = read_line () in
|
||||
|
||||
let output_iso =
|
||||
Sys.getcwd () // filename_of_os os arch "-unattend.iso" in
|
||||
unlink_on_exit output_iso;
|
||||
|
||||
let d = Filename.get_temp_dir_name () // random8 () in
|
||||
Unix.mkdir d 0o700;
|
||||
let config_dir = d // "config" in
|
||||
Unix.mkdir config_dir 0o700;
|
||||
let f = config_dir // "autounattend.xml" in
|
||||
|
||||
let chan = open_out f in
|
||||
let arch =
|
||||
match arch with
|
||||
| X86_64 -> "amd64"
|
||||
| I686 -> "x86"
|
||||
| _ ->
|
||||
eprintf "%s: Windows architecture %s not supported\n"
|
||||
prog (string_of_arch arch);
|
||||
exit 1 in
|
||||
(* Tip: If the install fails with a useless error "The answer file is
|
||||
* invalid", type Shift + F10 into the setup screen and look for a
|
||||
* file called \Windows\Panther\Setupact.log (NB:
|
||||
* not \Windows\Setupact.log)
|
||||
*)
|
||||
fprintf chan "
|
||||
<unattend xmlns=\"urn:schemas-microsoft-com:unattend\"
|
||||
xmlns:ms=\"urn:schemas-microsoft-com:asm.v3\"
|
||||
xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\">
|
||||
<settings pass=\"windowsPE\">
|
||||
<component name=\"Microsoft-Windows-Setup\"
|
||||
publicKeyToken=\"31bf3856ad364e35\"
|
||||
language=\"neutral\"
|
||||
versionScope=\"nonSxS\"
|
||||
processorArchitecture=\"%s\">
|
||||
<UserData>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
<ProductKey>
|
||||
<Key>%s</Key>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
</ProductKey>
|
||||
</UserData>
|
||||
|
||||
<DiskConfiguration>
|
||||
<Disk wcm:action=\"add\">
|
||||
<DiskID>0</DiskID>
|
||||
<WillWipeDisk>true</WillWipeDisk>
|
||||
<CreatePartitions>
|
||||
<!-- System partition -->
|
||||
<CreatePartition wcm:action=\"add\">
|
||||
<Order>1</Order>
|
||||
<Type>Primary</Type>
|
||||
<Size>300</Size>
|
||||
</CreatePartition>
|
||||
<!-- Windows partition -->
|
||||
<CreatePartition wcm:action=\"add\">
|
||||
<Order>2</Order>
|
||||
<Type>Primary</Type>
|
||||
<Extend>true</Extend>
|
||||
</CreatePartition>
|
||||
</CreatePartitions>
|
||||
<ModifyPartitions>
|
||||
<!-- System partition -->
|
||||
<ModifyPartition wcm:action=\"add\">
|
||||
<Order>1</Order>
|
||||
<PartitionID>1</PartitionID>
|
||||
<Label>System</Label>
|
||||
<Format>NTFS</Format>
|
||||
<Active>true</Active>
|
||||
</ModifyPartition>
|
||||
<!-- Windows partition -->
|
||||
<ModifyPartition wcm:action=\"add\">
|
||||
<Order>2</Order>
|
||||
<PartitionID>2</PartitionID>
|
||||
<Label>Windows</Label>
|
||||
<Letter>C</Letter>
|
||||
<Format>NTFS</Format>
|
||||
</ModifyPartition>
|
||||
</ModifyPartitions>
|
||||
</Disk>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
</DiskConfiguration>
|
||||
|
||||
<ImageInstall>
|
||||
<OSImage>
|
||||
<WillShowUI>Never</WillShowUI>
|
||||
<InstallFrom>
|
||||
<MetaData>
|
||||
<Key>/IMAGE/INDEX</Key>
|
||||
<Value>1</Value>
|
||||
</MetaData>
|
||||
</InstallFrom>
|
||||
<InstallTo>
|
||||
<DiskID>0</DiskID>
|
||||
<PartitionID>2</PartitionID>
|
||||
</InstallTo>
|
||||
</OSImage>
|
||||
</ImageInstall>
|
||||
</component>
|
||||
|
||||
<component name=\"Microsoft-Windows-International-Core-WinPE\"
|
||||
publicKeyToken=\"31bf3856ad364e35\"
|
||||
language=\"neutral\"
|
||||
versionScope=\"nonSxS\"
|
||||
processorArchitecture=\"%s\">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
</SetupUILanguage>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>"
|
||||
arch product_key arch;
|
||||
close_out chan;
|
||||
|
||||
let cmd = sprintf "cd %s && mkisofs -o %s -J -r config"
|
||||
(quote d) (quote output_iso) in
|
||||
if Sys.command cmd <> 0 then exit 1;
|
||||
let cmd = sprintf "rm -rf %s" (quote d) in
|
||||
if Sys.command cmd <> 0 then exit 1;
|
||||
|
||||
(* Return the name of the unattend ISO. *)
|
||||
output_iso
|
||||
|
||||
and make_boot_media os arch =
|
||||
match os, arch with
|
||||
| CentOS (major, _), Aarch64 ->
|
||||
@@ -753,6 +924,25 @@ and make_boot_media os arch =
|
||||
if Sys.command cmd <> 0 then exit 1;
|
||||
CDRom iso
|
||||
|
||||
| Windows (major, minor, variant), arch ->
|
||||
let iso_name =
|
||||
match major, minor, variant, arch with
|
||||
| 6, 1, Client, X86_64 -> (* Windows 7 *)
|
||||
"en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso"
|
||||
| 6, 1, Server, X86_64 -> (* Windows 2008 R2 *)
|
||||
"en_windows_server_2008_r2_with_sp1_x64_dvd_617601.iso"
|
||||
| 6, 2, Server, X86_64 -> (* Windows Server 2012 *)
|
||||
"en_windows_server_2012_x64_dvd_915478.iso"
|
||||
| 6, 3, Server, X86_64 -> (* Windows Server 2012 R2 *)
|
||||
"en_windows_server_2012_r2_with_update_x64_dvd_6052708.iso"
|
||||
| 10, 0, Server, X86_64 -> (* Windows Server 2016 *)
|
||||
"en_windows_server_2016_updated_feb_2018_x64_dvd_11636692.iso"
|
||||
| _ ->
|
||||
eprintf "%s: don't have an installer ISO for this version of Windows\n"
|
||||
prog;
|
||||
exit 1 in
|
||||
CDRom (windows_installers // iso_name)
|
||||
|
||||
| _ ->
|
||||
eprintf "%s: don't know how to calculate the --location for this OS and architecture\n" prog;
|
||||
exit 1
|
||||
@@ -776,7 +966,7 @@ The FreeBSD install is not automated. Select all defaults, except:
|
||||
(* If the install is not automated and we need a graphical console. *)
|
||||
and needs_graphics = function
|
||||
| CentOS _ | RHEL _ | Debian _ | Ubuntu _ | Fedora _ -> false
|
||||
| FreeBSD _ -> true
|
||||
| FreeBSD _ | Windows _ -> true
|
||||
|
||||
(* NB: Arguments do not need to be quoted, because we pass them
|
||||
* directly to exec(2).
|
||||
@@ -789,9 +979,23 @@ and make_virt_install_command os arch ks tmpname tmpout tmpefivars
|
||||
add "virt-install";
|
||||
|
||||
(* This ensures the libvirt domain will be automatically deleted
|
||||
* when virt-install exits.
|
||||
* when virt-install exits. However it doesn't work for certain
|
||||
* types of guest.
|
||||
*)
|
||||
add "--transient";
|
||||
(match os with
|
||||
| Windows _ ->
|
||||
printf "after Windows has installed, do:\n";
|
||||
printf " virsh shutdown %s\n virsh undefine %s\n%!" tmpname tmpname;
|
||||
| _ -> add "--transient"
|
||||
);
|
||||
|
||||
(* Don't try relabelling everything. This is particularly necessary
|
||||
* for the Windows install ISOs which are located on NFS.
|
||||
*)
|
||||
(match os with
|
||||
| Windows _ -> add "--security=type=none"
|
||||
| _ -> ()
|
||||
);
|
||||
|
||||
add (sprintf "--name=%s" tmpname);
|
||||
|
||||
@@ -845,7 +1049,7 @@ and make_virt_install_command os arch ks tmpname tmpout tmpefivars
|
||||
| Debian _ | Ubuntu _ -> "auto"
|
||||
| Fedora _ | RHEL _ | CentOS _ ->
|
||||
sprintf "ks=file:/%s" (Filename.basename ks)
|
||||
| FreeBSD _ -> assert false in
|
||||
| FreeBSD _ | Windows _ -> assert false in
|
||||
let proxy =
|
||||
let p = try Some (Sys.getenv "http_proxy") with Not_found -> None in
|
||||
match p with
|
||||
@@ -853,19 +1057,19 @@ and make_virt_install_command os arch ks tmpname tmpout tmpefivars
|
||||
(match os with
|
||||
| Fedora _ | RHEL _ | CentOS _ | Ubuntu _ -> ""
|
||||
| Debian _ -> "mirror/http/proxy="
|
||||
| FreeBSD _ -> assert false
|
||||
| FreeBSD _ | Windows _ -> assert false
|
||||
)
|
||||
| Some p ->
|
||||
match os with
|
||||
| Fedora _ | RHEL _ | CentOS _ -> "proxy=" ^ p
|
||||
| Debian _ | Ubuntu _ -> "mirror/http/proxy=" ^ p
|
||||
| FreeBSD _ -> assert false in
|
||||
| FreeBSD _ | Windows _ -> assert false in
|
||||
|
||||
add (sprintf "--extra-args=%s %s %s" (* sic: does NOT need to be quoted *)
|
||||
os_extra proxy (kernel_cmdline_of_os os arch));
|
||||
|
||||
(* doesn't need --initrd-inject *)
|
||||
| FreeBSD _ -> ()
|
||||
| FreeBSD _ | Windows _ -> ()
|
||||
);
|
||||
|
||||
add (sprintf "--disk=%s,size=%d,format=raw"
|
||||
@@ -873,7 +1077,19 @@ and make_virt_install_command os arch ks tmpname tmpout tmpefivars
|
||||
|
||||
(match boot_media with
|
||||
| Location location -> add (sprintf "--location=%s" location)
|
||||
| CDRom iso -> add (sprintf "--cdrom=%s" iso)
|
||||
| CDRom iso -> add (sprintf "--disk=%s,device=cdrom,boot_order=1" iso)
|
||||
);
|
||||
|
||||
(* Windows requires one or two extra CDs!
|
||||
* See: https://serverfault.com/questions/644437/unattended-installation-of-windows-server-2012-on-kvm
|
||||
*)
|
||||
(match os with
|
||||
| Windows _ ->
|
||||
let unattend_iso =
|
||||
match ks with None -> assert false | Some ks -> ks in
|
||||
(*add "--disk=/usr/share/virtio-win/virtio-win.iso,device=cdrom,boot_order=98";*)
|
||||
add (sprintf "--disk=%s,device=cdrom,boot_order=99" unattend_iso)
|
||||
| _ -> ()
|
||||
);
|
||||
|
||||
add "--serial=pty";
|
||||
@@ -907,6 +1123,13 @@ and os_variant_of_os ?(for_fedora = false) os arch =
|
||||
| Debian (ver, _) -> sprintf "debian%d" ver
|
||||
| Ubuntu (ver, _) -> sprintf "ubuntu%s" ver
|
||||
| FreeBSD (major, minor) -> sprintf "freebsd%d.%d" major minor
|
||||
|
||||
| Windows (6, 1, Client) -> "win7"
|
||||
| Windows (6, 1, Server) -> "win2k8r2"
|
||||
| Windows (6, 2, Server) -> "win2k12"
|
||||
| Windows (6, 3, Server) -> "win2k12r2"
|
||||
| Windows (10, 0, Server) -> "win2k16"
|
||||
| Windows _ -> assert false
|
||||
)
|
||||
else (
|
||||
match os, arch with
|
||||
@@ -935,6 +1158,13 @@ and os_variant_of_os ?(for_fedora = false) os arch =
|
||||
| Ubuntu _, _ -> assert false
|
||||
|
||||
| FreeBSD (major, minor), _ -> sprintf "freebsd%d.%d" major minor
|
||||
|
||||
| Windows (6, 1, Client), _ -> "win7"
|
||||
| Windows (6, 1, Server), _ -> "win2k8r2"
|
||||
| Windows (6, 2, Server), _ -> "win2k12"
|
||||
| Windows (6, 3, Server), _ -> "win2k12r2"
|
||||
| Windows (10, 0, Server), _ -> "win2k16"
|
||||
| Windows _, _ -> assert false
|
||||
)
|
||||
|
||||
and kernel_cmdline_of_os os arch =
|
||||
@@ -952,7 +1182,8 @@ and kernel_cmdline_of_os os arch =
|
||||
| (RHEL _|CentOS _), PPC64
|
||||
| (RHEL _|CentOS _), PPC64le ->
|
||||
"console=tty0 console=ttyS0,115200 rd_NO_PLYMOUTH"
|
||||
| FreeBSD _, (PPC64|PPC64le) -> assert false
|
||||
|
||||
| FreeBSD _, _ | Windows _, _ -> assert false
|
||||
|
||||
and make_postinstall os arch =
|
||||
match os with
|
||||
@@ -974,7 +1205,7 @@ and make_postinstall os arch =
|
||||
g#write "/etc/yum.repos.d/download.devel.redhat.com.repo" yum_conf
|
||||
)
|
||||
|
||||
| RHEL _ | Fedora _ | CentOS _ | FreeBSD _ -> None
|
||||
| RHEL _ | Fedora _ | CentOS _ | FreeBSD _ | Windows _ -> None
|
||||
|
||||
and make_rhel_yum_conf major minor arch =
|
||||
let buf = Buffer.create 4096 in
|
||||
@@ -1156,6 +1387,18 @@ and long_name_of_os os arch =
|
||||
| FreeBSD (major, minor), arch ->
|
||||
sprintf "FreeBSD %d.%d (%s)" major minor (string_of_arch arch)
|
||||
|
||||
| Windows (6, 1, Client), arch ->
|
||||
sprintf "Windows 7 (%s)" (string_of_arch arch)
|
||||
| Windows (6, 1, Server), arch ->
|
||||
sprintf "Windows Server 2008 R2 (%s)" (string_of_arch arch)
|
||||
| Windows (6, 2, Server), arch ->
|
||||
sprintf "Windows Server 2012 (%s)" (string_of_arch arch)
|
||||
| Windows (6, 3, Server), arch ->
|
||||
sprintf "Windows Server 2012 R2 (%s)" (string_of_arch arch)
|
||||
| Windows (10, 0, Server), arch ->
|
||||
sprintf "Windows Server 2016 (%s)" (string_of_arch arch)
|
||||
| Windows _, _ -> assert false
|
||||
|
||||
and notes_of_os os arch nvram =
|
||||
let args = ref [] in
|
||||
let add arg = args := arg :: !args in
|
||||
@@ -1178,6 +1421,10 @@ and notes_of_os os arch nvram =
|
||||
add "This is a minimal Ubuntu install."
|
||||
| FreeBSD _ ->
|
||||
add "This is an all-default FreeBSD install."
|
||||
| Windows _ ->
|
||||
add "This is an unattended Windows install.";
|
||||
add "";
|
||||
add "You must have an MSDN subscription to use this image."
|
||||
);
|
||||
add "";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user