underpost 2.96.0 → 2.96.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/baremetal/packer-workflows.json +11 -0
- package/cli.md +2 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -1
- package/packer/images/Rocky9Amd64/rocky9.pkr.hcl +6 -2
- package/packer/images/Rocky9Arm64/Makefile +69 -0
- package/packer/images/Rocky9Arm64/README.md +122 -0
- package/packer/images/Rocky9Arm64/http/rocky9.ks.pkrtpl.hcl +114 -0
- package/packer/images/Rocky9Arm64/rocky9.pkr.hcl +171 -0
- package/scripts/packer-init-vars-file.sh +16 -6
- package/scripts/packer-setup.sh +270 -33
- package/src/cli/baremetal.js +106 -7
- package/src/cli/index.js +4 -0
- package/src/index.js +2 -1
- package/manifests/mariadb/config.yaml +0 -10
- package/manifests/mariadb/secret.yaml +0 -8
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<!-- badges -->
|
|
20
20
|
|
|
21
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/2.96.1) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](https://www.npmjs.com/package/underpost)
|
|
22
22
|
|
|
23
23
|
<!-- end-badges -->
|
|
24
24
|
|
|
@@ -66,7 +66,7 @@ Run dev client server
|
|
|
66
66
|
npm run dev
|
|
67
67
|
```
|
|
68
68
|
<!-- -->
|
|
69
|
-
## underpost ci/cd cli v2.96.
|
|
69
|
+
## underpost ci/cd cli v2.96.1
|
|
70
70
|
|
|
71
71
|
### Usage: `underpost [options] [command]`
|
|
72
72
|
```
|
|
@@ -9,5 +9,16 @@
|
|
|
9
9
|
"filetype": "tgz",
|
|
10
10
|
"content": "rocky9.tar.gz"
|
|
11
11
|
}
|
|
12
|
+
},
|
|
13
|
+
"Rocky9Arm64": {
|
|
14
|
+
"dir": "packer/images/Rocky9Arm64",
|
|
15
|
+
"maas": {
|
|
16
|
+
"name": "custom/rocky9-arm64",
|
|
17
|
+
"title": "Rocky 9 Arm64 Custom",
|
|
18
|
+
"architecture": "arm64/generic",
|
|
19
|
+
"base_image": "rhel/9",
|
|
20
|
+
"filetype": "tgz",
|
|
21
|
+
"content": "rocky9.tar.gz"
|
|
22
|
+
}
|
|
12
23
|
}
|
|
13
24
|
}
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.96.
|
|
1
|
+
## underpost ci/cd cli v2.96.1
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -909,6 +909,7 @@ Options:
|
|
|
909
909
|
--packer-workflow-id <workflow-id> Specifies the workflow ID for Packer MAAS image operations.
|
|
910
910
|
--packer-maas-image-build Builds a MAAS image using Packer for the workflow specified by --packer-workflow-id.
|
|
911
911
|
--packer-maas-image-upload Uploads an existing MAAS image artifact without rebuilding for the workflow specified by --packer-workflow-id.
|
|
912
|
+
--packer-maas-image-cached Continue last build without removing artifacts (used with --packer-maas-image-build).
|
|
912
913
|
--commission Init workflow for commissioning a physical machine.
|
|
913
914
|
--nfs-build Builds an NFS root filesystem for a workflow id config architecture using QEMU emulation.
|
|
914
915
|
--nfs-mount Mounts the NFS root filesystem for a workflow id config architecture.
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.96.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.96.1
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -100,7 +100,7 @@ spec:
|
|
|
100
100
|
spec:
|
|
101
101
|
containers:
|
|
102
102
|
- name: dd-default-development-green
|
|
103
|
-
image: localhost/rockylinux9-underpost:v2.96.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.96.1
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
|
@@ -18,7 +18,7 @@ spec:
|
|
|
18
18
|
spec:
|
|
19
19
|
containers:
|
|
20
20
|
- name: dd-test-development-blue
|
|
21
|
-
image: localhost/rockylinux9-underpost:v2.96.
|
|
21
|
+
image: localhost/rockylinux9-underpost:v2.96.1
|
|
22
22
|
|
|
23
23
|
command:
|
|
24
24
|
- /bin/sh
|
|
@@ -103,7 +103,7 @@ spec:
|
|
|
103
103
|
spec:
|
|
104
104
|
containers:
|
|
105
105
|
- name: dd-test-development-green
|
|
106
|
-
image: localhost/rockylinux9-underpost:v2.96.
|
|
106
|
+
image: localhost/rockylinux9-underpost:v2.96.1
|
|
107
107
|
|
|
108
108
|
command:
|
|
109
109
|
- /bin/sh
|
package/package.json
CHANGED
|
@@ -107,8 +107,12 @@ source "qemu" "rocky9" {
|
|
|
107
107
|
disk_size = "45G"
|
|
108
108
|
format = "qcow2"
|
|
109
109
|
headless = var.headless
|
|
110
|
-
iso_checksum = "file:
|
|
111
|
-
|
|
110
|
+
iso_checksum = "file:https://download.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/CHECKSUM"
|
|
111
|
+
iso_urls = [
|
|
112
|
+
"https://download.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso",
|
|
113
|
+
"https://dl.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso",
|
|
114
|
+
"https://mirrors.edge.kernel.org/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso"
|
|
115
|
+
]
|
|
112
116
|
iso_target_path = "packer_cache/Rocky-9-latest-${local.iso_arch}-boot.iso"
|
|
113
117
|
memory = 2048
|
|
114
118
|
cores = 4
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/make -f
|
|
2
|
+
|
|
3
|
+
include ../../scripts/check.mk
|
|
4
|
+
|
|
5
|
+
PACKER ?= packer
|
|
6
|
+
PACKER_LOG ?= 0
|
|
7
|
+
TIMEOUT ?= 1h
|
|
8
|
+
ARCH ?= arm64
|
|
9
|
+
|
|
10
|
+
# Detect if running on ARM host
|
|
11
|
+
ifeq ($(shell uname -m),aarch64)
|
|
12
|
+
HOST_IS_ARM = true
|
|
13
|
+
else
|
|
14
|
+
HOST_IS_ARM = false
|
|
15
|
+
endif
|
|
16
|
+
|
|
17
|
+
ifeq ($(wildcard /usr/share/OVMF/OVMF_CODE.fd),)
|
|
18
|
+
OVMF_SFX ?= _4M
|
|
19
|
+
else
|
|
20
|
+
OVMF_SFX ?=
|
|
21
|
+
endif
|
|
22
|
+
|
|
23
|
+
export PACKER_LOG
|
|
24
|
+
|
|
25
|
+
# Fallback
|
|
26
|
+
ifeq ($(strip $(ARCH)),amd64)
|
|
27
|
+
ARCH = x86_64
|
|
28
|
+
endif
|
|
29
|
+
ifeq ($(strip $(ARCH)),arm64)
|
|
30
|
+
ARCH = aarch64
|
|
31
|
+
endif
|
|
32
|
+
|
|
33
|
+
.PHONY: all clean
|
|
34
|
+
|
|
35
|
+
all: rocky9.tar.gz
|
|
36
|
+
|
|
37
|
+
$(eval $(call check_packages_deps))
|
|
38
|
+
|
|
39
|
+
lint:
|
|
40
|
+
packer validate .
|
|
41
|
+
packer fmt -check -diff .
|
|
42
|
+
|
|
43
|
+
format:
|
|
44
|
+
packer fmt .
|
|
45
|
+
|
|
46
|
+
OVMF_VARS.fd:
|
|
47
|
+
ifeq ($(strip $(ARCH)),aarch64)
|
|
48
|
+
cp -v /usr/share/AAVMF/AAVMF_VARS.fd ${ARCH}_VARS.fd
|
|
49
|
+
else
|
|
50
|
+
cp -v /usr/share/OVMF/OVMF_VARS${OVMF_SFX}.fd ${ARCH}_VARS.fd
|
|
51
|
+
endif
|
|
52
|
+
|
|
53
|
+
SIZE_VARS.fd:
|
|
54
|
+
ifeq ($(strip $(ARCH)),aarch64)
|
|
55
|
+
truncate -s 64m ${ARCH}_VARS.fd
|
|
56
|
+
else
|
|
57
|
+
truncate -s 2m ${ARCH}_VARS.fd
|
|
58
|
+
endif
|
|
59
|
+
|
|
60
|
+
rocky9.tar.gz: check-deps clean OVMF_VARS.fd SIZE_VARS.fd
|
|
61
|
+
${PACKER} init rocky9.pkr.hcl && ${PACKER} build \
|
|
62
|
+
-var architecture=${ARCH} \
|
|
63
|
+
-var host_is_arm=${HOST_IS_ARM} \
|
|
64
|
+
-var timeout=${TIMEOUT} \
|
|
65
|
+
-var ovmf_suffix=${OVMF_SFX} \
|
|
66
|
+
rocky9.pkr.hcl
|
|
67
|
+
|
|
68
|
+
clean:
|
|
69
|
+
${RM} -rf *.fd output-rocky9 rocky9.tar.gz
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Rocky 9 Packer template for MAAS
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
The Packer template in this directory creates a Rocky 9 AMD64/ARM64 image for use with MAAS.
|
|
6
|
+
|
|
7
|
+
## Prerequisites to create the image
|
|
8
|
+
|
|
9
|
+
* A machine running Ubuntu 22.04+ with the ability to run KVM virtual machines.
|
|
10
|
+
* qemu-utils, libnbd-bin, nbdkit and fuse2fs
|
|
11
|
+
* qemu-system
|
|
12
|
+
* qemu-system-modules-spice (If building on Ubuntu 24.04 LTS "Noble")
|
|
13
|
+
* ovmf
|
|
14
|
+
* cloud-image-utils
|
|
15
|
+
* parted
|
|
16
|
+
* [Packer.](https://www.packer.io/intro/getting-started/install.html), v1.11.0 or newer
|
|
17
|
+
|
|
18
|
+
## Requirements to deploy the image
|
|
19
|
+
|
|
20
|
+
* [MAAS](https://maas.io) 3.3 or later, as that version introduces support for Rocky
|
|
21
|
+
* [Curtin](https://launchpad.net/curtin) 22.1. If you have a MAAS with an earlier Curtin version, you can [patch](https://code.launchpad.net/~xnox/curtin/+git/curtin/+merge/415604) distro.py to deploy Rocky.
|
|
22
|
+
|
|
23
|
+
## Customizing the image
|
|
24
|
+
|
|
25
|
+
You can customize the deployment image by modifying http/rocky.ks. See the [RHEL kickstart documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/performing_an_advanced_rhel_installation/kickstart-commands-and-options-reference_installing-rhel-as-an-experienced-user#part-or-partition_kickstart-commands-for-handling-storage) for more information.
|
|
26
|
+
|
|
27
|
+
## Building the image using a proxy
|
|
28
|
+
|
|
29
|
+
The Packer template downloads the Rocky ISO image from the Internet. You can tell Packer to use a proxy by setting the HTTP_PROXY environment variable to point to your proxy server. You can also redefine rocky_iso_url to a local file. If you want to skip the base image integrity check, set iso_checksum_type to none and remove iso_checksum.
|
|
30
|
+
|
|
31
|
+
To use a proxy during the installation define the `KS_PROXY` variable in the environment, as bellow:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
export KS_PROXY="\"${HTTP_PROXY}\""
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
# Building the image using a kickstart mirror
|
|
38
|
+
|
|
39
|
+
To tell Packer to use a specific mirror set the `KS_MIRROR` environment variable
|
|
40
|
+
poiniting to the mirror URL.
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
export KS_MIRROR="https://dl.rockylinux.org/pub/rocky/9"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Building an image
|
|
47
|
+
|
|
48
|
+
You can build the image using the Makefile:
|
|
49
|
+
|
|
50
|
+
```shell
|
|
51
|
+
make
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You can also manually run packer. Set your current working directory to packer-maas/rocky9, where this file resides, and generate an image with:
|
|
55
|
+
|
|
56
|
+
```shell
|
|
57
|
+
packer init
|
|
58
|
+
PACKER_LOG=1 packer build .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The installation runs in a non-interactive mode.
|
|
62
|
+
|
|
63
|
+
Note: rocky9.pkr.hcl runs Packer in headless mode, with the serial port output from qemu redirected to stdio to give feedback on image creation process. If you wish to see more, change the value of `headless` to `false` in rocky9.pkr.hcl, remove `[ "-serial", "stdio" ]` from `qemuargs` section and select `View`, then `serial0` in the qemu window that appears during build. This lets you watch progress of the image build script. Press `ctrl-b 2` to switch to shell to explore more, and `ctrl-b 1` to go back to log view.
|
|
64
|
+
|
|
65
|
+
### Makefile Parameters
|
|
66
|
+
|
|
67
|
+
#### ARCH
|
|
68
|
+
|
|
69
|
+
Defaults to x86_64 to build AMD64 compatible images. In order to build ARM64 images, use ARCH=aarch64
|
|
70
|
+
|
|
71
|
+
#### TIMEOUT
|
|
72
|
+
|
|
73
|
+
The timeout to apply when building the image. The default value is set to 1h.
|
|
74
|
+
|
|
75
|
+
## Uploading an image to MAAS
|
|
76
|
+
|
|
77
|
+
```shell
|
|
78
|
+
maas $PROFILE boot-resources create name='custom/rocky9' \
|
|
79
|
+
title='Rocky 9 Custom' architecture='amd64/generic' \
|
|
80
|
+
base_image='rhel/9' filetype='tgz' \
|
|
81
|
+
content@=rocky9.tar.gz
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For ARM64, use:
|
|
85
|
+
|
|
86
|
+
```shell
|
|
87
|
+
maas $PROFILE boot-resources create name='custom/rocky9' \
|
|
88
|
+
title='Rocky 9 Custom' architecture='arm64/generic' \
|
|
89
|
+
base_image='rhel/9' filetype='tgz' \
|
|
90
|
+
content@=rocky9.tar.gz
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Please note that, currently due to lack of support in curtin, deploying ARM64 images needs a preseed file. This is due to [LP# 2090874](https://bugs.launchpad.net/curtin/+bug/2090874) and currently is in the process of getting fixed.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
#cloud-config
|
|
97
|
+
debconf_selections:
|
|
98
|
+
maas: |
|
|
99
|
+
{{for line in str(curtin_preseed).splitlines()}}
|
|
100
|
+
{{line}}
|
|
101
|
+
{{endfor}}
|
|
102
|
+
|
|
103
|
+
extract_commands:
|
|
104
|
+
grub_install: curtin in-target -- cp -v /boot/efi/EFI/rocky/shimaa64.efi /boot/efi/EFI/rocky/shimx64.efi
|
|
105
|
+
|
|
106
|
+
late_commands:
|
|
107
|
+
maas: [wget, '--no-proxy', '{{node_disable_pxe_url}}', '--post-data', '{{node_disable_pxe_data}}', '-O', '/dev/null']
|
|
108
|
+
bootloader_01: ["curtin", "in-target", "--", "cp", "-v", "/boot/efi/EFI/rocky/shimaa64.efi", "/boot/efi/EFI/BOOT/bootaa64.efi"]
|
|
109
|
+
bootloader_02: ["curtin", "in-target", "--", "cp", "-v", "/boot/efi/EFI/rocky/grubaa64.efi", "/boot/efi/EFI/BOOT/"]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This file needs to be saved on Region Controllers under /var/snap/maas/current/preseeds/curtin_userdata_custom_arm64_generic_rocky9 or /etc/maas/preseeds/curtin_userdata_custom_arm64_generic_rocky9. The last portion of this file must match the image name uploaded in MAAS.
|
|
113
|
+
|
|
114
|
+
## Default username
|
|
115
|
+
|
|
116
|
+
MAAS uses cloud-init to create ```cloud-user``` account using the ssh keys configured for the MAAS admin user (e.g. imported from Launchpad). Log in to the machine:
|
|
117
|
+
|
|
118
|
+
```shell
|
|
119
|
+
ssh -i ~/.ssh/<your_identity_file> cloud-user@<machine-ip-address>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Next to that, the kickstart script creates an account with both username and password set to ```rocky```. Note that the default sshd configuration in Rocky 9 disallows password-based authentication when logging in via ssh, so trying `ssh rocky@<machine-ip-address>` will fail. Password-based authentication can be enabled by having `PasswordAuthentication yes` in /etc/ssh/sshd_config after logging in with ```cloud-user```. Perhaps there is a way to make that change using kickstart script, but it is not obvious as ```anaconda```, the installer, makes its own changes to sshd_config file during installation. If you know how to do this, a PR is welcome.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
url ${KS_OS_REPOS} ${KS_PROXY}
|
|
2
|
+
repo --name="AppStream" ${KS_APPSTREAM_REPOS} ${KS_PROXY}
|
|
3
|
+
repo --name="Extras" ${KS_EXTRAS_REPOS} ${KS_PROXY}
|
|
4
|
+
|
|
5
|
+
eula --agreed
|
|
6
|
+
|
|
7
|
+
# Turn off after installation
|
|
8
|
+
poweroff
|
|
9
|
+
|
|
10
|
+
# Do not start the Inital Setup app
|
|
11
|
+
firstboot --disable
|
|
12
|
+
|
|
13
|
+
# System language, keyboard and timezone
|
|
14
|
+
lang en_US.UTF-8
|
|
15
|
+
keyboard us
|
|
16
|
+
timezone UTC --utc
|
|
17
|
+
|
|
18
|
+
# Set the first NIC to acquire IPv4 address via DHCP
|
|
19
|
+
network --device eth0 --bootproto=dhcp
|
|
20
|
+
# Enable firewal, let SSH through
|
|
21
|
+
firewall --enabled --service=ssh
|
|
22
|
+
# Enable SELinux with default enforcing policy
|
|
23
|
+
selinux --enforcing
|
|
24
|
+
|
|
25
|
+
# Do not set up XX Window System
|
|
26
|
+
skipx
|
|
27
|
+
|
|
28
|
+
# Initial disk setup
|
|
29
|
+
# Use the first paravirtualized disk
|
|
30
|
+
ignoredisk --only-use=vda
|
|
31
|
+
# No need for bootloader
|
|
32
|
+
bootloader --disabled
|
|
33
|
+
# Wipe invalid partition tables
|
|
34
|
+
zerombr
|
|
35
|
+
# Erase all partitions and assign default labels
|
|
36
|
+
clearpart --all --initlabel
|
|
37
|
+
# Initialize the primary root partition with ext4 filesystem
|
|
38
|
+
part / --size=1 --grow --asprimary --fstype=ext4
|
|
39
|
+
|
|
40
|
+
# Set root password
|
|
41
|
+
rootpw --plaintext password
|
|
42
|
+
|
|
43
|
+
# Add a user named packer
|
|
44
|
+
user --groups=wheel --name=rocky --password=rocky --plaintext --gecos="rocky"
|
|
45
|
+
|
|
46
|
+
%post --erroronfail
|
|
47
|
+
# workaround anaconda requirements and clear root password
|
|
48
|
+
passwd -d root
|
|
49
|
+
passwd -l root
|
|
50
|
+
|
|
51
|
+
# Clean up install config not applicable to deployed environments.
|
|
52
|
+
for f in resolv.conf fstab; do
|
|
53
|
+
rm -f /etc/$f
|
|
54
|
+
touch /etc/$f
|
|
55
|
+
chown root:root /etc/$f
|
|
56
|
+
chmod 644 /etc/$f
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
rm -f /etc/sysconfig/network-scripts/ifcfg-[^lo]*
|
|
60
|
+
|
|
61
|
+
# Kickstart copies install boot options. Serial is turned on for logging with
|
|
62
|
+
# Packer which disables console output. Disable it so console output is shown
|
|
63
|
+
# during deployments
|
|
64
|
+
sed -i 's/^GRUB_TERMINAL=.*/GRUB_TERMINAL_OUTPUT="console"/g' /etc/default/grub
|
|
65
|
+
sed -i '/GRUB_SERIAL_COMMAND="serial"/d' /etc/default/grub
|
|
66
|
+
sed -ri 's/(GRUB_CMDLINE_LINUX=".*)\s+console=ttyAMA0(.*")/\1\2/' /etc/default/grub
|
|
67
|
+
sed -i 's/GRUB_ENABLE_BLSCFG=.*/GRUB_ENABLE_BLSCFG=false/g' /etc/default/grub
|
|
68
|
+
|
|
69
|
+
dnf clean all
|
|
70
|
+
|
|
71
|
+
# Passwordless sudo for the user 'rocky'
|
|
72
|
+
echo "rocky ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/rocky
|
|
73
|
+
chmod 440 /etc/sudoers.d/rocky
|
|
74
|
+
|
|
75
|
+
#---- Optional - Install your SSH key ----
|
|
76
|
+
# mkdir -m0700 /home/rocky/.ssh/
|
|
77
|
+
#
|
|
78
|
+
# cat <<EOF >/home/rocky/.ssh/authorized_keys
|
|
79
|
+
# ssh-rsa <your_public_key_here> you@your.domain
|
|
80
|
+
# EOF
|
|
81
|
+
#
|
|
82
|
+
### set permissions
|
|
83
|
+
# chmod 0600 /home/rocky/.ssh/authorized_keys
|
|
84
|
+
#
|
|
85
|
+
#### fix up selinux context
|
|
86
|
+
# restorecon -R /home/rocky/.ssh/
|
|
87
|
+
|
|
88
|
+
%end
|
|
89
|
+
|
|
90
|
+
%packages --ignoremissing
|
|
91
|
+
@core
|
|
92
|
+
bash-completion
|
|
93
|
+
cloud-init
|
|
94
|
+
cloud-utils-growpart
|
|
95
|
+
rsync
|
|
96
|
+
tar
|
|
97
|
+
patch
|
|
98
|
+
yum-utils
|
|
99
|
+
grub2-pc
|
|
100
|
+
grub2-efi-*
|
|
101
|
+
shim-*
|
|
102
|
+
grub2-efi-*-modules
|
|
103
|
+
efibootmgr
|
|
104
|
+
dosfstools
|
|
105
|
+
lvm2
|
|
106
|
+
mdadm
|
|
107
|
+
device-mapper-multipath
|
|
108
|
+
iscsi-initiator-utils
|
|
109
|
+
-plymouth
|
|
110
|
+
# Remove ALSA firmware
|
|
111
|
+
-a*-firmware
|
|
112
|
+
# Remove Intel wireless firmware
|
|
113
|
+
-i*-firmware
|
|
114
|
+
%end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
packer {
|
|
2
|
+
required_version = ">= 1.11.0"
|
|
3
|
+
required_plugins {
|
|
4
|
+
qemu = {
|
|
5
|
+
version = ">= 1.1.0, < 1.1.2"
|
|
6
|
+
source = "github.com/hashicorp/qemu"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
variable "filename" {
|
|
12
|
+
type = string
|
|
13
|
+
default = "rocky9.tar.gz"
|
|
14
|
+
description = "The filename of the tarball to produce"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
variable ks_proxy {
|
|
18
|
+
type = string
|
|
19
|
+
default = "${env("KS_PROXY")}"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variable ks_mirror {
|
|
23
|
+
type = string
|
|
24
|
+
default = "${env("KS_MIRROR")}"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
variable "timeout" {
|
|
28
|
+
type = string
|
|
29
|
+
default = "1h"
|
|
30
|
+
description = "Timeout for building the image"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
variable "architecture" {
|
|
34
|
+
type = string
|
|
35
|
+
default = "arm64"
|
|
36
|
+
description = "The architecture to build the image for (amd64 or arm64)"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
variable "host_is_arm" {
|
|
40
|
+
type = bool
|
|
41
|
+
default = false
|
|
42
|
+
description = "The host architecture is aarch64"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
variable "ovmf_suffix" {
|
|
46
|
+
type = string
|
|
47
|
+
default = ""
|
|
48
|
+
description = "Suffix for OVMF CODE and VARS files. Newer systems such as Noble use _4M."
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
variable "headless" {
|
|
52
|
+
type = bool
|
|
53
|
+
default = true
|
|
54
|
+
description = "Run packer in headless mode"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
locals {
|
|
58
|
+
iso_arch_map = {
|
|
59
|
+
"amd64" = "x86_64"
|
|
60
|
+
"x86_64" = "x86_64"
|
|
61
|
+
"arm64" = "aarch64"
|
|
62
|
+
"aarch64" = "aarch64"
|
|
63
|
+
}
|
|
64
|
+
iso_arch = lookup(local.iso_arch_map, var.architecture, "aarch64")
|
|
65
|
+
|
|
66
|
+
iso_checksum_map = {
|
|
67
|
+
"amd64" = "sha256:3b5c87b2f9e62fdf0235d424d64c677906096965aad8a580e0e98fcb9f97f267"
|
|
68
|
+
"x86_64" = "sha256:3b5c87b2f9e62fdf0235d424d64c677906096965aad8a580e0e98fcb9f97f267"
|
|
69
|
+
"arm64" = "sha256:a9ba9ff1187300cecccfaea021eeac04b6408b1180071fb22ee73249f075485e"
|
|
70
|
+
"aarch64" = "sha256:a9ba9ff1187300cecccfaea021eeac04b6408b1180071fb22ee73249f075485e"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
qemu_arch = {
|
|
74
|
+
"amd64" = "x86_64"
|
|
75
|
+
"x86_64" = "x86_64"
|
|
76
|
+
"arm64" = "aarch64"
|
|
77
|
+
"aarch64" = "aarch64"
|
|
78
|
+
}
|
|
79
|
+
uefi_imp = {
|
|
80
|
+
"amd64" = "OVMF"
|
|
81
|
+
"x86_64" = "OVMF"
|
|
82
|
+
"arm64" = "AAVMF"
|
|
83
|
+
"aarch64" = "AAVMF"
|
|
84
|
+
}
|
|
85
|
+
uefi_sfx = {
|
|
86
|
+
"amd64" = "${var.ovmf_suffix}"
|
|
87
|
+
"x86_64" = "${var.ovmf_suffix}"
|
|
88
|
+
"arm64" = ""
|
|
89
|
+
"aarch64" = ""
|
|
90
|
+
}
|
|
91
|
+
qemu_machine = {
|
|
92
|
+
"amd64" = "accel=kvm"
|
|
93
|
+
"x86_64" = "accel=kvm"
|
|
94
|
+
"arm64" = var.host_is_arm ? "virt,accel=kvm" : "virt"
|
|
95
|
+
"aarch64" = var.host_is_arm ? "virt,accel=kvm" : "virt"
|
|
96
|
+
}
|
|
97
|
+
qemu_cpu = {
|
|
98
|
+
"amd64" = "host"
|
|
99
|
+
"x86_64" = "host"
|
|
100
|
+
"arm64" = var.host_is_arm ? "host" : "max"
|
|
101
|
+
"aarch64" = var.host_is_arm ? "host" : "max"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
ks_proxy = var.ks_proxy != "" ? "--proxy=${var.ks_proxy}" : ""
|
|
105
|
+
ks_os_repos = var.ks_mirror != "" ? "--url=${var.ks_mirror}/BaseOS/${local.iso_arch}/os" : "--mirrorlist='http://mirrors.rockylinux.org/mirrorlist?arch=${local.iso_arch}&repo=BaseOS-9'"
|
|
106
|
+
ks_appstream_repos = var.ks_mirror != "" ? "--baseurl=${var.ks_mirror}/AppStream/${local.iso_arch}/os" : "--mirrorlist='https://mirrors.rockylinux.org/mirrorlist?release=9&arch=${local.iso_arch}&repo=AppStream-9'"
|
|
107
|
+
ks_extras_repos = var.ks_mirror != "" ? "--baseurl=${var.ks_mirror}/extras/${local.iso_arch}/os" : "--mirrorlist='https://mirrors.rockylinux.org/mirrorlist?arch=${local.iso_arch}&repo=extras-9'"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
source "qemu" "rocky9" {
|
|
111
|
+
boot_command = ["<up><wait>", "e", "<down><down><down><left>", " console=ttyAMA0 inst.cmdline inst.text inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/rocky9.ks <f10>"]
|
|
112
|
+
boot_wait = "5s"
|
|
113
|
+
communicator = "none"
|
|
114
|
+
disk_size = "45G"
|
|
115
|
+
format = "qcow2"
|
|
116
|
+
headless = var.headless
|
|
117
|
+
iso_checksum = lookup(local.iso_checksum_map, var.architecture, "file:https://download.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/CHECKSUM")
|
|
118
|
+
iso_urls = [
|
|
119
|
+
"https://download.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso",
|
|
120
|
+
"https://dl.rockylinux.org/pub/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso",
|
|
121
|
+
"https://mirrors.edge.kernel.org/rocky/9/isos/${local.iso_arch}/Rocky-9-latest-${local.iso_arch}-boot.iso"
|
|
122
|
+
]
|
|
123
|
+
iso_target_path = "packer_cache/Rocky-9-latest-${local.iso_arch}-boot.iso"
|
|
124
|
+
memory = 2048
|
|
125
|
+
cores = 4
|
|
126
|
+
qemu_binary = "qemu-system-${lookup(local.qemu_arch, var.architecture, "")}"
|
|
127
|
+
qemuargs = [
|
|
128
|
+
["-serial", "stdio"],
|
|
129
|
+
["-boot", "strict=off"],
|
|
130
|
+
["-device", "qemu-xhci"],
|
|
131
|
+
["-device", "usb-kbd"],
|
|
132
|
+
["-device", "virtio-net-pci,netdev=net0"],
|
|
133
|
+
["-netdev", "user,id=net0"],
|
|
134
|
+
["-device", "virtio-blk-pci,drive=drive0,bootindex=0"],
|
|
135
|
+
["-device", "virtio-blk-pci,drive=cdrom0,bootindex=1"],
|
|
136
|
+
["-machine", "${lookup(local.qemu_machine, var.architecture, "")}"],
|
|
137
|
+
["-cpu", "${lookup(local.qemu_cpu, var.architecture, "")}"],
|
|
138
|
+
["-device", "virtio-gpu-pci"],
|
|
139
|
+
["-global", "driver=cfi.pflash01,property=secure,value=off"],
|
|
140
|
+
["-drive", "if=pflash,format=raw,unit=0,id=ovmf_code,readonly=on,file=/usr/share/${lookup(local.uefi_imp, var.architecture, "")}/${lookup(local.uefi_imp, var.architecture, "")}_CODE${lookup(local.uefi_sfx, var.architecture, "")}.fd"],
|
|
141
|
+
["-drive", "if=pflash,format=raw,unit=1,id=ovmf_vars,file=${local.iso_arch}_VARS.fd"],
|
|
142
|
+
["-drive", "file=output-rocky9/packer-rocky9,if=none,id=drive0,cache=writeback,discard=ignore,format=qcow2"],
|
|
143
|
+
["-drive", "file=packer_cache/Rocky-9-latest-${local.iso_arch}-boot.iso,if=none,id=cdrom0,media=cdrom"]
|
|
144
|
+
]
|
|
145
|
+
shutdown_timeout = var.timeout
|
|
146
|
+
http_content = {
|
|
147
|
+
"/rocky9.ks" = templatefile("${path.root}/http/rocky9.ks.pkrtpl.hcl",
|
|
148
|
+
{
|
|
149
|
+
KS_PROXY = local.ks_proxy,
|
|
150
|
+
KS_OS_REPOS = local.ks_os_repos,
|
|
151
|
+
KS_APPSTREAM_REPOS = local.ks_appstream_repos,
|
|
152
|
+
KS_EXTRAS_REPOS = local.ks_extras_repos
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
build {
|
|
159
|
+
sources = ["source.qemu.rocky9"]
|
|
160
|
+
|
|
161
|
+
post-processor "shell-local" {
|
|
162
|
+
inline = [
|
|
163
|
+
"SOURCE=${source.name}",
|
|
164
|
+
"OUTPUT=${var.filename}",
|
|
165
|
+
"source ../../scripts/fuse-nbd",
|
|
166
|
+
"source ../../scripts/fuse-tar-root",
|
|
167
|
+
"rm -rf output-${source.name}",
|
|
168
|
+
]
|
|
169
|
+
inline_shebang = "/bin/bash -e"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -14,15 +14,25 @@ for image_dir in "$PACKER_DIR"/*; do
|
|
|
14
14
|
echo "Checking UEFI VARS files for $image_name..."
|
|
15
15
|
|
|
16
16
|
# Create x86_64 VARS file if it doesn't exist
|
|
17
|
-
if [
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if [ ! -f "$image_dir/x86_64_VARS.fd" ]; then
|
|
18
|
+
for src in /usr/share/edk2/ovmf/OVMF_VARS.fd /usr/share/OVMF/OVMF_VARS.fd; do
|
|
19
|
+
if [ -f "$src" ]; then
|
|
20
|
+
cp "$src" "$image_dir/x86_64_VARS.fd"
|
|
21
|
+
echo "Created $image_dir/x86_64_VARS.fd from $src"
|
|
22
|
+
break
|
|
23
|
+
fi
|
|
24
|
+
done
|
|
20
25
|
fi
|
|
21
26
|
|
|
22
27
|
# Create aarch64 VARS file if it doesn't exist
|
|
23
|
-
if [
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
if [ ! -f "$image_dir/aarch64_VARS.fd" ]; then
|
|
29
|
+
for src in /usr/share/AAVMF/AAVMF_VARS.fd /usr/share/edk2/aarch64/AAVMF_VARS.fd /usr/share/edk2/aarch64/QEMU_VARS.fd; do
|
|
30
|
+
if [ -f "$src" ]; then
|
|
31
|
+
cp "$src" "$image_dir/aarch64_VARS.fd"
|
|
32
|
+
echo "Created $image_dir/aarch64_VARS.fd from $src"
|
|
33
|
+
break
|
|
34
|
+
fi
|
|
35
|
+
done
|
|
26
36
|
fi
|
|
27
37
|
fi
|
|
28
38
|
done
|
package/scripts/packer-setup.sh
CHANGED
|
@@ -1,52 +1,289 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
2
|
+
# packer-setup.sh
|
|
3
|
+
# RHEL/CentOS/Rocky helper to prepare a host for building both amd64 and aarch64 Packer images.
|
|
4
|
+
# Installs packer (repo fallback), libvirt/qemu tooling, NBD/filesystem tools, UEFI firmware for x86_64 and aarch64,
|
|
5
|
+
# registers qemu-user binfmt for cross-chroot use and compiles qemu-system-aarch64 when repo packages are missing.
|
|
6
|
+
# Usage: sudo ./packer-setup.sh
|
|
4
7
|
|
|
5
8
|
set -euo pipefail
|
|
6
9
|
|
|
10
|
+
print(){ printf "[setup] %s\n" "$*"; }
|
|
11
|
+
err(){ printf "[setup] ERROR: %s\n" "$*" >&2; }
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
13
|
+
if [[ $(id -u) -ne 0 ]]; then
|
|
14
|
+
err "This script requires root. Run with sudo."; exit 3
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Detect host arch
|
|
18
|
+
HOST_RAW_ARCH=$(uname -m)
|
|
19
|
+
case "$HOST_RAW_ARCH" in
|
|
20
|
+
x86_64) HOST_ARCH=amd64;;
|
|
21
|
+
aarch64) HOST_ARCH=arm64;;
|
|
22
|
+
*) HOST_ARCH="$HOST_RAW_ARCH";;
|
|
23
|
+
esac
|
|
24
|
+
print "Host architecture: $HOST_RAW_ARCH -> normalized: $HOST_ARCH"
|
|
25
|
+
|
|
26
|
+
# Ensure RHEL-family
|
|
27
|
+
if [[ -f /etc/os-release ]]; then
|
|
28
|
+
. /etc/os-release
|
|
29
|
+
ID_LC=${ID,,}
|
|
30
|
+
ID_LIKE=${ID_LIKE,,}
|
|
31
|
+
else
|
|
32
|
+
ID_LC=unknown; ID_LIKE=unknown
|
|
33
|
+
fi
|
|
34
|
+
if [[ $ID_LC != "rocky" && $ID_LC != "rhel" && $ID_LC != "centos" && $ID_LIKE != *"rhel"* ]]; then
|
|
35
|
+
err "This script targets RHEL/CentOS/Rocky family. Detected: $ID_LC (like: $ID_LIKE). Exiting."; exit 4
|
|
36
|
+
fi
|
|
37
|
+
print "Distro detected: $PRETTY_NAME"
|
|
38
|
+
|
|
39
|
+
# Enable helpful repos and install helpers
|
|
40
|
+
print "Installing dnf-plugins-core and enabling CRB/PowerTools (if available)"
|
|
41
|
+
set +e
|
|
42
|
+
dnf install -y dnf-plugins-core >/dev/null 2>&1 || true
|
|
43
|
+
dnf config-manager --set-enabled crb >/dev/null 2>&1 || true
|
|
44
|
+
dnf config-manager --set-enabled powertools >/dev/null 2>&1 || true
|
|
45
|
+
# EPEL
|
|
46
|
+
if ! rpm -q epel-release >/dev/null 2>&1; then
|
|
47
|
+
print "Installing epel-release"
|
|
48
|
+
dnf install -y epel-release || true
|
|
49
|
+
fi
|
|
50
|
+
set -e
|
|
51
|
+
|
|
52
|
+
# 1) Try to install packer from distro repos, otherwise add HashiCorp repo and install
|
|
53
|
+
print "Attempting to install packer from distro repos"
|
|
54
|
+
if dnf install -y packer >/dev/null 2>&1; then
|
|
55
|
+
print "Packer installed from distro repo"
|
|
56
|
+
else
|
|
57
|
+
print "packer not available in distro repos or install failed. Adding HashiCorp repo and retrying."
|
|
58
|
+
# HashiCorp RPM repo for RHEL/CentOS/Rocky family (works for EL8/EL9)
|
|
59
|
+
if ! rpm -q hashicorp >/dev/null 2>&1; then
|
|
60
|
+
cat >/etc/yum.repos.d/hashicorp.repo <<'EOF'
|
|
61
|
+
[hashicorp]
|
|
62
|
+
name=HashiCorp Stable - $basearch
|
|
63
|
+
baseurl=https://rpm.releases.hashicorp.com/RHEL/$releasever/$basearch/stable
|
|
64
|
+
enabled=1
|
|
65
|
+
gpgcheck=1
|
|
66
|
+
gpgkey=https://rpm.releases.hashicorp.com/gpg
|
|
67
|
+
EOF
|
|
68
|
+
fi
|
|
69
|
+
if dnf makecache >/dev/null 2>&1 && dnf install -y packer >/dev/null 2>&1; then
|
|
70
|
+
print "Packer installed from HashiCorp repo"
|
|
71
|
+
else
|
|
72
|
+
err "Packer install from repo failed. You can install packer manually from HashiCorp releases if needed.";
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
10
75
|
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
76
|
+
# 2) Install libvirt, qemu tooling and enable libvirtd
|
|
77
|
+
print "Installing libvirt, qemu and related tooling (best-effort)"
|
|
78
|
+
LIBVIRT_PKGS=(libvirt libvirt-daemon qemu-kvm qemu-img virt-install bridge-utils)
|
|
79
|
+
# attempt to include qemu-system-aarch64 and qemu-system-x86_64 if available
|
|
80
|
+
LIBVIRT_PKGS+=(qemu-system-aarch64 qemu-system-x86_64 qemu-system-arm)
|
|
14
81
|
|
|
15
|
-
#
|
|
16
|
-
|
|
82
|
+
# Some packages may not exist exactly with those names; install best-effort
|
|
83
|
+
for pkg in "${LIBVIRT_PKGS[@]}"; do
|
|
84
|
+
dnf install -y "$pkg" >/dev/null 2>&1 || print "Package $pkg not available via dnf (skipping)"
|
|
85
|
+
done
|
|
17
86
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
sudo systemctl status libvirtd --no-pager
|
|
87
|
+
print "Enabling and starting libvirtd"
|
|
88
|
+
systemctl enable --now libvirtd || err "Failed to enable/start libvirtd"
|
|
89
|
+
systemctl status libvirtd --no-pager || true
|
|
22
90
|
|
|
23
|
-
#
|
|
24
|
-
|
|
91
|
+
# 3) Install NBD and filesystem tools required for MAAS image creation
|
|
92
|
+
print "Installing NBD and filesystem tooling: libnbd, nbdkit, e2fsprogs, kmod packages (best-effort)"
|
|
93
|
+
NBDS=(libnbd nbdkit e2fsprogs kmod-kvdo kmod)
|
|
94
|
+
for pkg in "${NBDS[@]}"; do
|
|
95
|
+
dnf install -y "$pkg" >/dev/null 2>&1 || print "Package $pkg not available via dnf (skipping)"
|
|
96
|
+
done
|
|
25
97
|
|
|
26
98
|
# 4) Install UEFI firmware for x86_64 and ARM64
|
|
27
|
-
|
|
99
|
+
print "Installing edk2 / OVMF UEFI firmware packages (x86_64 and aarch64)"
|
|
100
|
+
UEFI_PKGS=(edk2-ovmf edk2-aarch64 edk2-ovmf-aarch64)
|
|
101
|
+
for pkg in "${UEFI_PKGS[@]}"; do
|
|
102
|
+
dnf install -y "$pkg" >/dev/null 2>&1 || print "UEFI package $pkg not available (skipping)"
|
|
103
|
+
done
|
|
28
104
|
|
|
29
|
-
# 5)
|
|
30
|
-
|
|
31
|
-
if
|
|
32
|
-
|
|
33
|
-
sudo ln -sf /usr/libexec/qemu-kvm /usr/bin/qemu-system-x86_64
|
|
105
|
+
# 5) Ensure qemu-user-static for chroot/debootstrap cross-execution and register binfmt via podman
|
|
106
|
+
print "Installing qemu-user-static and registering binfmt handlers via podman"
|
|
107
|
+
if ! rpm -q qemu-user-static >/dev/null 2>&1; then
|
|
108
|
+
dnf install -y qemu-user-static >/dev/null 2>&1 || print "qemu-user-static not in repos (will extract from container)"
|
|
34
109
|
fi
|
|
35
110
|
|
|
36
|
-
if
|
|
37
|
-
|
|
38
|
-
|
|
111
|
+
if command -v podman >/dev/null 2>&1; then
|
|
112
|
+
# Register binfmt handlers
|
|
113
|
+
podman run --rm --privileged multiarch/qemu-user-static --reset -p yes || print "podman run for qemu-user-static failed (skip)"
|
|
114
|
+
|
|
115
|
+
# Extract static binaries to /usr/bin if not already present from RPM
|
|
116
|
+
if ! command -v qemu-aarch64-static >/dev/null 2>&1; then
|
|
117
|
+
print "Extracting qemu static binaries from multiarch/qemu-user-static container"
|
|
118
|
+
CONTAINER_ID=$(podman create multiarch/qemu-user-static:latest)
|
|
119
|
+
|
|
120
|
+
# Extract the binaries we need
|
|
121
|
+
for arch in aarch64 arm armeb; do
|
|
122
|
+
if podman cp "$CONTAINER_ID:/usr/bin/qemu-${arch}-static" "/usr/bin/qemu-${arch}-static" 2>/dev/null; then
|
|
123
|
+
chmod +x "/usr/bin/qemu-${arch}-static"
|
|
124
|
+
print "Installed qemu-${arch}-static to /usr/bin/"
|
|
125
|
+
fi
|
|
126
|
+
done
|
|
127
|
+
|
|
128
|
+
podman rm "$CONTAINER_ID" >/dev/null 2>&1 || true
|
|
129
|
+
fi
|
|
130
|
+
else
|
|
131
|
+
print "podman not available. Install podman to register binfmt for container/chroot convenience."
|
|
39
132
|
fi
|
|
40
133
|
|
|
41
|
-
# 6)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
134
|
+
# 6) Check qemu-system-aarch64 availability and 'virt' machine support; offer compile if missing
|
|
135
|
+
check_qemu_system_aarch64(){
|
|
136
|
+
# Explicitly check /usr/local/bin first (where compiled QEMU installs)
|
|
137
|
+
if [ -x /usr/local/bin/qemu-system-aarch64 ]; then
|
|
138
|
+
QBIN=/usr/local/bin/qemu-system-aarch64
|
|
139
|
+
elif command -v qemu-system-aarch64 >/dev/null 2>&1; then
|
|
140
|
+
QBIN=$(command -v qemu-system-aarch64)
|
|
141
|
+
else
|
|
142
|
+
return 1
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
print "qemu-system-aarch64 found at $QBIN"
|
|
146
|
+
if ! $QBIN -machine help 2>/dev/null | grep -q '\bvirt\b'; then
|
|
147
|
+
err "qemu-system-aarch64 present but 'virt' not listed -> may be missing aarch64 softmmu"
|
|
148
|
+
return 2
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# Check for user networking (slirp) support.
|
|
152
|
+
# We specify -machine virt to avoid "No machine specified" errors on some QEMU versions.
|
|
153
|
+
if ! $QBIN -machine virt -netdev help 2>&1 | grep -q '\buser\b'; then
|
|
154
|
+
err "qemu-system-aarch64 present but 'user' network backend not listed -> missing libslirp support"
|
|
155
|
+
return 3
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
print "qemu-system-aarch64 supports 'virt' and 'user' network -> good for full-system ARM emulation"
|
|
159
|
+
return 0
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if check_qemu_system_aarch64; then
|
|
163
|
+
print "qemu-system-aarch64 is ready"
|
|
164
|
+
else
|
|
165
|
+
rc=$?
|
|
166
|
+
if [[ $rc -eq 1 ]]; then
|
|
167
|
+
print "qemu-system-aarch64 not found in installed packages"
|
|
168
|
+
else
|
|
169
|
+
print "qemu-system-aarch64 present but incomplete"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# Try install from repo explicitly
|
|
173
|
+
print "Attempting to install qemu-system-aarch64 via dnf (best-effort)"
|
|
174
|
+
if dnf install -y qemu-system-aarch64 >/dev/null 2>&1; then
|
|
175
|
+
print "Installed qemu-system-aarch64 from repo"
|
|
176
|
+
else
|
|
177
|
+
print "qemu-system-aarch64 not available in enabled repos."
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
if check_qemu_system_aarch64; then
|
|
181
|
+
print "qemu-system-aarch64 now available after package install"
|
|
182
|
+
else
|
|
183
|
+
print "Compiling QEMU with aarch64-softmmu target. Installing build deps..."
|
|
184
|
+
dnf groupinstall -y 'Development Tools' || true
|
|
185
|
+
dnf install -y git libaio-devel libgcrypt-devel libfdt-devel glib2-devel zlib-devel pixman-devel libseccomp-devel libusb1-devel openssl-devel bison flex python3 python3-pip ninja-build || true
|
|
186
|
+
|
|
187
|
+
# Enforce libslirp-devel for user networking
|
|
188
|
+
if ! dnf install -y libslirp-devel; then
|
|
189
|
+
err "Failed to install libslirp-devel. User networking will not work."
|
|
190
|
+
exit 1
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# Install required Python packages for QEMU build
|
|
194
|
+
print "Installing Python dependencies for QEMU build"
|
|
195
|
+
python3 -m pip install --upgrade pip || true
|
|
196
|
+
python3 -m pip install tomli meson || true
|
|
197
|
+
|
|
198
|
+
TMPDIR=$(mktemp -d)
|
|
199
|
+
print "Cloning QEMU source to $TMPDIR/qemu"
|
|
200
|
+
# Use a stable release tag (v9.0.0) to ensure consistency
|
|
201
|
+
git clone --depth 1 --branch v9.0.0 https://gitlab.com/qemu-project/qemu.git "$TMPDIR/qemu"
|
|
202
|
+
cd "$TMPDIR/qemu"
|
|
203
|
+
|
|
204
|
+
print "Configuring QEMU build"
|
|
205
|
+
if ./configure --target-list=aarch64-softmmu --enable-virtfs --enable-slirp; then
|
|
206
|
+
print "Configure successful, building QEMU..."
|
|
207
|
+
if make -j"$(nproc)"; then
|
|
208
|
+
print "Build successful, installing..."
|
|
209
|
+
make install || err "QEMU install failed"
|
|
210
|
+
# Update PATH to include /usr/local/bin where QEMU was installed
|
|
211
|
+
export PATH="/usr/local/bin:$PATH"
|
|
212
|
+
hash -r || true
|
|
213
|
+
else
|
|
214
|
+
err "QEMU build (make) failed"
|
|
215
|
+
fi
|
|
216
|
+
else
|
|
217
|
+
err "QEMU configure failed. Check dependencies."
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
if check_qemu_system_aarch64; then
|
|
221
|
+
print "Successfully compiled and installed qemu-system-aarch64"
|
|
222
|
+
else
|
|
223
|
+
err "Compiled QEMU but qemu-system-aarch64 still missing or lacks 'virt'. Check logs in $TMPDIR/qemu"
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
cd /
|
|
227
|
+
rm -rf "$TMPDIR" || true
|
|
228
|
+
print "Removed build directory $TMPDIR"
|
|
229
|
+
fi
|
|
46
230
|
fi
|
|
47
231
|
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
232
|
+
# 7) Summary and verification commands for the user
|
|
233
|
+
print "\n=== Summary / Quick verification commands ==="
|
|
234
|
+
if command -v packer >/dev/null 2>&1; then print "packer: $(command -v packer)"; else print "packer: NOT INSTALLED"; fi
|
|
235
|
+
# Check /usr/local/bin explicitly for compiled qemu
|
|
236
|
+
if [ -x /usr/local/bin/qemu-system-aarch64 ]; then
|
|
237
|
+
print "qemu-system-aarch64: /usr/local/bin/qemu-system-aarch64"
|
|
238
|
+
elif command -v qemu-system-aarch64 >/dev/null 2>&1; then
|
|
239
|
+
print "qemu-system-aarch64: $(command -v qemu-system-aarch64)"
|
|
240
|
+
else
|
|
241
|
+
print "qemu-system-aarch64: NOT INSTALLED"
|
|
52
242
|
fi
|
|
243
|
+
if command -v qemu-aarch64-static >/dev/null 2>&1; then print "qemu-aarch64-static: $(command -v qemu-aarch64-static)"; else print "qemu-aarch64-static: NOT INSTALLED"; fi
|
|
244
|
+
print "libvirtd status:"
|
|
245
|
+
systemctl status libvirtd --no-pager || true
|
|
246
|
+
|
|
247
|
+
cat <<'EOF'
|
|
248
|
+
|
|
249
|
+
=== Example Packer qemu builder snippets ===
|
|
250
|
+
|
|
251
|
+
# aarch64 on x86_64 host (use qemu-system-aarch64 with TCG):
|
|
252
|
+
{
|
|
253
|
+
"type": "qemu",
|
|
254
|
+
"qemu_binary": "/usr/local/bin/qemu-system-aarch64",
|
|
255
|
+
"accelerator": "tcg",
|
|
256
|
+
"format": "raw",
|
|
257
|
+
"disk_size": "8192",
|
|
258
|
+
"headless": true,
|
|
259
|
+
"qemuargs": [
|
|
260
|
+
["-machine", "virt,highmem=on"],
|
|
261
|
+
["-cpu", "cortex-a57"],
|
|
262
|
+
["-bios", "/usr/share/edk2-aarch64/QEMU_EFI.fd"],
|
|
263
|
+
["-device", "virtio-net-device,netdev=net0"],
|
|
264
|
+
["-netdev", "user,id=net0,hostfwd=tcp::2222-:22"]
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# x86_64 on arm64 host (use kvm when available):
|
|
269
|
+
{
|
|
270
|
+
"type": "qemu",
|
|
271
|
+
"qemu_binary": "/usr/bin/qemu-system-x86_64",
|
|
272
|
+
"accelerator": "kvm",
|
|
273
|
+
"format": "raw",
|
|
274
|
+
"disk_size": "8192",
|
|
275
|
+
"headless": true,
|
|
276
|
+
"qemuargs": [
|
|
277
|
+
["-machine", "pc,q35"],
|
|
278
|
+
["-cpu", "host"],
|
|
279
|
+
["-bios", "/usr/share/ovmf/OVMF_CODE.fd"],
|
|
280
|
+
["-device", "virtio-net-pci,netdev=net0"],
|
|
281
|
+
["-netdev", "user,id=net0,hostfwd=tcp::2223-:22"]
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
EOF
|
|
286
|
+
|
|
287
|
+
print "Done. If any package failed to install due to repo availability, consider enabling CRB/powertools, adding a trusted COPR or rebuild repo for qemu, or compiling QEMU locally as the script offered."
|
|
288
|
+
|
|
289
|
+
exit 0
|
package/src/cli/baremetal.js
CHANGED
|
@@ -87,6 +87,7 @@ class UnderpostBaremetal {
|
|
|
87
87
|
packerWorkflowId: '',
|
|
88
88
|
packerMaasImageBuild: false,
|
|
89
89
|
packerMaasImageUpload: false,
|
|
90
|
+
packerMaasImageCached: false,
|
|
90
91
|
cloudInitUpdate: false,
|
|
91
92
|
commission: false,
|
|
92
93
|
nfsBuild: false,
|
|
@@ -141,8 +142,9 @@ class UnderpostBaremetal {
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
if (options.packerMaasImageTemplate) {
|
|
145
|
+
workflowId = options.packerWorkflowId;
|
|
144
146
|
if (!workflowId) {
|
|
145
|
-
throw new Error('workflow-id is required when using --packer-maas-image-template');
|
|
147
|
+
throw new Error('--packer-workflow-id is required when using --packer-maas-image-template');
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
const templatePath = options.packerMaasImageTemplate;
|
|
@@ -187,7 +189,7 @@ class UnderpostBaremetal {
|
|
|
187
189
|
logger.info(`1. Review and customize the Packer template files in: ${targetDir}`);
|
|
188
190
|
logger.info(`2. Review the workflow configuration in engine/baremetal/packer-workflows.json`);
|
|
189
191
|
logger.info(
|
|
190
|
-
`3. Build the image with: underpost baremetal ${workflowId} --packer-maas-image-build
|
|
192
|
+
`3. Build the image with: underpost baremetal --packer-workflow-id ${workflowId} --packer-maas-image-build`,
|
|
191
193
|
);
|
|
192
194
|
} catch (error) {
|
|
193
195
|
throw new Error(`Failed to extract template: ${error.message}`);
|
|
@@ -217,10 +219,26 @@ class UnderpostBaremetal {
|
|
|
217
219
|
throw new Error('Packer is not installed. Please install Packer to proceed.');
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
// Check for QEMU support if building for a different architecture (validator bots case)
|
|
223
|
+
UnderpostBaremetal.API.checkQemuCrossArchSupport(workflow);
|
|
224
|
+
|
|
220
225
|
logger.info(`Building Packer image for ${workflowId} in ${packerDir}...`);
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
|
|
227
|
+
// Only remove artifacts if not using cached mode
|
|
228
|
+
if (!options.packerMaasImageCached) {
|
|
229
|
+
const artifacts = [
|
|
230
|
+
'output-rocky9',
|
|
231
|
+
'packer_cache',
|
|
232
|
+
'x86_64_VARS.fd',
|
|
233
|
+
'aarch64_VARS.fd',
|
|
234
|
+
workflow.maas.content,
|
|
235
|
+
];
|
|
236
|
+
shellExec(`cd packer/images/${workflowId}
|
|
223
237
|
rm -rf ${artifacts.join(' ')}`);
|
|
238
|
+
logger.info('Removed previous build artifacts');
|
|
239
|
+
} else {
|
|
240
|
+
logger.info('Cached mode: Keeping existing artifacts for incremental build');
|
|
241
|
+
}
|
|
224
242
|
shellExec(`chmod +x ${underpostRoot}/scripts/packer-init-vars-file.sh`);
|
|
225
243
|
shellExec(`${underpostRoot}/scripts/packer-init-vars-file.sh`);
|
|
226
244
|
|
|
@@ -229,10 +247,17 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
229
247
|
throw new Error('Packer init failed');
|
|
230
248
|
}
|
|
231
249
|
|
|
232
|
-
const
|
|
250
|
+
const isArm = process.arch === 'arm64';
|
|
251
|
+
// Add /usr/local/bin to PATH so Packer can find compiled QEMU binaries
|
|
252
|
+
const packerEnv = {
|
|
253
|
+
...process.env,
|
|
254
|
+
PACKER_LOG: '1',
|
|
255
|
+
PATH: `/usr/local/bin:${process.env.PATH || '/usr/bin:/bin'}`,
|
|
256
|
+
};
|
|
257
|
+
const build = spawnSync('packer', ['build', '-var', `host_is_arm=${isArm}`, '.'], {
|
|
233
258
|
stdio: 'inherit',
|
|
234
259
|
cwd: packerDir,
|
|
235
|
-
env:
|
|
260
|
+
env: packerEnv,
|
|
236
261
|
});
|
|
237
262
|
|
|
238
263
|
if (build.status !== 0) {
|
|
@@ -244,7 +269,7 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
244
269
|
if (!fs.existsSync(tarballPath)) {
|
|
245
270
|
throw new Error(
|
|
246
271
|
`Build artifact not found: ${tarballPath}\n` +
|
|
247
|
-
`Please build first with: --packer-
|
|
272
|
+
`Please build first with: --packer-workflow-id ${workflowId} --packer-maas-image-build`,
|
|
248
273
|
);
|
|
249
274
|
}
|
|
250
275
|
const stats = fs.statSync(tarballPath);
|
|
@@ -1388,6 +1413,80 @@ udp-port = 32766
|
|
|
1388
1413
|
logger.info('NFS server restarted.');
|
|
1389
1414
|
},
|
|
1390
1415
|
|
|
1416
|
+
/**
|
|
1417
|
+
* @method checkQemuCrossArchSupport
|
|
1418
|
+
* @description Checks for QEMU support when building for a different architecture.
|
|
1419
|
+
* This is essential for validator bots that need to build images for architectures
|
|
1420
|
+
* different from the host system (e.g., building arm64 on x86_64 or vice versa).
|
|
1421
|
+
* @param {object} workflow - The workflow configuration object.
|
|
1422
|
+
* @param {object} workflow.maas - The MAAS configuration.
|
|
1423
|
+
* @param {string} workflow.maas.architecture - Target architecture (e.g., 'arm64/generic', 'amd64/generic').
|
|
1424
|
+
* @memberof UnderpostBaremetal
|
|
1425
|
+
* @throws {Error} If QEMU is not installed or doesn't support required machine types.
|
|
1426
|
+
* @returns {void}
|
|
1427
|
+
*/
|
|
1428
|
+
checkQemuCrossArchSupport(workflow) {
|
|
1429
|
+
// Check for QEMU support if building for a different architecture (validator bots case)
|
|
1430
|
+
if (workflow.maas.architecture.startsWith('arm64') && process.arch !== 'arm64') {
|
|
1431
|
+
// Building arm64/aarch64 on x86_64 host
|
|
1432
|
+
// Check both /usr/local/bin (compiled) and system paths
|
|
1433
|
+
let qemuAarch64Path = null;
|
|
1434
|
+
|
|
1435
|
+
if (shellExec('test -x /usr/local/bin/qemu-system-aarch64', { silent: true }).code === 0) {
|
|
1436
|
+
qemuAarch64Path = '/usr/local/bin/qemu-system-aarch64';
|
|
1437
|
+
} else if (shellExec('which qemu-system-aarch64', { silent: true }).code === 0) {
|
|
1438
|
+
qemuAarch64Path = shellExec('which qemu-system-aarch64', { silent: true }).stdout.trim();
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
if (!qemuAarch64Path) {
|
|
1442
|
+
throw new Error(
|
|
1443
|
+
'qemu-system-aarch64 is not installed. Please install it to build ARM64 images on x86_64 hosts.\n' +
|
|
1444
|
+
'Run: node bin baremetal --dev --install-packer',
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
logger.info(`Found qemu-system-aarch64 at: ${qemuAarch64Path}`);
|
|
1449
|
+
|
|
1450
|
+
// Verify that the installed qemu supports the 'virt' machine type (required for arm64)
|
|
1451
|
+
const machineHelp = shellExec(`${qemuAarch64Path} -machine help`, { silent: true }).stdout;
|
|
1452
|
+
if (!machineHelp.includes('virt')) {
|
|
1453
|
+
throw new Error(
|
|
1454
|
+
'The installed qemu-system-aarch64 does not support the "virt" machine type.\n' +
|
|
1455
|
+
'This usually happens if qemu-system-aarch64 is a symlink to qemu-kvm on x86_64.\n' +
|
|
1456
|
+
'Run: node bin baremetal --dev --install-packer',
|
|
1457
|
+
);
|
|
1458
|
+
}
|
|
1459
|
+
} else if (workflow.maas.architecture.startsWith('amd64') && process.arch !== 'x64') {
|
|
1460
|
+
// Building amd64/x86_64 on aarch64 host
|
|
1461
|
+
// Check both /usr/local/bin (compiled) and system paths
|
|
1462
|
+
let qemuX86Path = null;
|
|
1463
|
+
|
|
1464
|
+
if (shellExec('test -x /usr/local/bin/qemu-system-x86_64', { silent: true }).code === 0) {
|
|
1465
|
+
qemuX86Path = '/usr/local/bin/qemu-system-x86_64';
|
|
1466
|
+
} else if (shellExec('which qemu-system-x86_64', { silent: true }).code === 0) {
|
|
1467
|
+
qemuX86Path = shellExec('which qemu-system-x86_64', { silent: true }).stdout.trim();
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if (!qemuX86Path) {
|
|
1471
|
+
throw new Error(
|
|
1472
|
+
'qemu-system-x86_64 is not installed. Please install it to build x86_64 images on aarch64 hosts.\n' +
|
|
1473
|
+
'Run: node bin baremetal --dev --install-packer',
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
logger.info(`Found qemu-system-x86_64 at: ${qemuX86Path}`);
|
|
1478
|
+
|
|
1479
|
+
// Verify that the installed qemu supports the 'pc' or 'q35' machine type (required for x86_64)
|
|
1480
|
+
const machineHelp = shellExec(`${qemuX86Path} -machine help`, { silent: true }).stdout;
|
|
1481
|
+
if (!machineHelp.includes('pc') && !machineHelp.includes('q35')) {
|
|
1482
|
+
throw new Error(
|
|
1483
|
+
'The installed qemu-system-x86_64 does not support the "pc" or "q35" machine type.\n' +
|
|
1484
|
+
'Run: node bin baremetal --dev --install-packer',
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
},
|
|
1489
|
+
|
|
1391
1490
|
/**
|
|
1392
1491
|
* @method bootConfFactory
|
|
1393
1492
|
* @description Generates the boot configuration file for specific workflows,
|
package/src/cli/index.js
CHANGED
|
@@ -625,6 +625,10 @@ program
|
|
|
625
625
|
'--packer-maas-image-upload',
|
|
626
626
|
'Uploads an existing MAAS image artifact without rebuilding for the workflow specified by --packer-workflow-id.',
|
|
627
627
|
)
|
|
628
|
+
.option(
|
|
629
|
+
'--packer-maas-image-cached',
|
|
630
|
+
'Continue last build without removing artifacts (used with --packer-maas-image-build).',
|
|
631
|
+
)
|
|
628
632
|
.option('--commission', 'Init workflow for commissioning a physical machine.')
|
|
629
633
|
.option('--nfs-build', 'Builds an NFS root filesystem for a workflow id config architecture using QEMU emulation.')
|
|
630
634
|
.option('--nfs-mount', 'Mounts the NFS root filesystem for a workflow id config architecture.')
|
package/src/index.js
CHANGED
|
@@ -36,7 +36,7 @@ class Underpost {
|
|
|
36
36
|
* @type {String}
|
|
37
37
|
* @memberof Underpost
|
|
38
38
|
*/
|
|
39
|
-
static version = 'v2.96.
|
|
39
|
+
static version = 'v2.96.1';
|
|
40
40
|
/**
|
|
41
41
|
* Repository cli API
|
|
42
42
|
* @static
|
|
@@ -193,6 +193,7 @@ export {
|
|
|
193
193
|
UnderpostRootEnv,
|
|
194
194
|
UnderpostFileStorage,
|
|
195
195
|
UnderpostImage,
|
|
196
|
+
UnderpostStatic,
|
|
196
197
|
UnderpostLxd,
|
|
197
198
|
UnderpostMonitor,
|
|
198
199
|
UnderpostRepository,
|