aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Buchholz <tomalok@gmail.com>2019-04-29 22:22:13 -0700
committerJake Buchholz <tomalok@gmail.com>2019-04-29 22:22:13 -0700
commitc8b443e75148a97c926239f2a734a3fcd72b8646 (patch)
tree05aaf32db315193955260c2eb9caa243767c16c4
parent9dc3539850ba4eaf4dedd3ad66be94ec28faa9b0 (diff)
downloadalpine-ec2-ami-c8b443e75148a97c926239f2a734a3fcd72b8646.tar.bz2
alpine-ec2-ami-c8b443e75148a97c926239f2a734a3fcd72b8646.tar.xz
alpine-ec2-ami-c8b443e75148a97c926239f2a734a3fcd72b8646.zip
sort out bootloader stuff
* packer.conf + don't need to pass bootloader + pass kernel_mods/kernel_opts + use_env_var_file to get around problems with ENV var contents (new execute_command, too) * profiles/base/1 + add kernel_modules/options * scripts/resolve-profile.py.in + fold() - strips quotes from complex keys - include separator char at beginning of fmt - different dicts use different separators + svcs dict -> scalar - make vars clearer - ' ' separator between levels * setup-ami.sh + no longer need to 'tr' REPOS, PKGS, SVCS + detect bootloader to use - when 'grub-efi' is bootloader, partition target device w/small EFI partition, format vfat, install_grub_efi() untested yet + merge setup_extlinux into install_extlinux
-rw-r--r--packer.conf6
-rw-r--r--profiles/base/114
-rw-r--r--scripts/resolve-profile.py.in37
-rwxr-xr-xscripts/setup-ami.sh135
4 files changed, 131 insertions, 61 deletions
diff --git a/packer.conf b/packer.conf
index ecd5b81..513f093 100644
--- a/packer.conf
+++ b/packer.conf
@@ -71,12 +71,14 @@ provisioners = [
71 "APK_TOOLS_SHA256={{user `apk_tools_sha256`}}" 71 "APK_TOOLS_SHA256={{user `apk_tools_sha256`}}"
72 "ALPINE_KEYS={{user `alpine_keys`}}" 72 "ALPINE_KEYS={{user `alpine_keys`}}"
73 "ALPINE_KEYS_SHA256={{user `alpine_keys_sha256`}}" 73 "ALPINE_KEYS_SHA256={{user `alpine_keys_sha256`}}"
74 "BOOTLOADER={{user `bootloader`}}"
75 "REPOS={{user `repos`}}" 74 "REPOS={{user `repos`}}"
76 "PKGS={{user `pkgs`}}" 75 "PKGS={{user `pkgs`}}"
77 "SVCS={{user `svcs`}}" 76 "SVCS={{user `svcs`}}"
77 "KERNEL_MODS={{user `kernel_modules`}}"
78 "KERNEL_OPTS={{user `kernel_options`}}"
78 ] 79 ]
79 execute_command = "sudo sh -c '{{ .Vars }} {{ .Path }}'" 80 use_env_var_file = "true"
81 execute_command = "sudo sh -c '. {{.EnvVarFile}} && {{.Path}}'"
80 } 82 }
81] 83]
82 84
diff --git a/profiles/base/1 b/profiles/base/1
index a4c8ab1..3bda7ed 100644
--- a/profiles/base/1
+++ b/profiles/base/1
@@ -41,7 +41,6 @@ apk_tools = null
41apk_tools_sha256 = null 41apk_tools_sha256 = null
42alpine_keys = null 42alpine_keys = null
43alpine_keys_sha256 = null 43alpine_keys_sha256 = null
44bootloader = null
45repos {} 44repos {}
46pkgs { 45pkgs {
47 linux-virt = true 46 linux-virt = true
@@ -55,12 +54,10 @@ pkgs {
55 tzdata = true 54 tzdata = true
56} 55}
57svcs { 56svcs {
58 # sysinit
59 devfs = "sysinit" 57 devfs = "sysinit"
60 dmesg = "sysinit" 58 dmesg = "sysinit"
61 hwdrivers = "sysinit" 59 hwdrivers = "sysinit"
62 mdev = "sysinit" 60 mdev = "sysinit"
63 # boot
64 acpid = "boot" 61 acpid = "boot"
65 bootmisc = "boot" 62 bootmisc = "boot"
66 haveged = "boot" 63 haveged = "boot"
@@ -70,13 +67,20 @@ svcs {
70 swap = "boot" 67 swap = "boot"
71 sysctl = "boot" 68 sysctl = "boot"
72 syslog = "boot" 69 syslog = "boot"
73 # default
74 chronyd = "default" 70 chronyd = "default"
75 networking = "default" 71 networking = "default"
76 sshd = "default" 72 sshd = "default"
77 tiny-ec2-bootstrap = "default" 73 tiny-ec2-bootstrap = "default"
78 # shutdown
79 killprocs = "shutdown" 74 killprocs = "shutdown"
80 mount-ro = "shutdown" 75 mount-ro = "shutdown"
81 savecache = "shutdown" 76 savecache = "shutdown"
82} 77}
78kernel_modules {
79 "sd-mod" = true
80 "usb-storage" = true
81 "ext4" = true
82}
83kernel_options {
84 "console=ttyS0" = true
85 "console=tty0" = true
86}
diff --git a/scripts/resolve-profile.py.in b/scripts/resolve-profile.py.in
index 67f9d24..050da00 100644
--- a/scripts/resolve-profile.py.in
+++ b/scripts/resolve-profile.py.in
@@ -22,20 +22,23 @@ os.makedirs(profile_dir)
22 22
23# func to fold dict down to scalar 23# func to fold dict down to scalar
24def fold(dict, fmt): 24def fold(dict, fmt):
25 a = [] 25 s = ''
26 for k, v in dict.items(): 26 for k, v in dict.items():
27 k = k.strip('"') # complex keys may be in quotes
27 if v == True: 28 if v == True:
28 a.append(k) 29 s += fmt[0] + k
29 elif not (v == None or v == False): 30 elif not (v == None or v == False):
30 a.append(fmt.format(k, v)) 31 s += fmt.format(k, v)
31 return ','.join(str(x) for x in a) 32 return s[1:]
32 33
33# fold these dicts vars down to scalar, based on item values 34# fold these dicts vars down to scalar, based on item values
34fold_dicts = { 35fold_dicts = {
35 'ami_access': '{0}', 36 'ami_access': ',{0}',
36 'ami_regions': '{0}', 37 'ami_regions': ',{0}',
37 'repos': '@{1} {0}', 38 'repos': "\n@{1} {0}",
38 'pkgs': '{0}@{1}' 39 'pkgs': ' {0}@{1}',
40 'kernel_modules': ',{0}',
41 'kernel_options': ' {0}'
39} 42}
40 43
41# parse/resolve HOCON profile config, we need just the 'builds' portion 44# parse/resolve HOCON profile config, we need just the 'builds' portion
@@ -62,17 +65,17 @@ for bk, b in builds.items():
62 b[dk] = fold(b[dk], fmt) 65 b[dk] = fold(b[dk], fmt)
63 66
64 # fold 'svcs' dict to scalar 67 # fold 'svcs' dict to scalar
65 svcs = {} 68 lvls = {}
66 for svc, v in b['svcs'].items(): 69 for svc, lvl in b['svcs'].items():
67 if v == True: 70 if lvl == True:
68 # service in default runlevel 71 # service in default runlevel
69 svcs['default'].append(svc) 72 lvls['default'].append(svc)
70 elif not (v == None or v == False): 73 elif not (lvl == None or lvl == False):
71 # service in specified runlevel (skip svc when false/null) 74 # service in specified runlevel (skip svc when false/null)
72 if v not in svcs.keys(): 75 if lvl not in lvls.keys():
73 svcs[v] = [] 76 lvls[lvl] = []
74 svcs[v].append(svc) 77 lvls[lvl].append(svc)
75 b['svcs'] = ':'.join(str(l) + '=' + ','.join(str(s) for s in ss) for l, ss in svcs.items()) 78 b['svcs'] = ' '.join(str(lvl) + '=' + ','.join(str(svc) for svc in svcs) for lvl, svcs in lvls.items())
76 79
77 # write build def json file 80 # write build def json file
78 with open(vars_file, 'w') as out: 81 with open(vars_file, 'w') as out:
diff --git a/scripts/setup-ami.sh b/scripts/setup-ami.sh
index b79768c..72157a5 100755
--- a/scripts/setup-ami.sh
+++ b/scripts/setup-ami.sh
@@ -3,6 +3,9 @@
3 3
4set -eu 4set -eu
5 5
6# what bootloader should we use?
7[ -d "/sys/firmware/efi" ] && BOOTLOADER=grub-efi || BOOTLOADER=syslinux
8
6die() { 9die() {
7 printf '\033[1;31mERROR:\033[0m %s\n' "$@" >&2 # bold red 10 printf '\033[1;31mERROR:\033[0m %s\n' "$@" >&2 # bold red
8 exit 1 11 exit 1
@@ -55,21 +58,55 @@ fetch_apk_tools() {
55 find "$store" -name apk 58 find "$store" -name apk
56} 59}
57 60
61# mostly from Alpine's /sbin/setup-disk
62setup_partitions() {
63 # TODO: do we really need to waste 1M?
64 local diskdev="$1" start=1M line=
65 shift
66
67 # create new partitions
68 (
69 for line in "$@"; do
70 case "$line" in
71 0M*) ;;
72 *) echo "$start,$line"; start= ;;
73 esac
74 done
75 ) | sfdisk --quiet --label $DISKLABEL $diskdev
76
77 # create device nodes if not exist
78 mdev -s
79}
80
58make_filesystem() { 81make_filesystem() {
59 local device="$1" # target device path 82 local device="$1" # target device path
60 local target="$2" # mount target 83 local root_dev="$1" # root partition
84 local target="$2" # mount target
85 local efi_dev= # EFI partition
86
87 if [ "$BOOTLOADER" = 'grub-efi' ]; then
88 # create a small EFI partition (remainder for root), and format it
89 setup_partitions "$device" '5M,EF' ',L'
90 efi_dev="${device}1"
91 root_dev="${device}2"
92 mkfs.vfat -n EFI "${device}1"
93 fi
61 94
62 mkfs.ext4 -O ^64bit "$device" 95 mkfs.ext4 -O ^64bit -L / "$root_dev"
63 e2label "$device" / 96 mount "$root_dev" "$target"
64 mount "$device" "$target" 97
98 if [ "$BOOTLOADER" = 'grub-efi' ]; then
99 mkdir -p "$target"/boot/efi
100 mount -t vfat "$efi_dev" "$target"/boot/efi
101 fi
102 # TODO? return "$root_dev"
65} 103}
66 104
67setup_repositories() { 105setup_repositories() {
68 local target="$1" # target directory 106 local target="$1" # target directory
69 local repos="$2" # repositories
70 107
71 mkdir -p "$target"/etc/apk/keys 108 mkdir -p "$target"/etc/apk/keys
72 echo "$repos" > "$target"/etc/apk/repositories 109 echo "$REPOS" > "$target"/etc/apk/repositories
73} 110}
74 111
75fetch_keys() { 112fetch_keys() {
@@ -107,9 +144,8 @@ setup_chroot() {
107 144
108install_core_packages() { 145install_core_packages() {
109 local target="$1" # target directory 146 local target="$1" # target directory
110 local pkgs="$2" # packages, space separated
111 147
112 chroot "$target" apk --no-cache add $pkgs 148 chroot "$target" apk --no-cache add $PKGS
113 149
114 chroot "$target" apk --no-cache add --no-scripts $BOOTLOADER 150 chroot "$target" apk --no-cache add --no-scripts $BOOTLOADER
115 151
@@ -131,26 +167,28 @@ setup_mdev() {
131 sed -n -i -e '/# fallback/r /tmp/nvme-ebs-mdev.conf' -e 1x -e '2,${x;p}' -e '${x;p}' "$target"/etc/mdev.conf 167 sed -n -i -e '/# fallback/r /tmp/nvme-ebs-mdev.conf' -e 1x -e '2,${x;p}' -e '${x;p}' "$target"/etc/mdev.conf
132} 168}
133 169
134# TODO: use alpine-conf setup-*? (based on $BOOTLOADER)
135create_initfs() { 170create_initfs() {
136 local target="$1" 171 local target="$1"
137 172
138 # TODO: other useful mkinitfs stuff?
139
140 # Create ENA feature for mkinitfs
141 echo "kernel/drivers/net/ethernet/amazon" > \
142 "$target"/etc/mkinitfs/features.d/ena.modules
143
144 # Enable ENA and NVME features these don't hurt for any instance and are 173 # Enable ENA and NVME features these don't hurt for any instance and are
145 # hard requirements of the 5 series and i3 series of instances 174 # hard requirements of the 5 series and i3 series of instances
175 # TODO: profile-ize?
146 sed -Ei 's/^features="([^"]+)"/features="\1 nvme ena"/' \ 176 sed -Ei 's/^features="([^"]+)"/features="\1 nvme ena"/' \
147 "$target"/etc/mkinitfs/mkinitfs.conf 177 "$target"/etc/mkinitfs/mkinitfs.conf
148 178
149 chroot "$target" /sbin/mkinitfs $(basename $(find "$target"/lib/modules/* -maxdepth 0)) 179 chroot "$target" /sbin/mkinitfs $(basename $(find "$target"/lib/modules/* -maxdepth 0))
150} 180}
151 181
152# TODO: this is for syslinux only, there's likely a grub equivalence 182install_bootloader() {
153setup_extlinux() { 183 local target="$1"
184 case "$BOOTLOADER" in
185 syslinux) install_extlinux "$target" ;;
186 grub-efi) install_grub_efi "$target" ;;
187 *) die "unknown bootloader '$BOOTLOADER'" ;;
188 esac
189}
190
191install_extlinux() {
154 local target="$1" 192 local target="$1"
155 193
156 # Must use disk labels instead of UUID or devices paths so that this works 194 # Must use disk labels instead of UUID or devices paths so that this works
@@ -159,26 +197,51 @@ setup_extlinux() {
159 # 197 #
160 # Enable ext4 because the root device is formatted ext4 198 # Enable ext4 because the root device is formatted ext4
161 # 199 #
162 # Shorten timeout because EC2 has no way to interact with instance console 200 # Shorten timeout (1/10s) as EC2 has no way to interact with instance console
163 # 201 #
164 # ttyS0 is the target for EC2s "Get System Log" feature whereas tty0 is the 202 # ttyS0 is the target for EC2s "Get System Log" feature whereas tty0 is the
165 # target for EC2s "Get Instance Screenshot" feature. Enabling the serial 203 # target for EC2s "Get Instance Screenshot" feature. Enabling the serial
166 # port early in extlinux gives the most complete output in the system log. 204 # port early in extlinux gives the most complete output in the system log.
167 sed -Ei -e "s|^[# ]*(root)=.*|\1=LABEL=/|" \ 205 sed -Ei -e "s|^[# ]*(root)=.*|\1=LABEL=/|" \
168 -e "s|^[# ]*(default_kernel_opts)=.*|\1=\"console=ttyS0 console=tty0\"|" \ 206 -e "s|^[# ]*(default_kernel_opts)=.*|\1=\"$KERNEL_OPTS\"|" \
169 -e "s|^[# ]*(serial_port)=.*|\1=ttyS0|" \ 207 -e "s|^[# ]*(serial_port)=.*|\1=ttyS0|" \
170 -e "s|^[# ]*(modules)=.*|\1=sd-mod,usb-storage,ext4|" \ 208 -e "s|^[# ]*(modules)=.*|\1=$KERNEL_MODS|" \
171 -e "s|^[# ]*(default)=.*|\1=virt|" \ 209 -e "s|^[# ]*(default)=.*|\1=virt|" \
172 -e "s|^[# ]*(timeout)=.*|\1=1|" \ 210 -e "s|^[# ]*(timeout)=.*|\1=1|" \
173 "$target"/etc/update-extlinux.conf 211 "$target"/etc/update-extlinux.conf
212
213 chroot "$target" /sbin/extlinux --install /boot
214 chroot "$target" /sbin/update-extlinux --warn-only
174} 215}
175 216
176# TODO: this is for syslinux only, there's likely a grub equivalence 217install_grub_efi() {
177install_extlinux() {
178 local target="$1" 218 local target="$1"
179 219
180 chroot "$target" /sbin/extlinux --install /boot 220 case "$ARCH" in
181 chroot "$target" /sbin/update-extlinux --warn-only 221 x86_64) grub_target=x86_64-efi ; fwa=x64 ;;
222 aarch64) grub_target=arm64-efi ; fwa=aa64 ;;
223 *) die "ARCH=$ARCH is currently unsupported" ;;
224 esac
225
226 # TODO: this should be set up when we mkfs/mount
227 #mkdir -p "$target"/boot/efi
228
229 # disable nvram so grub doesn't call efibootmgr
230 chroot "$target" /sbin/grub-install --target=$grub_target --efi-directory=/boot/efi \
231 --bootloader-id=alpine --boot-directory=/boot --no-nvram
232
233 # fallback mode
234 install -D "$target"/boot/efi/EFI/alpine/grub$fwa.efi "$target"/boot/efi/EFI/boot/$fwa.efi
235
236 # add cmdline linux defaults to /etc/default/grub
237 echo "GRUB_CMDLINE_LINUX_DEFAULT=\"modules=$KERNEL_MODS $KERNEL_OPTS\"" >> "$target"/etc/default/grub
238
239 # eliminate grub pause
240 sed -ie 's/^GRUB_TIMEOUT=.$/GRUB_TIMEOUT=0/' "$target"/etc/default/grub
241
242 # generate/install new config
243 [ -e "$target"/boot/grub/grub.cfg ] && cp "$target"/boot/grub/grub.cfg "$target"/boot/grub/grub.cfg.backup
244 chroot "$target" grub-mkconfig -o /boot/grub/grub.cfg
182} 245}
183 246
184setup_fstab() { 247setup_fstab() {
@@ -188,6 +251,11 @@ setup_fstab() {
188# <fs> <mountpoint> <type> <opts> <dump/pass> 251# <fs> <mountpoint> <type> <opts> <dump/pass>
189LABEL=/ / ext4 defaults,noatime 1 1 252LABEL=/ / ext4 defaults,noatime 1 1
190EOF 253EOF
254
255 # if we're using grub-efi bootloader, add extra line for EFI partition
256 if [ "$BOOTLOADER" = 'grub-efi' ]; then
257 echo "LABEL=EFI /boot/efi vfat defaults,noatime,uid=0,gid=0,umask=077 0 0" >> "$target"/etc/fstab
258 fi
191} 259}
192 260
193setup_networking() { 261setup_networking() {
@@ -204,9 +272,8 @@ EOF
204 272
205enable_services() { 273enable_services() {
206 local target="$1" 274 local target="$1"
207 local svcs="$2"
208 275
209 local lvl_svcs; for lvl_svcs in $svcs; do 276 local lvl_svcs; for lvl_svcs in $SVCS; do
210 rc_add "$target" $(echo "$lvl_svcs" | tr =, ' ') 277 rc_add "$target" $(echo "$lvl_svcs" | tr =, ' ')
211 done 278 done
212} 279}
@@ -267,10 +334,6 @@ cleanup() {
267} 334}
268 335
269main() { 336main() {
270 local repos=$(echo "$REPOS" | tr , "\n")
271 local pkgs=$(echo "$PKGS" | tr , ' ')
272 local svcs=$(echo "$SVCS" | tr : ' ')
273
274 local device="/dev/xvdf" 337 local device="/dev/xvdf"
275 local target="/mnt/target" 338 local target="/mnt/target"
276 339
@@ -285,7 +348,7 @@ main() {
285 make_filesystem "$device" "$target" 348 make_filesystem "$device" "$target"
286 349
287 einfo "Configuring Alpine repositories" 350 einfo "Configuring Alpine repositories"
288 setup_repositories "$target" "$repos" 351 setup_repositories "$target"
289 352
290 einfo "Fetching Alpine signing keys" 353 einfo "Fetching Alpine signing keys"
291 fetch_keys "$target" 354 fetch_keys "$target"
@@ -296,19 +359,17 @@ main() {
296 setup_chroot "$target" 359 setup_chroot "$target"
297 360
298 einfo "Installing core packages" 361 einfo "Installing core packages"
299 install_core_packages "$target" "$pkgs" 362 install_core_packages "$target"
300 363
301 # TODO: syslinux vs grub, maybe use setup-* scripts?
302 einfo "Configuring and enabling boot loader" 364 einfo "Configuring and enabling boot loader"
303 create_initfs "$target" 365 create_initfs "$target"
304 setup_extlinux "$target" 366 install_bootloader "$target"
305 install_extlinux "$target"
306 367
307 einfo "Configuring system" 368 einfo "Configuring system"
308 setup_mdev "$target" 369 setup_mdev "$target"
309 setup_fstab "$target" 370 setup_fstab "$target"
310 setup_networking "$target" 371 setup_networking "$target"
311 enable_services "$target" "$svcs" 372 enable_services "$target"
312 create_alpine_user "$target" 373 create_alpine_user "$target"
313 configure_ntp "$target" 374 configure_ntp "$target"
314 375