diff --git a/alpine-cloud-images/alpine.pkr.hcl b/alpine-cloud-images/alpine.pkr.hcl index 5cd4c99..433c121 100644 --- a/alpine-cloud-images/alpine.pkr.hcl +++ b/alpine-cloud-images/alpine.pkr.hcl @@ -61,7 +61,7 @@ source qemu alpine { "root", "setup-interfaces", "ifup eth0", - "setup-sshd -c openssh", + "setup-sshd openssh", "echo PermitRootLogin yes >> /etc/ssh/sshd_config", "service sshd restart", "echo 'root:${local.password}' | chpasswd", diff --git a/alpine-cloud-images/build b/alpine-cloud-images/build index 59290e3..49bcbe0 100755 --- a/alpine-cloud-images/build +++ b/alpine-cloud-images/build @@ -48,13 +48,19 @@ from image_configs import ImageConfigManager ### Constants & Variables -STEPS = ['configs', 'state', 'local', 'import', 'publish'] +STEPS = ['configs', 'state', 'rollback', 'local', 'import', 'publish'] LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' WORK_CLEAN = {'bin', 'include', 'lib', 'pyvenv.cfg', '__pycache__'} WORK_OVERLAYS = ['configs', 'scripts'] -OVMF_FIRMWARE = { - 'aarch64': 'usr/share/OVMF/QEMU_EFI.fd', - 'x86_64': 'usr/share/OVMF/OVMF.fd' +UEFI_FIRMWARE = { + 'aarch64': { + 'apk': 'aavmf', + 'bin': 'usr/share/AAVMF/QEMU_EFI.fd', + }, + 'x86_64': { + 'apk': 'ovmf', + 'bin': 'usr/share/OVMF/OVMF.fd', + } } alpine = Alpine() @@ -120,6 +126,9 @@ def install_overlay(overlay): os.makedirs(dest_dir, exist_ok=True) for src in unique_list(['.'] + args.custom): src_dir = os.path.join(src, overlay) + if not os.path.exists(src_dir): + log.debug('%s does not exist, skipping', src_dir) + continue for x in glob(os.path.join(src_dir, '**'), recursive=True): x = x.removeprefix(src_dir + '/') src_x = os.path.join(src_dir, x) @@ -169,10 +178,12 @@ def install_qemu_firmware(): log.info('Installing UEFI firmware in work environment') os.makedirs(firm_dir) - for arch, bin in OVMF_FIRMWARE.items(): - v = alpine.apk_version('community', arch, 'ovmf') - ovmf_url = f"{alpine.repo_url('community', arch)}/ovmf-{v}.apk" - data = urlopen(ovmf_url).read() + for arch, a_cfg in UEFI_FIRMWARE.items(): + apk = a_cfg['apk'] + bin = a_cfg['bin'] + v = alpine.apk_version('community', arch, apk) + apk_url = f"{alpine.repo_url('community', arch)}/{apk}-{v}.apk" + data = urlopen(apk_url).read() # Python tarfile library can't extract from APKs tar_cmd = ['tar', '-zxf', '-', '-C', firm_dir, bin] @@ -241,6 +252,8 @@ console.setFormatter(logfmt) log.addHandler(console) log.debug(args) +# TODO: rollback requires --revise + # set up credential provider, if we're going to use it if args.use_broker: clouds.set_credential_provider(debug=args.debug) @@ -274,7 +287,7 @@ if not image_configs.refresh_state( log.info('No pending actions to take at this time.') sys.exit(0) -if args.step == 'state': +if args.step == 'state' or args.step == 'rollback': sys.exit(0) # install firmware if missing diff --git a/alpine-cloud-images/clouds/aws.py b/alpine-cloud-images/clouds/aws.py index aa9ef42..f181287 100644 --- a/alpine-cloud-images/clouds/aws.py +++ b/alpine-cloud-images/clouds/aws.py @@ -383,10 +383,13 @@ class AWSCloudAdapter(CloudAdapterInterface): # set up AMI deprecation ec2c = image.meta.client log.info('%s: Setting EOL deprecation time on %s', r, image.id) - ec2c.enable_image_deprecation( - ImageId=image.id, - DeprecateAt=f"{tags.end_of_life}T23:59:59Z" - ) + try: + ec2c.enable_image_deprecation( + ImageId=image.id, + DeprecateAt=f"{tags.end_of_life}T23:59:59Z" + ) + except Exception: + log.warning('Unable to set EOL Deprecation on %s image:', r, exc_info=True) artifacts[r] = image.id diff --git a/alpine-cloud-images/configs/alpine.conf b/alpine-cloud-images/configs/alpine.conf index 6b44962..37cf0bd 100644 --- a/alpine-cloud-images/configs/alpine.conf +++ b/alpine-cloud-images/configs/alpine.conf @@ -46,10 +46,10 @@ Default { # profile build matrix Dimensions { version { + "3.16" { include required("version/3.16.conf") } "3.15" { include required("version/3.15.conf") } "3.14" { include required("version/3.14.conf") } "3.13" { include required("version/3.13.conf") } - "3.12" { include required("version/3.12.conf") } edge { include required("version/edge.conf") } } arch { diff --git a/alpine-cloud-images/configs/arch/aarch64.conf b/alpine-cloud-images/configs/arch/aarch64.conf index 41f1161..dc4cfc3 100644 --- a/alpine-cloud-images/configs/arch/aarch64.conf +++ b/alpine-cloud-images/configs/arch/aarch64.conf @@ -1,5 +1,6 @@ # vim: ts=2 et: name = [aarch64] +arch_name = aarch64 # aarch64 is UEFI only EXCLUDE = [bios] diff --git a/alpine-cloud-images/configs/arch/x86_64.conf b/alpine-cloud-images/configs/arch/x86_64.conf index af68640..d90ba09 100644 --- a/alpine-cloud-images/configs/arch/x86_64.conf +++ b/alpine-cloud-images/configs/arch/x86_64.conf @@ -1,5 +1,6 @@ # vim: ts=2 et: name = [x86_64] +arch_name = x86_64 # TODO: until we have a image metadata service, let's avoid UEFI EXCLUDE = [uefi] diff --git a/alpine-cloud-images/configs/bootstrap/cloudinit.conf b/alpine-cloud-images/configs/bootstrap/cloudinit.conf index 4883c4e..5430221 100644 --- a/alpine-cloud-images/configs/bootstrap/cloudinit.conf +++ b/alpine-cloud-images/configs/bootstrap/cloudinit.conf @@ -1,5 +1,7 @@ # vim: ts=2 et: -# name = [cloudinit] +name = [cloudinit] +bootstrap_name = cloud-init +bootstrap_url = "https://cloud-init.io/" # start cloudinit images with 3.15 EXCLUDE = ["3.12", "3.13", "3.14"] diff --git a/alpine-cloud-images/configs/cloud/aws.conf b/alpine-cloud-images/configs/cloud/aws.conf index f7e6329..fd23f4e 100644 --- a/alpine-cloud-images/configs/cloud/aws.conf +++ b/alpine-cloud-images/configs/cloud/aws.conf @@ -1,6 +1,9 @@ # vim: ts=2 et: -builder = qemu +cloud_name = Amazon Web Services +cloud_image_url = "https://{region}.console.aws.amazon.com/ec2/home#Images:visibility=public-images;imageId={image_id}", +cloud_launch_url = "https://{region}.console.aws.amazon.com/ec2/home#launchAmi={image_id}" +builder = qemu ntp_server = 169.254.169.123 kernel_modules { diff --git a/alpine-cloud-images/configs/firmware/bios.conf b/alpine-cloud-images/configs/firmware/bios.conf index 4b8b17f..93f67c0 100644 --- a/alpine-cloud-images/configs/firmware/bios.conf +++ b/alpine-cloud-images/configs/firmware/bios.conf @@ -1,5 +1,6 @@ # vim: ts=2 et: -#name = [bios] +name = [bios] +firmware_name = BIOS bootloader = extlinux packages.syslinux = --no-scripts diff --git a/alpine-cloud-images/configs/firmware/uefi.conf b/alpine-cloud-images/configs/firmware/uefi.conf index fe23a45..12937c7 100644 --- a/alpine-cloud-images/configs/firmware/uefi.conf +++ b/alpine-cloud-images/configs/firmware/uefi.conf @@ -1,5 +1,6 @@ # vim: ts=2 et: -name = [uefi] +name = [uefi] +firmware_name = UEFI bootloader = grub-efi packages { diff --git a/alpine-cloud-images/configs/version/3.12.conf b/alpine-cloud-images/configs/version/3.12.conf index 3fbb039..9254d91 100644 --- a/alpine-cloud-images/configs/version/3.12.conf +++ b/alpine-cloud-images/configs/version/3.12.conf @@ -1,3 +1,5 @@ # vim: ts=2 et: -include required("base/1.conf") \ No newline at end of file +include required("base/1.conf") + +# NOTE: EOL 2022-05-01 \ No newline at end of file diff --git a/alpine-cloud-images/configs/version/3.16.conf b/alpine-cloud-images/configs/version/3.16.conf new file mode 100644 index 0000000..29a6936 --- /dev/null +++ b/alpine-cloud-images/configs/version/3.16.conf @@ -0,0 +1,7 @@ +# vim: ts=2 et: + +include required("base/4.conf") + +motd { + sudo_removed = "NOTE: 'sudo' is no longer installed by default, please use 'doas' instead." +} diff --git a/alpine-cloud-images/image_configs.py b/alpine-cloud-images/image_configs.py index 891ed3c..1abb964 100644 --- a/alpine-cloud-images/image_configs.py +++ b/alpine-cloud-images/image_configs.py @@ -206,6 +206,12 @@ class ImageConfig(): def image_description(self): return self.description.format(**self.__dict__) + def image_url(self, region, image_id): + return self.cloud_image_url.format(region=region, image_id=image_id, **self.__dict__) + + def launch_url(self, region, image_id): + return self.cloud_launch_url.format(region=region, image_id=image_id, **self.__dict__) + @property def tags(self): # stuff that really ought to be there diff --git a/configs/bootstrap/tiny.conf b/configs/bootstrap/tiny.conf new file mode 100644 index 0000000..1a50056 --- /dev/null +++ b/configs/bootstrap/tiny.conf @@ -0,0 +1,33 @@ +# vim: ts=2 et: +name = [tiny] +bootstrap_name = Tiny Cloud +bootstrap_url = "https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud" + +services { + sysinit.tiny-cloud-early = true + default.tiny-cloud = true + default.tiny-cloud-final = true +} + +WHEN { + aws { + packages.tiny-cloud-aws = true + WHEN { + "3.12" { + # tiny-cloud-network requires ifupdown-ng (unavailable in 3.12) + packages.tiny-cloud-aws = null + services.sysinit.tiny-cloud-early = null + services.default.tiny-cloud = null + services.default.tiny-cloud-final = null + # fall back to tiny-ec2-bootstrap instead + packages.tiny-ec2-bootstrap = true + services.default.tiny-ec2-bootstrap = true + } + } + } + # azure.packages.tiny-cloud-azure = true + # gcp.packages.tiny-cloud-gcp = true + # oci.packages.tiny-cloud-oci = true +} + +scripts = [ setup-tiny ] \ No newline at end of file diff --git a/scripts/setup-tiny b/scripts/setup-tiny new file mode 100755 index 0000000..9fc91fc --- /dev/null +++ b/scripts/setup-tiny @@ -0,0 +1,21 @@ +#!/bin/sh -eu +# vim: ts=4 et: + +[ -z "$DEBUG" ] || [ "$DEBUG" = 0 ] || set -x + +TARGET=/mnt + +einfo() { + printf '\n\033[1;7;36m> %s <\033[0m\n' "$@" >&2 # bold reversed cyan +} + +if [ "$VERSION" = "3.12" ]; then + # tiny-cloud-network requires ifupdown-ng, not in 3.12 + einfo "Configuring Tiny EC2 Bootstrap..." + echo "EC2_USER=$IMAGE_LOGIN" > /etc/conf.d/tiny-ec2-bootstrap +else + einfo "Configuring Tiny Cloud..." + sed -i.bak -Ee "s/^#?CLOUD_USER=.*/CLOUD_USER=$IMAGE_LOGIN/" \ + "$TARGET"/etc/conf.d/tiny-cloud + rm "$TARGET"/etc/conf.d/tiny-cloud.bak +fi