-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
--------- Co-authored-by: Gabriel Ramirez <[email protected]> Co-authored-by: Alan Baghumian <[email protected]>
- Loading branch information
1 parent
3a4660f
commit 6682b3b
Showing
17 changed files
with
860 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
http/Autounattend.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#!/usr/bin/make -f | ||
|
||
include ../scripts/check.mk | ||
|
||
PACKER ?= packer | ||
PACKER_LOG ?= 0 | ||
export PACKER_LOG | ||
|
||
ISO ?= | ||
VERSION ?= 2022 | ||
BOOT ?= uefi | ||
HEADLESS ?= false | ||
|
||
ifeq ($(strip $(VERSION)),10) | ||
TYPE = Windows | ||
EDIT ?= PRO | ||
else ifeq ($(strip $(VERSION)),11) | ||
TYPE = Windows | ||
EDIT ?= PRO | ||
else | ||
TYPE = Windows Server | ||
EDIT ?= SERVERSTANDARD | ||
endif | ||
|
||
ifeq ($(wildcard /usr/share/OVMF/OVMF_CODE.fd),) | ||
OVMF_SFX ?= _4M | ||
else | ||
OVMF_SFX ?= | ||
endif | ||
|
||
.PHONY: all clean | ||
|
||
all: windows | ||
|
||
$(eval $(call check_packages_deps,cloud-image-utils ovmf,cloud-image-utils ovmf)) | ||
|
||
OVMF_VARS.fd: /usr/share/OVMF/OVMF_VARS*.fd | ||
cp -v $< $@ | ||
|
||
http/Autounattend.xml: http/Autounattend.xml.${BOOT}.template | ||
sed s#@VERSION@#"${TYPE} ${VERSION} ${EDIT}"#g $< > $@ | ||
ifneq ($(strip $(PKEY1)),) | ||
sed -i s#@PKEY@#${PKEY}#g $@ | ||
sed -i 's/<!--<ProductKey>/<ProductKey>/;s/<\/ProductKey>-->/<\/ProductKey>/' $@ | ||
endif | ||
ifeq ($(strip $(VERSION)),10) | ||
sed -i 's/<!--<LocalAccounts>/<LocalAccounts>/;s/<\/LocalAccounts>-->/<\/LocalAccounts>/' $@ | ||
else ifeq ($(strip $(VERSION)),11) | ||
sed -i 's/<!--<LocalAccounts>/<LocalAccounts>/;s/<\/LocalAccounts>-->/<\/LocalAccounts>/' $@ | ||
endif | ||
|
||
extra_drivers: | ||
mkisofs -o drivers.iso -V 'Extra Drivers' -input-charset utf-8 drivers | ||
|
||
.INTERMEDIATE: extra_drivers http/Autounattend.xml | ||
|
||
windows: check-deps clean extra_drivers http/Autounattend.xml OVMF_VARS.fd | ||
${PACKER} init . && ${PACKER} build -var iso_path=${ISO} \ | ||
-var headless=${HEADLESS} \ | ||
-var ovmf_suffix=${OVMF_SFX} \ | ||
windows.pkr.hcl | ||
|
||
clean: | ||
${RM} -rf output-* windows.tar.gz http/Autounattend.xml \ | ||
drivers.iso OVMF_VARS.fd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Packer Template for Microsoft Windows | ||
|
||
## Introduction | ||
|
||
The Packer templates in this directory creates Windows Server images for use with MAAS. | ||
|
||
|
||
## Prerequisites (to create the image) | ||
|
||
* A machine running Ubuntu 18.04+ with the ability to run KVM virtual machines. | ||
* qemu-utils, libnbd-bin, nbdkit and fuse2fs | ||
* qemu-system | ||
* ovmf | ||
* cloud-image-utils | ||
* [Packer](https://www.packer.io/intro/getting-started/install.html), v1.7.0 or newer | ||
|
||
|
||
## Requirements (to deploy the image) | ||
|
||
* [MAAS](https://maas.io) 3.2+ | ||
* [Curtin](https://launchpad.net/curtin) 21.0+ | ||
|
||
|
||
## Supported Microsoft Windows Versions | ||
|
||
This process has been build and deployment tested with the following versions of | ||
Microsoft Windows: | ||
|
||
* Windows Server 2022 | ||
* Windows Server 2019 | ||
* Windows Server 2016 | ||
* Windows 10 Pro 22H2 | ||
|
||
|
||
## Known Issues | ||
|
||
* The current process builds UEFI compatible images only. | ||
|
||
|
||
## windows.json Template | ||
|
||
This template builds a dd.tgz MAAS image from an official Microsoft Windows ISO. | ||
This process also installs the latest VirtIO drivers as well as Cloudbase-init. | ||
|
||
|
||
## Obtaining Microsoft Windows ISO images | ||
|
||
You can obtains Microsoft Windows Evaluation ISO images from the following links: | ||
|
||
* [Windows Server 2022](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2022) | ||
* [Windows Server 2019](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2019) | ||
* [Windows Server 2016](https://www.microsoft.com/en-us/evalcenter/download-windows-server-2016) | ||
|
||
|
||
### Building the image | ||
|
||
The build the image you give the template a script which has all the | ||
customization: | ||
|
||
```shell | ||
sudo make windows ISO=<path-to-iso> VERSION=<windows-version> windows.json | ||
``` | ||
|
||
### Makefile Parameters | ||
|
||
#### BOOT | ||
|
||
Currently uefi is the only supported value. | ||
|
||
#### EDIT | ||
|
||
The edition of a targeted ISO image. It defaults to PRO for Microsoft Windows 10/11 | ||
and SERVERSTANDARD for Microsoft Windows Servers. Many Microsoft Windows Server ISO | ||
images do contain multiple editions and this prarameter is useful to build a particular | ||
edition such as Standard or Datacenter etc. | ||
|
||
#### HEADLESS | ||
|
||
Whether VNC viewer should not be launched. Default is set to false. | ||
|
||
#### ISO | ||
|
||
Path to Microsoft Windows ISO used to build the image. | ||
|
||
#### PACKER_LOG | ||
|
||
Enable (1) or Disable (0) verbose packer logs. The default value is set to 0. | ||
|
||
#### PKEY | ||
|
||
User supplied Microsoft Windows Product Key. When usimg KMS, you can obtain the | ||
activation keys from the link below: | ||
|
||
* [KMS Client Activation and Product Keys](https://learn.microsoft.com/en-us/windows-server/get-started/kms-client-activation-keys) | ||
|
||
Please note that PKEY is an optional parameter but it might be required during | ||
the build time depending on the type of ISO being used. Evaluation series ISO | ||
images usually do not require a product key to proceed, however this is not | ||
true with Enterprise and Retail ISO images. | ||
|
||
#### VERSION | ||
|
||
Specify the Microsoft Windows Version. Example inputs include: 2022, 2019, 2016 | ||
and 10. | ||
|
||
|
||
## Uploading images to MAAS | ||
|
||
Use MAAS CLI to upload the image: | ||
|
||
```shell | ||
maas admin boot-resources create \ | ||
name='windows/windows-server' \ | ||
title='Windows Server' \ | ||
architecture='amd64/generic' \ | ||
filetype='ddtgz' \ | ||
content@=windows-server-amd64-root-dd.gz | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
## To be implemented (TODO List) | ||
|
||
* Complete the support for build-time driver injection. | ||
* Add support for BIOS based deployments. | ||
* Add support for Windows 11 which requires TPM 2.0. | ||
* Migrate scripts/setup-nbd to use fuse. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This has been cloned from the following Git repository: | ||
|
||
[Windows Curtin Hooks](https://github.com/cloudbase/windows-curtin-hooks.git) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
#!/bin/bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/bin/bash | ||
|
||
PYTHON2=`/bin/which python` | ||
PYTHON3=`/bin/which python3` | ||
|
||
PYTHON=${PYTHON2:-$PYTHON3} | ||
|
||
if [ -z $PYTHON ] | ||
then | ||
echo "Failed to find python interpretor" | ||
exit 1 | ||
fi | ||
|
||
SCRIPT_DIR=`/usr/bin/dirname $0` | ||
ABSPATH=`/bin/readlink -m $SCRIPT_DIR` | ||
|
||
FINALIZE="$ABSPATH/finalize.py" | ||
|
||
if [ ! -e $FINALIZE ] | ||
then | ||
echo "No finalize script available" | ||
exit 0 | ||
fi | ||
|
||
$PYTHON $FINALIZE | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# | ||
# Copyright 2015 Cloudbase Solutions SRL | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
|
||
import os | ||
import sys | ||
import tempfile | ||
import yaml | ||
import platform | ||
import json | ||
|
||
from curtin.log import LOG | ||
from curtin import util | ||
try: | ||
from curtin.util import load_command_config | ||
except ImportError: | ||
from curtin.config import load_command_config | ||
|
||
CLOUDBASE_INIT_TEMPLATE = """ | ||
metadata_services=cloudbaseinit.metadata.services.maasservice.MaaSHttpService | ||
maas_metadata_url={url} | ||
maas_oauth_consumer_key={consumer_key} | ||
maas_oauth_consumer_secret='' | ||
maas_oauth_token_key={token_key} | ||
maas_oauth_token_secret={token_secret} | ||
""" | ||
|
||
CHANGE_LICENSE_TPL = """ | ||
slmgr /ipk {license_key} | ||
""" | ||
|
||
def get_oauth_data(state): | ||
cfg = state.get("debconf_selections") | ||
if not cfg: | ||
return None | ||
maas = cfg.get("maas") | ||
if not maas: | ||
return None | ||
data = {i.split(None, 3)[1].split("/")[1]: i.split(None, 3)[-1] for i in maas.split("\n") if len(i) > 0} | ||
oauth_data = data.get("maas-metadata-credentials") | ||
metadata_url = data.get("maas-metadata-url") | ||
if oauth_data is None or metadata_url is None: | ||
return None | ||
oauth_dict = {k.split("=")[0].split("_",1)[1]: k.split("=")[1] for k in oauth_data.split("&")} | ||
oauth_dict["url"] = metadata_url | ||
return oauth_dict | ||
|
||
def get_cloudbaseinit_dir(target): | ||
dirs = [ | ||
os.path.join( | ||
target, | ||
"Cloudbase-Init", | ||
), | ||
os.path.join( | ||
target, | ||
"Program Files", | ||
"Cloudbase Solutions", | ||
"Cloudbase-Init", | ||
), | ||
os.path.join( | ||
target, | ||
"Program Files (x86)", | ||
"Cloudbase Solutions", | ||
"Cloudbase-Init", | ||
), | ||
] | ||
for i in dirs: | ||
if os.path.isdir(i): | ||
return i | ||
raise ValueError("Failed to find cloudbase-init install destination") | ||
|
||
def curthooks(): | ||
state = util.load_command_environment() | ||
config = load_command_config({}, state) | ||
target = state['target'] | ||
cloudbaseinit = get_cloudbaseinit_dir(target) | ||
|
||
if target is None: | ||
sys.stderr.write("Unable to find target. " | ||
"Use --target or set TARGET_MOUNT_POINT\n") | ||
sys.exit(2) | ||
|
||
context = get_oauth_data(config) | ||
local_scripts = os.path.join( | ||
cloudbaseinit, | ||
"LocalScripts", | ||
) | ||
|
||
networking = config.get("network") | ||
if networking: | ||
curtin_dir = os.path.join(target, "curtin") | ||
networking_file = os.path.join(target, "network.json") | ||
if os.path.isdir(curtin_dir): | ||
networking_file = os.path.join(curtin_dir, "network.json") | ||
with open(networking_file, "wb") as fd: | ||
fd.write(json.dumps(networking, indent=2).encode('utf-8')) | ||
|
||
license_key = config.get("license_key") | ||
if license_key and len(license_key) > 0: | ||
try: | ||
license_script = CHANGE_LICENSE_TPL.format({"license_key": license_key}) | ||
os.makedirs(local_scripts) | ||
licensekey_path = os.path.join(local_scripts, "ChangeLicenseKey.ps1") | ||
with open(licensekey_path, "w") as script: | ||
script.write(license_script) | ||
except Exception as err: | ||
sys.stderr.write("Failed to write LocalScripts: %r", err) | ||
cloudbase_init_cfg = os.path.join( | ||
cloudbaseinit, | ||
"conf", | ||
"cloudbase-init.conf") | ||
cloudbase_init_unattended_cfg = os.path.join( | ||
cloudbaseinit, | ||
"conf", | ||
"cloudbase-init-unattend.conf") | ||
|
||
if os.path.isfile(cloudbase_init_cfg) is False: | ||
sys.stderr.write("Unable to find cloudbase-init.cfg.\n") | ||
sys.exit(2) | ||
|
||
cloudbase_init_values = CLOUDBASE_INIT_TEMPLATE.format(**context) | ||
|
||
fp = open(cloudbase_init_cfg, 'a') | ||
fp_u = open(cloudbase_init_unattended_cfg, 'a') | ||
for i in cloudbase_init_values.splitlines(): | ||
fp.write("%s\r\n" % i) | ||
fp_u.write("%s\r\n" % i) | ||
fp.close() | ||
fp_u.close() | ||
|
||
|
||
curthooks() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#### Extra Windows drivers | ||
Place all extra Windows drivers under infs directory. | ||
|
||
Please note that these drivers will be installed using | ||
dpinst.exe which does not support scanning sub directories. | ||
|
||
This requires all drivers to be present directly under the | ||
infs directory. | ||
|
||
These can include custom Windows drivers needed by certain | ||
hardware components to function, either becuase the drivers | ||
are not natively availble in Windows or would require extra | ||
optimization. | ||
|
Empty file.
Empty file.
Oops, something went wrong.