diff --git a/Rakefile b/Rakefile index 61e3f80865..3670300c36 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,7 @@ require "standard/rake" namespace :stemcell do desc "Build a base OS image for use in stemcells" - task :build_os_image, [:operating_system_name, :operating_system_version, :os_image_path] do |_, args| + task :build_os_image, [:operating_system_name, :operating_system_version, :os_image_path, :architecture] do |_, args| require "bosh/stemcell/archive_handler" require "bosh/stemcell/build_environment" require "bosh/stemcell/definition" @@ -11,7 +11,9 @@ namespace :stemcell do require "bosh/stemcell/stage_collection" require "bosh/stemcell/stage_runner" - definition = Bosh::Stemcell::Definition.for("null", "null", args.operating_system_name, args.operating_system_version) + args.with_defaults(architecture: Bosh::Stemcell::Definition::DEFAULT_ARCHITECTURE) + + definition = Bosh::Stemcell::Definition.for("null", "null", args.operating_system_name, args.operating_system_version, args.architecture) environment = Bosh::Stemcell::BuildEnvironment.new( ENV.to_hash, definition, @@ -42,7 +44,7 @@ namespace :stemcell do end desc "Build a stemcell, requires `os_image_path` pointing at an image created via `stemcell:build_os_image`" - task :build, [:infrastructure_name, :hypervisor_name, :operating_system_name, :operating_system_version, :os_image_path, :build_number] do |_, args| + task :build, [:infrastructure_name, :hypervisor_name, :operating_system_name, :operating_system_version, :os_image_path, :build_number, :architecture] do |_, args| require "bosh/stemcell/build_environment" require "bosh/stemcell/definition" require "bosh/stemcell/stage_collection" @@ -50,9 +52,9 @@ namespace :stemcell do require "bosh/stemcell/stemcell_packager" require "bosh/stemcell/stemcell_builder" - args.with_defaults(build_number: "0000") + args.with_defaults(build_number: "0000", architecture: Bosh::Stemcell::Definition::DEFAULT_ARCHITECTURE) - definition = Bosh::Stemcell::Definition.for(args.infrastructure_name, args.hypervisor_name, args.operating_system_name, args.operating_system_version) + definition = Bosh::Stemcell::Definition.for(args.infrastructure_name, args.hypervisor_name, args.operating_system_name, args.operating_system_version, args.architecture) environment = Bosh::Stemcell::BuildEnvironment.new( ENV.to_hash, definition, diff --git a/bosh-stemcell/lib/bosh/stemcell/arch.rb b/bosh-stemcell/lib/bosh/stemcell/arch.rb index 4e91c23b21..34d1f3a934 100644 --- a/bosh-stemcell/lib/bosh/stemcell/arch.rb +++ b/bosh-stemcell/lib/bosh/stemcell/arch.rb @@ -7,5 +7,10 @@ def self.arch def self.x86_64? arch == "x86_64" end + + # GNU triplet prefix used for multiarch library paths, e.g. x86_64-linux-gnu + def self.gnu_arch + x86_64? ? "x86_64" : "aarch64" + end end end diff --git a/bosh-stemcell/lib/bosh/stemcell/build_environment.rb b/bosh-stemcell/lib/bosh/stemcell/build_environment.rb index 307c39645f..439cac7ec2 100644 --- a/bosh-stemcell/lib/bosh/stemcell/build_environment.rb +++ b/bosh-stemcell/lib/bosh/stemcell/build_environment.rb @@ -193,10 +193,11 @@ def exclude_exclusions when Infrastructure::Gdch::NAME " --tag ~exclude_on_gdch" end, + " --tag ~exclude_on_#{definition.architecture}", if operating_system.variant? " --tag ~exclude_on_#{operating_system.variant}" end - ].compact.join(" ").rstrip + ].compact.join(" ").squeeze(" ").rstrip end def image_file_path diff --git a/bosh-stemcell/lib/bosh/stemcell/builder_options.rb b/bosh-stemcell/lib/bosh/stemcell/builder_options.rb index 9144fbbefc..15e668dc3a 100644 --- a/bosh-stemcell/lib/bosh/stemcell/builder_options.rb +++ b/bosh-stemcell/lib/bosh/stemcell/builder_options.rb @@ -24,6 +24,7 @@ def default "stemcell_operating_system" => operating_system.name, "stemcell_operating_system_version" => operating_system.version, "stemcell_operating_system_variant" => operating_system.variant, + "stemcell_arch" => definition.architecture, "ruby_bin" => ruby_bin, "image_create_disk_size" => image_create_disk_size, "os_image_tgz" => os_image_tgz_path diff --git a/bosh-stemcell/lib/bosh/stemcell/definition.rb b/bosh-stemcell/lib/bosh/stemcell/definition.rb index ac6fabd5a8..26e972166c 100644 --- a/bosh-stemcell/lib/bosh/stemcell/definition.rb +++ b/bosh-stemcell/lib/bosh/stemcell/definition.rb @@ -3,20 +3,24 @@ module Bosh::Stemcell class Definition - attr_reader :infrastructure, :hypervisor_name, :operating_system + DEFAULT_ARCHITECTURE = "amd64".freeze - def self.for(infrastructure_name, hypervisor_name, operating_system_name, operating_system_version) + attr_reader :infrastructure, :hypervisor_name, :operating_system, :architecture + + def self.for(infrastructure_name, hypervisor_name, operating_system_name, operating_system_version, architecture = DEFAULT_ARCHITECTURE) new( Bosh::Stemcell::Infrastructure.for(infrastructure_name), hypervisor_name, - Bosh::Stemcell::OperatingSystem.for(operating_system_name, operating_system_version) + Bosh::Stemcell::OperatingSystem.for(operating_system_name, operating_system_version), + architecture ) end - def initialize(infrastructure, hypervisor_name, operating_system) + def initialize(infrastructure, hypervisor_name, operating_system, architecture = DEFAULT_ARCHITECTURE) @infrastructure = infrastructure @hypervisor_name = hypervisor_name @operating_system = operating_system + @architecture = architecture || DEFAULT_ARCHITECTURE end def stemcell_name(disk_format) @@ -28,6 +32,8 @@ def stemcell_name(disk_format) stemcell_name_parts << operating_system.version if operating_system.version stemcell_name_parts << operating_system.variant if operating_system.variant stemcell_name_parts << disk_format unless disk_format == infrastructure.default_disk_format + # amd64 stemcell names carry no architecture suffix; other architectures do. + stemcell_name_parts << architecture unless architecture == DEFAULT_ARCHITECTURE stemcell_name_parts.join("-") end @@ -38,7 +44,8 @@ def disk_formats def ==(other) infrastructure == other.infrastructure && - operating_system == other.operating_system + operating_system == other.operating_system && + architecture == other.architecture end end end diff --git a/bosh-stemcell/lib/bosh/stemcell/infrastructure.rb b/bosh-stemcell/lib/bosh/stemcell/infrastructure.rb index be37b1a58e..72d0234425 100644 --- a/bosh-stemcell/lib/bosh/stemcell/infrastructure.rb +++ b/bosh-stemcell/lib/bosh/stemcell/infrastructure.rb @@ -46,6 +46,15 @@ def additional_cloud_properties {} end + # Maps the BOSH/Debian architecture to the value recorded as + # cloud_properties.architecture in stemcell.MF, which CPIs consume unchanged. + # Raises for an unmapped architecture; override where a CPI expects another spelling. + def architecture_name(architecture) + {"amd64" => "x86_64", "arm64" => "aarch64"}.fetch(architecture) do + raise ArgumentError, "Unsupported stemcell architecture: #{architecture}" + end + end + def ==(other) name == other.name && hypervisor == other.hypervisor && @@ -129,6 +138,12 @@ def additional_cloud_properties "boot_mode" => "uefi-preferred" } end + + # The AWS CPI passes the architecture to EC2 RegisterImage unchanged, which + # accepts "arm64" but not "aarch64". + def architecture_name(architecture) + (architecture == "arm64") ? "arm64" : super + end end class Alicloud < Base diff --git a/bosh-stemcell/lib/bosh/stemcell/stemcell_packager.rb b/bosh-stemcell/lib/bosh/stemcell/stemcell_packager.rb index 428a1b525d..2636ce804d 100644 --- a/bosh-stemcell/lib/bosh/stemcell/stemcell_packager.rb +++ b/bosh-stemcell/lib/bosh/stemcell/stemcell_packager.rb @@ -50,7 +50,7 @@ def manifest(disk_format) end def manifest_cloud_properties(disk_format, infrastructure, stemcell_name) - architecture = "x86_64" + architecture = infrastructure.architecture_name(definition.architecture) { "name" => stemcell_name, diff --git a/bosh-stemcell/spec/assets/dpkg-list-ubuntu-arm64.txt b/bosh-stemcell/spec/assets/dpkg-list-ubuntu-arm64.txt new file mode 100644 index 0000000000..121c43f288 --- /dev/null +++ b/bosh-stemcell/spec/assets/dpkg-list-ubuntu-arm64.txt @@ -0,0 +1,495 @@ +adduser +anacron +apparmor +apparmor-utils +apt +apt-utils +auditd +autoconf +automake +autopoint +autotools-dev +base-files +base-passwd +bash +bind9-dnsutils +bind9-host +bind9-libs:arm64 +binutils +binutils-aarch64-linux-gnu +binutils-common:arm64 +bison +bsdextrautils +bsdutils +build-essential +busybox-initramfs +bzip2 +ca-certificates +chrony +cloud-guest-utils +cmake +cmake-data +console-setup +console-setup-linux +coreutils +cpio +cpp +cpp-13 +cpp-13-aarch64-linux-gnu +cpp-aarch64-linux-gnu +cron +cron-daemon-common +curl +dash +dbus +dbus-bin +dbus-daemon +dbus-session-bus-common +dbus-system-bus-common +dbus-user-session +debconf +debconf-i18n +debhelper +debianutils +debugedit +dh-autoreconf +dh-strip-nondeterminism +dhcpcd-base +diffutils +distro-info +distro-info-data +dmsetup +dnsutils +dpkg +dpkg-dev +dracut-install +dwz +e2fsprogs +eject +ethtool +fdisk +file +findutils +flex +g++ +g++-13 +g++-13-aarch64-linux-gnu +g++-aarch64-linux-gnu +gcc +gcc-13 +gcc-13-aarch64-linux-gnu +gcc-13-base:arm64 +gcc-14-base:arm64 +gcc-aarch64-linux-gnu +gdb +gdisk +gettext +gettext-base +gir1.2-girepository-2.0:arm64 +gir1.2-glib-2.0:arm64 +gir1.2-packagekitglib-1.0 +gpg +gpg-agent +gpgconf +gpgv +grep +groff-base +grub-common +grub-efi-arm64 +grub-efi-arm64-bin +grub-efi-arm64-signed +grub2-common +gzip +hostname +htop +icu-devtools +ifupdown +init +init-system-helpers +initramfs-tools +initramfs-tools-bin +initramfs-tools-core +intltool-debian +iproute2 +iptables +iputils-arping +iputils-ping +iso-codes +kbd +keyboard-configuration +klibc-utils +kmod +krb5-locales +less +libacl1:arm64 +libaio1t64:arm64 +libapparmor1:arm64 +libappstream5:arm64 +libapt-pkg6.0t64:arm64 +libarchive-zip-perl +libarchive13t64:arm64 +libargon2-1:arm64 +libasan8:arm64 +libassuan0:arm64 +libatm1t64:arm64 +libatomic1:arm64 +libattr1:arm64 +libaudit-common +libaudit1:arm64 +libauparse0t64:arm64 +libbabeltrace1:arm64 +libbinutils:arm64 +libblkid1:arm64 +libbpf1:arm64 +libbrotli1:arm64 +libbsd0:arm64 +libbz2-1.0:arm64 +libbz2-dev:arm64 +libc-bin +libc-dev-bin +libc6-dev:arm64 +libc6:arm64 +libcap-dev:arm64 +libcap-ng0:arm64 +libcap2-bin +libcap2:arm64 +libcbor0.10:arm64 +libcc1-0:arm64 +libcom-err2:arm64 +libcrack2:arm64 +libcrypt-dev:arm64 +libcrypt1:arm64 +libcryptsetup12:arm64 +libctf-nobfd0:arm64 +libctf0:arm64 +libcurl3t64-gnutls:arm64 +libcurl4-openssl-dev:arm64 +libcurl4t64:arm64 +libdb5.3t64:arm64 +libdbus-1-3:arm64 +libdebconfclient0:arm64 +libdebhelper-perl +libdebuginfod-common +libdebuginfod1t64:arm64 +libdevmapper1.02.1:arm64 +libdpkg-perl +libduktape207:arm64 +libdw1t64:arm64 +libedit2:arm64 +libefiboot1t64:arm64 +libefivar1t64:arm64 +libelf1t64:arm64 +libestr0:arm64 +libexpat1:arm64 +libext2fs2t64:arm64 +libfastjson4:arm64 +libfdisk1:arm64 +libffi8:arm64 +libfido2-1:arm64 +libfile-stripnondeterminism-perl +libfreetype6:arm64 +libfribidi0:arm64 +libfuse3-3:arm64 +libgcc-13-dev:arm64 +libgcc-s1:arm64 +libgcrypt20-dev +libgcrypt20:arm64 +libgdbm-compat4t64:arm64 +libgdbm6t64:arm64 +libgirepository-1.0-1:arm64 +libglib2.0-0t64:arm64 +libglib2.0-bin +libglib2.0-data +libgmp10:arm64 +libgnutls30t64:arm64 +libgomp1:arm64 +libgpg-error-dev +libgpg-error0:arm64 +libgprofng0:arm64 +libgssapi-krb5-2:arm64 +libgstreamer1.0-0:arm64 +libhogweed6t64:arm64 +libhwasan0:arm64 +libibverbs1:arm64 +libicu-dev:arm64 +libicu74:arm64 +libidn2-0:arm64 +libinih1:arm64 +libip4tc2:arm64 +libip6tc2:arm64 +libisl23:arm64 +libitm1:arm64 +libjansson4:arm64 +libjson-c5:arm64 +libjsoncpp25:arm64 +libk5crypto3:arm64 +libkeyutils1:arm64 +libklibc:arm64 +libkmod2:arm64 +libkrb5-3:arm64 +libkrb5support0:arm64 +libldap2:arm64 +liblmdb0:arm64 +liblocale-gettext-perl +liblsan0:arm64 +liblz4-1:arm64 +liblzma5:arm64 +libmagic-mgc +libmagic1t64:arm64 +libmaxminddb0:arm64 +libmd0:arm64 +libmnl0:arm64 +libmount1:arm64 +libmpc3:arm64 +libmpfr6:arm64 +libncurses-dev:arm64 +libncurses6:arm64 +libncursesw6:arm64 +libnetfilter-conntrack3:arm64 +libnetplan1:arm64 +libnettle8t64:arm64 +libnewt0.52:arm64 +libnfnetlink0:arm64 +libnftables1:arm64 +libnftnl11:arm64 +libnghttp2-14:arm64 +libnl-3-200:arm64 +libnl-genl-3-200:arm64 +libnl-route-3-200:arm64 +libnpth0t64:arm64 +libnss-systemd:arm64 +libnvme1t64 +libp11-kit0:arm64 +libpackagekit-glib2-18:arm64 +libpam-cap:arm64 +libpam-modules-bin +libpam-modules:arm64 +libpam-pwquality:arm64 +libpam-runtime +libpam-systemd:arm64 +libpam0g:arm64 +libparted2t64:arm64 +libpcap0.8t64:arm64 +libpcre2-8-0:arm64 +libperl5.38t64:arm64 +libpipeline1:arm64 +libpng16-16t64:arm64 +libpolkit-agent-1-0:arm64 +libpolkit-gobject-1-0:arm64 +libpopt0:arm64 +libproc2-0:arm64 +libpsl5t64:arm64 +libpwquality-common +libpwquality1:arm64 +libpython3-stdlib:arm64 +libpython3.12-minimal:arm64 +libpython3.12-stdlib:arm64 +libpython3.12t64:arm64 +libreadline-dev:arm64 +libreadline8t64:arm64 +librelp0:arm64 +librhash0:arm64 +librtmp1:arm64 +libsasl2-2:arm64 +libsasl2-modules-db:arm64 +libseccomp2:arm64 +libselinux1:arm64 +libsemanage-common +libsemanage2:arm64 +libsensors-config +libsensors5:arm64 +libsepol2:arm64 +libsframe1:arm64 +libslang2:arm64 +libsmartcols1:arm64 +libsource-highlight-common +libsource-highlight4t64:arm64 +libsqlite3-0:arm64 +libss2:arm64 +libssh-4:arm64 +libssl-dev:arm64 +libssl3t64:arm64 +libstdc++-13-dev:arm64 +libstdc++6:arm64 +libstemmer0d:arm64 +libsub-override-perl +libsystemd-shared:arm64 +libsystemd0:arm64 +libtasn1-6:arm64 +libtext-charwidth-perl:arm64 +libtext-iconv-perl:arm64 +libtext-wrapi18n-perl +libtinfo6:arm64 +libtirpc-common +libtirpc3t64:arm64 +libtool +libtsan2:arm64 +libubsan1:arm64 +libuchardet0:arm64 +libudev1:arm64 +libunistring5:arm64 +libunwind8:arm64 +liburcu8t64:arm64 +libuuid1:arm64 +libuv1t64:arm64 +libwrap0:arm64 +libxml2-dev:arm64 +libxml2:arm64 +libxmlb2:arm64 +libxslt1-dev:arm64 +libxslt1.1:arm64 +libxtables12:arm64 +libxxhash0:arm64 +libyaml-0-2:arm64 +libzstd1:arm64 +linux-base +linux-firmware +linux-firmware-amd-graphics +linux-firmware-amd-misc +linux-firmware-broadcom-wireless +linux-firmware-intel-graphics +linux-firmware-intel-misc +linux-firmware-intel-wireless +linux-firmware-marvell-prestera +linux-firmware-marvell-wireless +linux-firmware-mediatek +linux-firmware-mellanox-spectrum +linux-firmware-misc +linux-firmware-netronome +linux-firmware-nvidia-graphics +linux-firmware-qlogic +linux-firmware-qualcomm-graphics +linux-firmware-qualcomm-misc +linux-firmware-qualcomm-wireless +linux-firmware-realtek +linux-libc-dev:arm64 +locales +login +logrotate +logsave +lsb-release +lsof +lto-disabled-list +m4 +make +man-db +mawk +media-types +module-assistant +mokutil +mount +ncurses-base +ncurses-bin +net-tools +netbase +netcat-openbsd +netplan-generator +networkd-dispatcher +nftables +nvme-cli +openssh-client +openssh-server +openssh-sftp-server +openssl +packagekit +parted +passwd +patch +perl +perl-base +perl-modules-5.38 +pinentry-curses +po-debconf +polkitd +procps +psmisc +python-apt-common +python3 +python3-apparmor +python3-apt +python3-blinker +python3-cffi-backend:arm64 +python3-cryptography +python3-dbus +python3-distro +python3-gi +python3-httplib2 +python3-jwt +python3-launchpadlib +python3-lazr.restfulclient +python3-lazr.uri +python3-libapparmor +python3-markdown-it +python3-mdurl +python3-minimal +python3-netifaces:arm64 +python3-netplan +python3-oauthlib +python3-pkg-resources +python3-pygments +python3-pyparsing +python3-rich +python3-six +python3-software-properties +python3-typing-extensions +python3-wadllib +python3-yaml +python3.12 +python3.12-minimal +quota +readline-common +rng-tools-debian +rpcsvc-proto +rsync +rsyslog +rsyslog-gnutls +rsyslog-openssl +rsyslog-relp +runit +sbsigntool +sed +sensible-utils +sgml-base +shared-mime-info +shim-signed +software-properties-common +strace +sudo +sysstat +systemd +systemd-dev +systemd-hwe-hwdb +systemd-resolved +systemd-sysv +systemd-timesyncd +sysuser-helper +sysvinit-utils +tar +tcpdump +traceroute +tzdata +tzdata-legacy +ubuntu-keyring +ubuntu-pro-client +ubuntu-pro-client-l10n +ucf +udev +unzip +util-linux +uuid-dev:arm64 +uuid-runtime +vim-common +vim-runtime +vim-tiny +wget +whiptail +wireless-regdb +xdg-user-dirs +xfsprogs +xkb-data +xml-core +xxd +xz-utils +zip +zlib1g-dev:arm64 +zlib1g:arm64 diff --git a/bosh-stemcell/spec/bosh/stemcell/arch_spec.rb b/bosh-stemcell/spec/bosh/stemcell/arch_spec.rb new file mode 100644 index 0000000000..2acda87175 --- /dev/null +++ b/bosh-stemcell/spec/bosh/stemcell/arch_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" +require "bosh/stemcell/arch" + +module Bosh::Stemcell + describe Arch do + describe ".gnu_arch" do + it "is x86_64 on an x86_64 host" do + allow(Arch).to receive(:arch).and_return("x86_64") + expect(Arch.gnu_arch).to eq("x86_64") + end + + it "is aarch64 on an aarch64 host" do + allow(Arch).to receive(:arch).and_return("aarch64") + expect(Arch.gnu_arch).to eq("aarch64") + end + end + end +end diff --git a/bosh-stemcell/spec/bosh/stemcell/build_environment_spec.rb b/bosh-stemcell/spec/bosh/stemcell/build_environment_spec.rb index 8ea3a922d1..475be7849c 100644 --- a/bosh-stemcell/spec/bosh/stemcell/build_environment_spec.rb +++ b/bosh-stemcell/spec/bosh/stemcell/build_environment_spec.rb @@ -17,7 +17,8 @@ module Bosh::Stemcell instance_double( "Bosh::Stemcell::Definition", infrastructure: infrastructure, - operating_system: operating_system + operating_system: operating_system, + architecture: "amd64" ) end @@ -211,7 +212,7 @@ module Bosh::Stemcell "OS_NAME=#{operating_system.name}", "OS_VERSION=#{operating_system.version}", "CANDIDATE_BUILD_NUMBER=#{version}", - "bundle exec rspec -fd --tag ~exclude_on_fips", + "bundle exec rspec -fd --tag ~exclude_on_amd64 --tag ~exclude_on_fips", "spec/os_image/#{operating_system.name}_spec.rb", "spec/stemcells/#{operating_system.name}_spec.rb", "spec/stemcells/go_agent_spec.rb", @@ -243,7 +244,7 @@ module Bosh::Stemcell "OS_NAME=#{operating_system.name}", "OS_VERSION=#{operating_system.version}", "CANDIDATE_BUILD_NUMBER=#{version}", - "bundle exec rspec -fd --tag ~exclude_on_gdch", + "bundle exec rspec -fd --tag ~exclude_on_gdch --tag ~exclude_on_amd64", "spec/os_image/#{operating_system.name}_spec.rb", "spec/stemcells/#{operating_system.name}_spec.rb", "spec/stemcells/go_agent_spec.rb", @@ -255,6 +256,40 @@ module Bosh::Stemcell expect(subject.stemcell_rspec_command).to eq(expected_rspec_command) end end + + context "when the architecture is arm64" do + let(:definition) do + instance_double( + "Bosh::Stemcell::Definition", + infrastructure: infrastructure, + operating_system: operating_system, + architecture: "arm64" + ) + end + + before { allow(operating_system).to receive(:variant?).and_return(false) } + + it "excludes arm64 tagged specs instead of amd64 tagged specs" do + expected_rspec_command = [ + "cd #{stemcell_specs_dir};", + "STEMCELL_IMAGE=#{File.join(work_path, "fake-root-disk-image.raw")}", + "STEMCELL_WORKDIR=#{work_path}", + "STEMCELL_INFRASTRUCTURE=#{infrastructure.name}", + "OS_NAME=#{operating_system.name}", + "OS_VERSION=#{operating_system.version}", + "CANDIDATE_BUILD_NUMBER=#{version}", + "bundle exec rspec -fd --tag ~exclude_on_arm64", + "spec/os_image/#{operating_system.name}_spec.rb", + "spec/stemcells/#{operating_system.name}_spec.rb", + "spec/stemcells/go_agent_spec.rb", + "spec/stemcells/#{infrastructure.name}_spec.rb", + "spec/stemcells/stig_spec.rb", + "spec/stemcells/cis_spec.rb" + ].join(" ") + + expect(subject.stemcell_rspec_command).to eq(expected_rspec_command) + end + end end describe "#build_path" do diff --git a/bosh-stemcell/spec/bosh/stemcell/builder_options_spec.rb b/bosh-stemcell/spec/bosh/stemcell/builder_options_spec.rb index b76cdbe0ed..3b010dbda7 100644 --- a/bosh-stemcell/spec/bosh/stemcell/builder_options_spec.rb +++ b/bosh-stemcell/spec/bosh/stemcell/builder_options_spec.rb @@ -20,7 +20,8 @@ module Bosh::Stemcell instance_double( "Bosh::Stemcell::Definition", infrastructure: infrastructure, - operating_system: operating_system + operating_system: operating_system, + architecture: "amd64" ) } @@ -58,6 +59,11 @@ module Bosh::Stemcell expect(result["stemcell_operating_system_variant"]).to eq("bear") end + it "sets the stemcell architecture" do + result = stemcell_builder_options.default + expect(result["stemcell_arch"]).to eq("amd64") + end + # rubocop:disable Metrics/MethodLength def self.it_sets_correct_environment_variables describe "setting enviroment variables" do diff --git a/bosh-stemcell/spec/bosh/stemcell/definition_spec.rb b/bosh-stemcell/spec/bosh/stemcell/definition_spec.rb index f66dbb1e10..81fd318a28 100644 --- a/bosh-stemcell/spec/bosh/stemcell/definition_spec.rb +++ b/bosh-stemcell/spec/bosh/stemcell/definition_spec.rb @@ -41,7 +41,7 @@ module Bosh::Stemcell definition = instance_double("Bosh::Stemcell::Definition") expect(Bosh::Stemcell::Definition) .to receive(:new) - .with(infrastructure, hypervisor, operating_system) + .with(infrastructure, hypervisor, operating_system, "amd64") .and_return(definition) Bosh::Stemcell::Definition.for( @@ -51,12 +51,52 @@ module Bosh::Stemcell "operating-system-version" ) end + + it "passes an explicit architecture through to the new definition" do + expect(Bosh::Stemcell::Infrastructure) + .to receive(:for) + .with("infrastructure-name") + .and_return(infrastructure) + + expect(Bosh::Stemcell::OperatingSystem) + .to receive(:for) + .with("operating-system-name", "operating-system-version") + .and_return(operating_system) + + definition = instance_double("Bosh::Stemcell::Definition") + expect(Bosh::Stemcell::Definition) + .to receive(:new) + .with(infrastructure, hypervisor, operating_system, "arm64") + .and_return(definition) + + Bosh::Stemcell::Definition.for( + "infrastructure-name", + hypervisor, + "operating-system-name", + "operating-system-version", + "arm64" + ) + end end describe "#initialize" do its(:infrastructure) { should == infrastructure } its(:operating_system) { should == operating_system } its(:hypervisor_name) { should == hypervisor } + + it "defaults the architecture to amd64" do + expect(definition.architecture).to eq("amd64") + end + + context "when an architecture is provided" do + subject(:definition) do + Bosh::Stemcell::Definition.new(infrastructure, hypervisor, operating_system, "arm64") + end + + it "uses the provided architecture" do + expect(definition.architecture).to eq("arm64") + end + end end describe "#==" do @@ -113,6 +153,26 @@ module Bosh::Stemcell ) end end + + context "the architecture is the default (amd64)" do + it "leaves the architecture off the name" do + expect(definition.stemcell_name("disk-format")).to eq( + "infrastructure-name-hypervisor-operating-system-name-operating_system_version-disk-format" + ) + end + end + + context "the architecture is non-default (arm64)" do + subject(:definition) do + Bosh::Stemcell::Definition.new(infrastructure, hypervisor, operating_system, "arm64") + end + + it "appends the architecture to the name" do + expect(definition.stemcell_name("disk-format")).to eq( + "infrastructure-name-hypervisor-operating-system-name-operating_system_version-disk-format-arm64" + ) + end + end end describe "disk_formats" do diff --git a/bosh-stemcell/spec/bosh/stemcell/infrastructure_spec.rb b/bosh-stemcell/spec/bosh/stemcell/infrastructure_spec.rb index 8e817e456c..d24eafb28b 100644 --- a/bosh-stemcell/spec/bosh/stemcell/infrastructure_spec.rb +++ b/bosh-stemcell/spec/bosh/stemcell/infrastructure_spec.rb @@ -41,6 +41,31 @@ module Bosh::Stemcell ) expect(infrastructure.additional_cloud_properties).to eq({}) end + + describe "#architecture_name" do + subject(:infrastructure) do + Infrastructure::Base.new( + name: "foo", + hypervisor: "xen", + default_disk_size: 1024, + disk_formats: [], + stemcell_formats: [] + ) + end + + it "maps amd64 to x86_64" do + expect(infrastructure.architecture_name("amd64")).to eq("x86_64") + end + + it "maps arm64 to aarch64" do + expect(infrastructure.architecture_name("arm64")).to eq("aarch64") + end + + it "raises for an unsupported architecture rather than mislabeling it" do + expect { infrastructure.architecture_name("riscv64") } + .to raise_error(ArgumentError, /Unsupported stemcell architecture: riscv64/) + end + end end describe Infrastructure::NullInfrastructure do @@ -91,6 +116,22 @@ module Bosh::Stemcell it "has aws specific additional cloud properties" do expect(subject.additional_cloud_properties).to eq({"root_device_name" => "/dev/sda1", "boot_mode" => "uefi-preferred"}) end + + describe "#architecture_name" do + it "maps amd64 to x86_64" do + expect(subject.architecture_name("amd64")).to eq("x86_64") + end + + # EC2 RegisterImage accepts "arm64" but not "aarch64". + it "maps arm64 to arm64" do + expect(subject.architecture_name("arm64")).to eq("arm64") + end + + it "raises for an unsupported architecture" do + expect { subject.architecture_name("riscv64") } + .to raise_error(ArgumentError, /Unsupported stemcell architecture: riscv64/) + end + end end describe Infrastructure::Alicloud do diff --git a/bosh-stemcell/spec/bosh/stemcell/stemcell_packager_spec.rb b/bosh-stemcell/spec/bosh/stemcell/stemcell_packager_spec.rb index a7929f84ef..faf95169d7 100644 --- a/bosh-stemcell/spec/bosh/stemcell/stemcell_packager_spec.rb +++ b/bosh-stemcell/spec/bosh/stemcell/stemcell_packager_spec.rb @@ -135,6 +135,40 @@ def additional_cloud_properties expect(YAML.safe_load(contents)["agent_features"]).to eq(manifest["agent_features"]) end + context "when the definition is arm64" do + let(:definition) do + Bosh::Stemcell::Definition.new(infrastructure, "fake_hypervisor", operating_system, "arm64") + end + + it "records aarch64 as the manifest architecture" do + packager.package("raw") + actual_manifest = YAML.load_file(File.join(work_dir, "stemcell/stemcell.MF")) + expect(actual_manifest["cloud_properties"]["architecture"]).to eq("aarch64") + end + + context "on AWS" do + let(:infrastructure) { Bosh::Stemcell::Infrastructure.for("aws") } + + # The AWS CPI forwards this value to EC2 RegisterImage, which rejects "aarch64". + it "records arm64 as the manifest architecture" do + packager.package("raw") + actual_manifest = YAML.load_file(File.join(work_dir, "stemcell/stemcell.MF")) + expect(actual_manifest["cloud_properties"]["architecture"]).to eq("arm64") + end + end + end + + context "when the definition has an unsupported architecture" do + let(:definition) do + Bosh::Stemcell::Definition.new(infrastructure, "fake_hypervisor", operating_system, "riscv64") + end + + it "raises rather than mislabeling the manifest architecture" do + expect { packager.package("raw") } + .to raise_error(ArgumentError, /Unsupported stemcell architecture: riscv64/) + end + end + it "returns the path of the created tarball" do expect(packager.package(disk_format)).to eq( File.join(tarball_dir, "bosh-stemcell-1234-fake_infra-fake_hypervisor-ubuntu-noble.tgz") diff --git a/bosh-stemcell/spec/os_image/ubuntu_spec.rb b/bosh-stemcell/spec/os_image/ubuntu_spec.rb index 7e6f1faf9d..2adc5c337d 100644 --- a/bosh-stemcell/spec/os_image/ubuntu_spec.rb +++ b/bosh-stemcell/spec/os_image/ubuntu_spec.rb @@ -33,9 +33,10 @@ describe "base_apt" do describe file("/etc/apt/sources.list") do - its(:content) { should match 'deb http:\/\/(archive|snapshot).ubuntu.com\/ubuntu(|\/\d*T\d*Z) noble main universe multiverse' } - its(:content) { should match 'deb http:\/\/(archive|snapshot).ubuntu.com\/ubuntu(|\/\d*T\d*Z) noble-updates main universe multiverse' } - its(:content) { should match 'deb http:\/\/(security|snapshot).ubuntu.com\/ubuntu(|\/\d*T\d*Z) noble-security main universe multiverse' } + # ports.ubuntu.com (ubuntu-ports) serves the non-amd64 architectures. + %w[noble noble-updates noble-security].each do |listing| + its(:content) { should match %r{deb http://(archive|ports|security|snapshot)\.ubuntu\.com/ubuntu(-ports)?(|/\d*T\d*Z) #{listing} main universe multiverse} } + end end describe file("/lib/systemd/system/monit.service") do @@ -86,14 +87,18 @@ end context "installed by system_grub" do - %w[ - grub2 - ].each do |pkg| + # ARM64 has no "grub2" metapackage; grub-efi-arm64 is the equivalent. + grub_packages = Bosh::Stemcell::Arch.x86_64? ? %w[grub2] : %w[grub-efi-arm64] + grub_packages.each do |pkg| describe package(pkg) do it { should be_installed } end end - %w[unicode.pf2 menu.lst gfxblacklist.txt].each do |grub_stage| + # gfxblacklist.txt ships with the amd64 grub2 metapackage and is not present + # in the arm64 grub-efi-arm64 package set. + grub_files = %w[unicode.pf2 menu.lst] + grub_files << "gfxblacklist.txt" if Bosh::Stemcell::Arch.x86_64? + grub_files.each do |grub_stage| describe file("/boot/grub/#{grub_stage}") do it { should be_file } end @@ -163,7 +168,8 @@ end context "PAM configuration" do - describe file("/lib/x86_64-linux-gnu/security/pam_pwquality.so") do + pam_multiarch_triplet = "#{Bosh::Stemcell::Arch.gnu_arch}-linux-gnu" + describe file("/lib/#{pam_multiarch_triplet}/security/pam_pwquality.so") do it { should be_file } end diff --git a/bosh-stemcell/spec/stemcells/ubuntu_spec.rb b/bosh-stemcell/spec/stemcells/ubuntu_spec.rb index f1e879685d..84ce2f0d67 100644 --- a/bosh-stemcell/spec/stemcells/ubuntu_spec.rb +++ b/bosh-stemcell/spec/stemcells/ubuntu_spec.rb @@ -452,7 +452,9 @@ dpkg_list_packages = "dpkg --get-selections | cut -f1 | sed -E '#{linux_version_regex}'" # TODO: maby we can use awk "dpkg --get-selections | awk '!/linux-(.+)-([0-9]+.+)/&&/linux/{print $1}'" - let(:dpkg_list_ubuntu) { File.readlines(spec_asset("dpkg-list-ubuntu.txt")).map(&:chop) } + # Package names carry the architecture (e.g. libc6:amd64), so arm64 has its own list. + dpkg_list_ubuntu_file = Bosh::Stemcell::Arch.x86_64? ? "dpkg-list-ubuntu.txt" : "dpkg-list-ubuntu-arm64.txt" + let(:dpkg_list_ubuntu) { File.readlines(spec_asset(dpkg_list_ubuntu_file)).map(&:chop) } let(:dpkg_list_kernel_ubuntu) { File.readlines(spec_asset("dpkg-list-ubuntu-kernel.txt")).map(&:chop) } let(:dpkg_list_google_ubuntu) { File.readlines(spec_asset("dpkg-list-ubuntu-google-additions.txt")).map(&:chop) } let(:dpkg_list_vsphere_ubuntu) { File.readlines(spec_asset("dpkg-list-ubuntu-vsphere-additions.txt")).map(&:chop) } diff --git a/bosh-stemcell/spec/support/stemcell_shared_examples.rb b/bosh-stemcell/spec/support/stemcell_shared_examples.rb index 4c5b72bbfe..f37c2e7dc2 100644 --- a/bosh-stemcell/spec/support/stemcell_shared_examples.rb +++ b/bosh-stemcell/spec/support/stemcell_shared_examples.rb @@ -34,7 +34,8 @@ it("should be owned by root user (stig: V-38466)") { should be_owned_by("root") } end - describe file("/lib64") do + # /lib64 holds the x86_64 dynamic linker; arm64 uses /lib/ld-linux-aarch64.so.1. + describe file("/lib64"), exclude_on_arm64: true do it("should be owned by root user (stig: V-38466)") { should be_owned_by("root") } end diff --git a/ci/docker/os-image-stemcell-builder/Dockerfile b/ci/docker/os-image-stemcell-builder/Dockerfile index 40fc8e6f1a..4d2afc7628 100644 --- a/ci/docker/os-image-stemcell-builder/Dockerfile +++ b/ci/docker/os-image-stemcell-builder/Dockerfile @@ -1,6 +1,6 @@ # bosh/os-image-stemcell-builder ARG BASE_IMAGE -FROM $BASE_IMAGE +FROM $BASE_IMAGE AS base LABEL maintainer="cf-bosh@lists.cloudfoundry.org" @@ -13,9 +13,6 @@ ARG RUBY_INSTALL_URL ARG RUBY_VERSION ARG GEM_HOME -ARG OVF_TOOL_INSTALLER -ARG OVF_TOOL_INSTALLER_SHA1 - # ENV VARs ENV DEBIAN_FRONTEND="noninteractive" ENV LANG="en_US.UTF-8" @@ -78,7 +75,15 @@ RUN temp_dir="/mnt/tmp" \ RUN mkdir -p /mnt/stemcells \ && chown -R ubuntu:ubuntu /mnt/stemcells -# VMware's ovftool is used to create vSphere stemcells +# VMware's ovftool is used to create vSphere stemcells. VMware ships no arm64 +# Linux ovftool and vSphere is not an arm64 target, so it is only installed on amd64. +# +# TARGETARCH is provided automatically by BuildKit ("amd64" / "arm64"). +ARG TARGETARCH + +FROM base AS ovftool-amd64 +ARG OVF_TOOL_INSTALLER +ARG OVF_TOOL_INSTALLER_SHA1 ADD ${OVF_TOOL_INSTALLER} /tmp/ovftool_installer.bundle RUN cd /tmp \ && echo "${OVF_TOOL_INSTALLER_SHA1} /tmp/ovftool_installer.bundle" | sha1sum -c - \ @@ -87,9 +92,32 @@ RUN cd /tmp \ && bash ./ovftool_installer.bundle --eulas-agreed \ && rm -rf ./ovftool_installer.bundle /tmp/vmware-root/ /usr/local/bin/more +# On arm64 the ovftool stage is a no-op passthrough of the base image. +FROM base AS ovftool-arm64 + +# Select the arch-appropriate ovftool stage and continue the build from it. +FROM ovftool-${TARGETARCH} AS builder + +# Build args are per-stage in BuildKit, so re-declare the ones used below. +ARG META4_CLI_URL +ARG META4_VERSION +ARG SYFT_CLI_URL +ARG YQ_CLI_URL +ARG RUBY_INSTALL_URL +ARG RUBY_VERSION +ARG GEM_HOME + +# dpb587/metalink publishes no arm64 binary, so on arm64 build-docker-args.sh +# leaves META4_CLI_URL empty and meta4 is built from source with the image's Go toolchain. RUN meta4_cli_path="/usr/local/bin/meta4" \ - && curl --show-error -sL "${META4_CLI_URL}" \ - > "${meta4_cli_path}" \ + && if [ -n "${META4_CLI_URL}" ]; then \ + curl --show-error -sL "${META4_CLI_URL}" > "${meta4_cli_path}"; \ + else \ + git clone --depth 1 --branch "${META4_VERSION}" \ + https://github.com/dpb587/metalink.git /tmp/metalink \ + && ( cd /tmp/metalink && go build -o "${meta4_cli_path}" ./cli ) \ + && rm -rf /tmp/metalink; \ + fi \ && chmod +x "${meta4_cli_path}" ENV GEM_HOME="${GEM_HOME}" \ diff --git a/ci/pipeline-template.yml b/ci/pipeline-template.yml index 14916b51c3..6342776830 100644 --- a/ci/pipeline-template.yml +++ b/ci/pipeline-template.yml @@ -59,6 +59,7 @@ plan: OS_NAME: ubuntu S3_API_ENDPOINT: storage.googleapis.com OS_VERSION: (@= data.values.stemcell_details.os_short_name @)(@= FIPS @) + STEMCELL_ARCH: amd64 STEMCELL_BUCKET: bosh-core-stemcells-candidate(@= FIPS @) GIT_USER_EMAIL: (@= data.values.stemcell_details.bot_email @) GIT_USER_NAME: (@= data.values.stemcell_details.bot_name @) @@ -187,6 +188,7 @@ groups: - name: infrastructure-tending jobs: - build-os-image-stemcell-builder + - build-os-image-stemcell-builder-arm64 - ensure-integration-network - cleanup-published-* - cleanup-unpublished-* @@ -249,6 +251,50 @@ jobs: params: image: image/image.tar +- name: build-os-image-stemcell-builder-arm64 + public: true + serial: true + plan: + - get: daily + trigger: true + tags: [ arm64 ] + - get: ubuntu_base + tags: [ arm64 ] + - get: os-image-stemcell-builder-dockerfile + trigger: true + tags: [ arm64 ] + - get: bosh-stemcells-ci + tags: [ arm64 ] + - task: build-docker-args + file: bosh-stemcells-ci/ci/tasks/build-docker-args.yml + image: ubuntu_base + tags: [ arm64 ] + - task: build-image + privileged: true + tags: [ arm64 ] + config: + platform: linux + image_resource: + type: registry-image + source: + repository: concourse/oci-build-task + inputs: + - name: os-image-stemcell-builder-dockerfile + - name: docker-build-args + outputs: + - name: image + params: + CONTEXT: os-image-stemcell-builder-dockerfile/ci/docker/os-image-stemcell-builder + BUILD_ARGS_FILE: docker-build-args/docker-build-args.yml + BUILD_ARG_BASE_IMAGE: ubuntu:(@= data.values.stemcell_details.os_short_name @) + run: + path: build + - put: os-image-stemcell-builder-registry-image-arm64 + no_get: true + tags: [ arm64 ] + params: + image: image/image.tar + #! Manually triggered job that idempotently ensures the GCP subnetwork and #! firewall rule consumed by deploy-director / cleanup-bats-vms / prepare-bats #! in the test-stemcells-ipv4 and bats jobs below exist. GCP is the source of @@ -428,6 +474,7 @@ jobs: params: OPERATING_SYSTEM_NAME: ubuntu OPERATING_SYSTEM_VERSION: (@= data.values.stemcell_details.os_short_name @) + STEMCELL_ARCH: amd64 UBUNTU_DEBOOTSTRAP_MIRROR: http://mirrors.edge.kernel.org/ubuntu privileged: true vars: @@ -447,6 +494,53 @@ jobs: params: file: os-image-version/number +- name: build-os-image-arm64 + serial: true + plan: + - put: build-time + tags: [ arm64 ] + - get: bosh-stemcells-ci + tags: [ arm64 ] + - get: os-image-stemcell-builder-registry-image-arm64 + tags: [ arm64 ] + - get: bosh-linux-stemcell-builder + trigger: true + tags: [ arm64 ] + - get: os-image-version-arm64 + params: + bump: "major" + tags: [ arm64 ] + - get: usn-log + - get: stemcell-trigger + trigger: true + - task: build + file: bosh-stemcells-ci/ci/tasks/os-images/build.yml + image: os-image-stemcell-builder-registry-image-arm64 + tags: [ arm64 ] + params: + OPERATING_SYSTEM_NAME: ubuntu + OPERATING_SYSTEM_VERSION: (@= data.values.stemcell_details.os_short_name @) + STEMCELL_ARCH: arm64 + UBUNTU_DEBOOTSTRAP_MIRROR: http://ports.ubuntu.com/ubuntu-ports + privileged: true + vars: + image_os_tag: (@= data.values.stemcell_details.os_short_name @) + - put: os-image-tarball-arm64 + params: + files: + - os-image/(@= data.values.stemcell_details.os_name @).tgz + - usn-log/usn-log.json + rename: (@= data.values.stemcell_details.branch @)/(@= data.values.stemcell_details.os_name @)-arm64.meta4 + options: + author_email: (@= data.values.stemcell_details.bot_email @) + author_name: (@= data.values.stemcell_details.bot_name @) + message: 'Bump os-image tgz (arm64)' + version: os-image-version-arm64/version + - put: os-image-version-arm64 + tags: [ arm64 ] + params: + file: os-image-version-arm64/number + - name: test-unit plan: - get: bosh-stemcells-ci @@ -638,6 +732,66 @@ jobs: - #@ build_stemcell(iaas.iaas, iaas.hypervisor, "-fips") #@ end +- name: build-aws-xen-hvm-arm64 + serial: true + plan: + - in_parallel: + - get: version + passed: + - build-stemcell + resource: version + trigger: true + tags: [ arm64 ] + - get: bosh-stemcells-ci + tags: [ arm64 ] + - get: os-image-stemcell-builder-registry-image-arm64 + tags: [ arm64 ] + - get: build-time + passed: + - build-stemcell + trigger: true + tags: [ arm64 ] + - get: bosh-linux-stemcell-builder + passed: + - build-stemcell + resource: bosh-linux-stemcell-builder + tags: [ arm64 ] + - get: stemcells-index + tags: [ arm64 ] + - get: os-image-tarball + resource: os-image-tarball-arm64 + passed: + - build-os-image-arm64 + - task: create-stemcell + file: bosh-stemcells-ci/ci/tasks/build.yml + image: os-image-stemcell-builder-registry-image-arm64 + tags: [ arm64 ] + params: + HYPERVISOR: xen-hvm + IAAS: aws + OS_NAME: ubuntu + S3_API_ENDPOINT: storage.googleapis.com + OS_VERSION: (@= data.values.stemcell_details.os_short_name @) + STEMCELL_ARCH: arm64 + STEMCELL_BUCKET: bosh-core-stemcells-candidate + GIT_USER_EMAIL: (@= data.values.stemcell_details.bot_email @) + GIT_USER_NAME: (@= data.values.stemcell_details.bot_name @) + AGENT_SUFFIX: (@= data.values.stemcell_details.agent_suffix @) + privileged: true + vars: + image_os_tag: (@= data.values.stemcell_details.os_short_name @) + - put: aws-xen-hvm-arm64 + attempts: 3 + params: + files: + - stemcell/*.tgz + rename: "{{.Version}}/aws-xen-hvm(@= data.values.stemcell_details.agent_suffix @)-arm64.meta4" + options: + author_email: (@= data.values.stemcell_details.bot_email @) + author_name: (@= data.values.stemcell_details.bot_name @) + message: 'dev: (@= data.values.stemcell_details.os_name @) (arm64)' + version: candidate-build-number/number + - name: bats serial: true plan: @@ -1643,6 +1797,24 @@ resources: - #@ metalink_resource(iaas.iaas, iaas.hypervisor, "-fips") #@ end +- name: aws-xen-hvm-arm64 + type: metalink-repository + source: + mirror_files: + - destination: s3://storage.googleapis.com/bosh-core-stemcells-candidate/aws/{{.Name}} + options: + private_key: ((github_deploy_key_bosh-io-stemcells-core-index.private_key)) + filters: + - repositorypath: "*/aws-xen-hvm(@= data.values.stemcell_details.agent_suffix @)-arm64.meta4" + uri: git+ssh://git@github.com:cloudfoundry/bosh-io-stemcells-core-index.git//dev/(@= data.values.stemcell_details.os_name @)/ + url_handlers: + - include: + - (s3|https)://.* + options: + access_key: ((hmac_accesskey)) + secret_key: ((hmac_secret)) + type: s3 + - name: os-image-tarball type: metalink-repository source: @@ -1661,6 +1833,24 @@ resources: secret_key: ((hmac_secret)) type: s3 +- name: os-image-tarball-arm64 + type: metalink-repository + source: + mirror_files: + - destination: s3://storage.googleapis.com/bosh-os-images/(@= data.values.stemcell_details.branch @)-arm64/{{.Name}} + options: + private_key: ((github_deploy_key_bosh-linux-stemcell-builder.private_key)) + filters: + - repositorypath: "(@= data.values.stemcell_details.branch @)/(@= data.values.stemcell_details.os_name @)-arm64.meta4" + uri: git+ssh://git@github.com/cloudfoundry/bosh-linux-stemcell-builder.git//image-metalinks/#(@= data.values.stemcell_details.branch @) + url_handlers: + - include: + - (s3|https)://.* + options: + access_key: ((hmac_accesskey)) + secret_key: ((hmac_secret)) + type: s3 + - name: version type: semver source: @@ -1679,6 +1869,15 @@ resources: file: (@= data.values.stemcell_details.branch @)/os-image-version private_key: ((github_deploy_key_bosh-linux-stemcell-builder.private_key)) +- name: os-image-version-arm64 + type: semver + source: + driver: git + uri: git@github.com:cloudfoundry/bosh-linux-stemcell-builder + branch: release-details + file: (@= data.values.stemcell_details.branch @)/os-image-version-arm64 + private_key: ((github_deploy_key_bosh-linux-stemcell-builder.private_key)) + - name: bosh-linux-stemcell-builder-push type: git source: @@ -1868,6 +2067,14 @@ resources: username: ((dockerhub_username)) password: ((dockerhub_password)) +- name: os-image-stemcell-builder-registry-image-arm64 + type: registry-image + source: + repository: bosh/os-image-stemcell-builder + tag: (@= data.values.stemcell_details.os_short_name @)-arm64 + username: ((dockerhub_username)) + password: ((dockerhub_password)) + - name: bosh-os-image-builder-vmware-ovftool type: gcs-resource source: diff --git a/ci/tasks/build-docker-args.sh b/ci/tasks/build-docker-args.sh index d56f2c02c0..b1e90f3a91 100755 --- a/ci/tasks/build-docker-args.sh +++ b/ci/tasks/build-docker-args.sh @@ -18,12 +18,23 @@ export TZ="Etc/UTC" apt-get update -y apt-get install -y --no-install-recommends ca-certificates curl jq -meta4_cli_url="$(curl -s https://api.github.com/repos/dpb587/metalink/releases/latest \ - | jq -r '.assets[] | select(.name | match("meta4-[0-9]+.[0-9]+.[0-9]+-linux-amd64")) | .browser_download_url')" +# Select CLI assets for the architecture this task runs on, so the builder image +# can be built for both amd64 and arm64 workers. +case "$(uname -m)" in + aarch64|arm64) arch="arm64" ;; + *) arch="amd64" ;; +esac + +meta4_release="$(curl -s https://api.github.com/repos/dpb587/metalink/releases/latest)" +meta4_cli_url="$(jq -r --arg a "linux-${arch}" '.assets[] | select(.name | test("^meta4-[0-9]+\\.[0-9]+\\.[0-9]+-" + $a + "$")) | .browser_download_url' <<< "${meta4_release}")" +# dpb587/metalink publishes linux-amd64 only. When no prebuilt binary exists for +# this arch, META4_CLI_URL is left empty and the Dockerfile builds meta4 from +# source at META4_VERSION instead. +meta4_version="$(jq -r '.tag_name' <<< "${meta4_release}")" syft_cli_url="$(curl -s https://api.github.com/repos/anchore/syft/releases/latest \ - | jq -r '.assets[] | select(.name | endswith ("_linux_amd64.tar.gz")) | .browser_download_url')" + | jq -r --arg a "_linux_${arch}.tar.gz" '.assets[] | select(.name | endswith ($a)) | .browser_download_url')" yq_cli_url="$(curl -s https://api.github.com/repos/mikefarah/yq/releases/latest \ - | jq -r '.assets[] | select(.name | endswith ("linux_amd64")) | .browser_download_url')" + | jq -r --arg a "linux_${arch}" '.assets[] | select(.name | endswith ($a)) | .browser_download_url')" ruby_install_url="$(curl -s https://api.github.com/repos/postmodern/ruby-install/releases/latest \ | jq -r '.assets[] | select(.name | endswith ("tar.gz")) | .browser_download_url')" @@ -33,6 +44,7 @@ gem_home="/usr/local/bundle" cat << EOF > "${REPO_PARENT}/docker-build-args/docker-build-args.yml" META4_CLI_URL: "${meta4_cli_url}" +META4_VERSION: "${meta4_version}" SYFT_CLI_URL: "${syft_cli_url}" YQ_CLI_URL: "${yq_cli_url}" RUBY_INSTALL_URL: "${ruby_install_url}" diff --git a/ci/tasks/build.sh b/ci/tasks/build.sh index 7046eeedf5..9611b1a5f0 100755 --- a/ci/tasks/build.sh +++ b/ci/tasks/build.sh @@ -23,6 +23,7 @@ check_param IAAS check_param HYPERVISOR check_param OS_NAME check_param OS_VERSION +check_param STEMCELL_ARCH OS_IMAGE="$(readlink -f "${REPO_PARENT}/os-image-tarball"/*.tgz)" @@ -86,22 +87,32 @@ set -e cd "${REPO_PARENT}/bosh-linux-stemcell-builder" bundle install -bundle exec rake "stemcell:build[${IAAS},${HYPERVISOR},${OS_NAME},${OS_VERSION},${OS_IMAGE},${CANDIDATE_BUILD_NUMBER}]" +bundle exec rake "stemcell:build[${IAAS},${HYPERVISOR},${OS_NAME},${OS_VERSION},${OS_IMAGE},${CANDIDATE_BUILD_NUMBER},${STEMCELL_ARCH}]" SUDO # # Output and checksum the stemcell artifacts # -stemcell_name="bosh-stemcell-${CANDIDATE_BUILD_NUMBER}-${IAAS}-${HYPERVISOR}-${OS_NAME}-${OS_VERSION}${AGENT_SUFFIX}" -meta4_path="${REPO_PARENT}/stemcells-index-output/dev/${OS_NAME}-${OS_VERSION}/${CANDIDATE_BUILD_NUMBER}/${IAAS}-${HYPERVISOR}${AGENT_SUFFIX}.meta4" +# Non-default architectures carry an "-" suffix in the stemcell name +# (see Bosh::Stemcell::Definition#stemcell_name) and get their own index entry, +# so they never collide with the amd64 artifacts. +if [ "${STEMCELL_ARCH}" == "amd64" ]; then + arch_suffix="" +else + arch_suffix="-${STEMCELL_ARCH}" +fi + +stemcell_name_base="bosh-stemcell-${CANDIDATE_BUILD_NUMBER}-${IAAS}-${HYPERVISOR}-${OS_NAME}-${OS_VERSION}${AGENT_SUFFIX}" +stemcell_name="${stemcell_name_base}${arch_suffix}" +meta4_path="${REPO_PARENT}/stemcells-index-output/dev/${OS_NAME}-${OS_VERSION}/${CANDIDATE_BUILD_NUMBER}/${IAAS}-${HYPERVISOR}${AGENT_SUFFIX}${arch_suffix}.meta4" echo "${CANDIDATE_BUILD_NUMBER}" > "${REPO_PARENT}/candidate-build-number/number" mkdir -p "$( dirname "$meta4_path" )" rm -f "$meta4_path" meta4 create --metalink="$meta4_path" -raw_images=( "${REPO_PARENT}/bosh-linux-stemcell-builder/tmp"/*-raw.tgz ) +raw_images=( "${REPO_PARENT}/bosh-linux-stemcell-builder/tmp"/*-raw${arch_suffix}.tgz ) if [ "${#raw_images[@]}" -ge 2 ]; then echo "Found more than one raw image: '${raw_images[*]}'" >&2 exit 1 @@ -109,8 +120,8 @@ fi if [ -e "${raw_images[0]}" ] ; then # openstack currently publishes raw files - raw_stemcell_filename="${stemcell_name}-raw.tgz" - mv "${REPO_PARENT}/bosh-linux-stemcell-builder/tmp"/*-raw.tgz "${REPO_PARENT}/stemcell/${raw_stemcell_filename}" + raw_stemcell_filename="${stemcell_name_base}-raw${arch_suffix}.tgz" + mv "${raw_images[0]}" "${REPO_PARENT}/stemcell/${raw_stemcell_filename}" meta4 import-file --metalink="$meta4_path" --version="${CANDIDATE_BUILD_NUMBER}" "${REPO_PARENT}/stemcell/${raw_stemcell_filename}" meta4 file-set-url --metalink="$meta4_path" --file="${raw_stemcell_filename}" "https://${S3_API_ENDPOINT}/${STEMCELL_BUCKET}/${IAAS}/${raw_stemcell_filename}" @@ -130,4 +141,4 @@ cd "${REPO_PARENT}/stemcells-index-output" git add -A git config --global user.email "${GIT_USER_EMAIL}" git config --global user.name "${GIT_USER_NAME}" -git commit -m "dev: ${OS_NAME}-${OS_VERSION}/${CANDIDATE_BUILD_NUMBER} (${IAAS}-${HYPERVISOR})" +git commit -m "dev: ${OS_NAME}-${OS_VERSION}/${CANDIDATE_BUILD_NUMBER} (${IAAS}-${HYPERVISOR}${arch_suffix})" diff --git a/ci/tasks/build.yml b/ci/tasks/build.yml index beae4ce7f0..d8b8eb08c6 100644 --- a/ci/tasks/build.yml +++ b/ci/tasks/build.yml @@ -23,6 +23,7 @@ params: HYPERVISOR: replace-me OS_NAME: replace-me OS_VERSION: replace-me + STEMCELL_ARCH: replace-me STEMCELL_BUCKET: replace-me S3_API_ENDPOINT: s3.amazonaws.com ESM_TOKEN: diff --git a/ci/tasks/os-images/build.sh b/ci/tasks/os-images/build.sh index 5b55f27f79..a530ea024c 100755 --- a/ci/tasks/os-images/build.sh +++ b/ci/tasks/os-images/build.sh @@ -21,6 +21,7 @@ function check_param() { check_param OPERATING_SYSTEM_NAME check_param OPERATING_SYSTEM_VERSION +check_param STEMCELL_ARCH OS_IMAGE_NAME=${OPERATING_SYSTEM_NAME}-${OPERATING_SYSTEM_VERSION} OS_IMAGE=${REPO_PARENT}/os-image/${OS_IMAGE_NAME}.tgz @@ -44,5 +45,5 @@ set -e cd "${REPO_PARENT}/bosh-linux-stemcell-builder" bundle install -bundle exec rake "stemcell:build_os_image[${OPERATING_SYSTEM_NAME},${OPERATING_SYSTEM_VERSION},${OS_IMAGE}]" +bundle exec rake "stemcell:build_os_image[${OPERATING_SYSTEM_NAME},${OPERATING_SYSTEM_VERSION},${OS_IMAGE},${STEMCELL_ARCH}]" SUDO diff --git a/ci/tasks/os-images/build.yml b/ci/tasks/os-images/build.yml index 38de5860de..61ae469cd3 100644 --- a/ci/tasks/os-images/build.yml +++ b/ci/tasks/os-images/build.yml @@ -17,6 +17,7 @@ run: params: OPERATING_SYSTEM_NAME: replace-me OPERATING_SYSTEM_VERSION: replace-me + STEMCELL_ARCH: replace-me ESM_TOKEN: UBUNTU_ADVANTAGE_TOKEN: UBUNTU_DEBOOTSTRAP_MIRROR: diff --git a/stemcell_builder/lib/helpers.sh b/stemcell_builder/lib/helpers.sh index 2ca4bbdaaa..402cfdf7ac 100644 --- a/stemcell_builder/lib/helpers.sh +++ b/stemcell_builder/lib/helpers.sh @@ -94,3 +94,34 @@ function is_x86_64() { fi } +# Prints the Debian architecture (e.g. amd64, arm64) of the stemcell being built. +# Prefers the architecture of the bootstrapped root filesystem (set by +# debootstrap), which is available to every stage regardless of how build +# settings are propagated. Falls back to the stemcell_arch build setting, then amd64. +# +# Usage: stemcell_target_arch [rootfs_path] +# rootfs_path defaults to $chroot; image stages that mount the rootfs +# elsewhere (e.g. $image_mount_point) should pass their path explicitly. +function stemcell_target_arch() { + local rootfs="${1:-${chroot:-}}" + local arch="" + if [ -n "$rootfs" ] && [ -x "$rootfs/usr/bin/dpkg" ]; then + arch="$(run_in_chroot "$rootfs" "dpkg --print-architecture" 2>/dev/null | tr -d '[:space:]')" + fi + if [ -z "$arch" ]; then + arch="${stemcell_arch:-amd64}" + fi + echo "$arch" +} + + +# GNU triplet prefix used for multiarch library paths (e.g. x86_64-linux-gnu) +function stemcell_gnu_arch() { + local arch + arch="$(stemcell_target_arch "$@")" + case "$arch" in + amd64) echo "x86_64" ;; + arm64) echo "aarch64" ;; + *) echo "Unsupported stemcell architecture: $arch" >&2; return 1 ;; + esac +} diff --git a/stemcell_builder/stages/base_apt/apply.sh b/stemcell_builder/stages/base_apt/apply.sh index 276a84b67e..29b84d111c 100755 --- a/stemcell_builder/stages/base_apt/apply.sh +++ b/stemcell_builder/stages/base_apt/apply.sh @@ -8,6 +8,16 @@ source $base_dir/lib/prelude_apply.bash mount --bind /sys "$chroot/sys" add_on_exit "umount $chroot/sys" +# Ubuntu serves non-amd64 architectures (e.g. arm64) from the ports mirror +# (ports.ubuntu.com/ubuntu-ports) rather than archive/security.ubuntu.com. +if [ "$(stemcell_target_arch)" == "arm64" ]; then + apt_archive_mirror="http://ports.ubuntu.com/ubuntu-ports" + apt_security_mirror="http://ports.ubuntu.com/ubuntu-ports" +else + apt_archive_mirror="http://archive.ubuntu.com/ubuntu" + apt_security_mirror="http://security.ubuntu.com/ubuntu" +fi + # check if current git branch is a tag and use snapshot date from the last commit message in that tag if [ -n "${BUILD_TIME:-}" ]; then cat > "$chroot/etc/apt/sources.list" < "$chroot/etc/apt/sources.list" <.url/.sha256sum assets point at linux-amd64 builds. Other +# architectures (e.g. arm64) read .linux-.url/.sha256sum. +# shellcheck disable=SC2154 +cli_arch="${stemcell_arch:-amd64}" +if [ "${cli_arch}" == "amd64" ]; then + cli_asset_suffix="" +else + cli_asset_suffix=".linux-${cli_arch}" +fi + for cli_binary in "${blobstore_clis[@]}"; do + if [ ! -f "${assets_dir}/${cli_binary}${cli_asset_suffix}.url" ]; then + echo "No linux-${cli_arch} build of ${cli_binary} is configured: expected ${cli_binary}${cli_asset_suffix}.url and .sha256sum in ${assets_dir}" >&2 + exit 1 + fi # shellcheck disable=SC2154 - cli_url=$(cat "${assets_dir}/${cli_binary}.url") - cli_sha256sum=$(cat "${assets_dir}/${cli_binary}.sha256sum") + cli_url=$(cat "${assets_dir}/${cli_binary}${cli_asset_suffix}.url") + cli_sha256sum=$(cat "${assets_dir}/${cli_binary}${cli_asset_suffix}.sha256sum") curl_five_times "${downloaded_cli_dir}/${cli_binary}" "${cli_url}" echo "${cli_sha256sum} ${downloaded_cli_dir}/${cli_binary}" | sha256sum -c - diff --git a/stemcell_builder/stages/bosh_go_agent/apply.sh b/stemcell_builder/stages/bosh_go_agent/apply.sh index ad7938f02a..e5bb3501d7 100755 --- a/stemcell_builder/stages/bosh_go_agent/apply.sh +++ b/stemcell_builder/stages/bosh_go_agent/apply.sh @@ -9,12 +9,18 @@ source $base_dir/lib/prelude_bosh.bash cp -a $assets_dir/alerts.monitrc $chroot/var/vcap/monit/alerts.monitrc cd $assets_dir -wget -O /usr/bin/meta4 https://github.com/dpb587/metalink/releases/download/v0.2.0/meta4-0.2.0-linux-amd64 \ - && echo "81a592eaf647358563f296aced845ac60d9061a45b30b852d1c3f3674720fe19 /usr/bin/meta4" | shasum -a 256 -c \ - && chmod +x /usr/bin/meta4 - +# meta4 is provided by the os-image-stemcell-builder image +meta4_bin="$(command -v meta4 || true)" +if [ -z "${meta4_bin}" ]; then + echo "meta4 not found on the build host; the os-image-stemcell-builder image provides it" >&2 + exit 1 +fi + +# Install the agent built for the stemcell's architecture (linux-amd64 or +# linux-arm64); the agent metalink lists one file per architecture. +agent_arch="$(stemcell_target_arch)" bosh_agent_version=$(cat ${assets_dir}/bosh-agent-version) -/usr/bin/meta4 file-download --metalink=${assets_dir}/metalink.meta4 --file=bosh-agent-${bosh_agent_version}-linux-amd64 bosh-agent +${meta4_bin} file-download --metalink=${assets_dir}/metalink.meta4 --file=bosh-agent-${bosh_agent_version}-linux-${agent_arch} bosh-agent mv bosh-agent $chroot/var/vcap/bosh/bin/ ln --force $chroot/var/vcap/bosh/bin/bosh-agent $chroot/var/vcap/bosh/etc/bosh-enable-monit-access diff --git a/stemcell_builder/stages/image_install_grub/apply.sh b/stemcell_builder/stages/image_install_grub/apply.sh index ce64080679..aec7869286 100755 --- a/stemcell_builder/stages/image_install_grub/apply.sh +++ b/stemcell_builder/stages/image_install_grub/apply.sh @@ -76,8 +76,13 @@ echo "(hd0) ${device}" > ${image_mount_point}/boot/grub/device.map echo "(hd0) ${device}" > ${image_mount_point}/device.map # fallback for non-UEFI systems # install bootsector into disk image file -run_in_chroot ${image_mount_point} "grub-install --target=x86_64-efi --efi-directory=/boot/efi --boot-directory=/boot/efi/EFI --removable -v --no-floppy ${device}" -run_in_chroot ${image_mount_point} "grub-install -v --target=i386-pc --grub-mkdevicemap=/device.map --no-floppy ${device}" # fallback for non-UEFI systems +if [ "$(stemcell_target_arch ${image_mount_point})" == "arm64" ]; then + # ARM64 is UEFI-only; there is no i386-pc/BIOS fallback target. + run_in_chroot ${image_mount_point} "grub-install --target=arm64-efi --efi-directory=/boot/efi --boot-directory=/boot/efi/EFI --removable -v --no-floppy ${device}" +else + run_in_chroot ${image_mount_point} "grub-install --target=x86_64-efi --efi-directory=/boot/efi --boot-directory=/boot/efi/EFI --removable -v --no-floppy ${device}" + run_in_chroot ${image_mount_point} "grub-install -v --target=i386-pc --grub-mkdevicemap=/device.map --no-floppy ${device}" # fallback for non-UEFI systems +fi mkdir -p ${image_mount_point}/boot/efi/boot/grub cp ${image_mount_point}/boot/efi/EFI/BOOT/grub.cfg ${image_mount_point}/boot/efi/boot/grub/grub.cfg diff --git a/stemcell_builder/stages/password_policies/apply.sh b/stemcell_builder/stages/password_policies/apply.sh index 86e78dde3d..d2f4c426e0 100755 --- a/stemcell_builder/stages/password_policies/apply.sh +++ b/stemcell_builder/stages/password_policies/apply.sh @@ -34,12 +34,14 @@ strip_trailing_whitespace_from $chroot/etc/pam.d/common-password patch -p1 $chroot/etc/pam.d/common-password < $assets_dir/ubuntu/common-password.patch # libpam-lastlog2 installs pam_lastlog2.so only to the multiarch path -# (/usr/lib/x86_64-linux-gnu/security/) but PAM's securedir is /usr/lib/security/. -# Bridge the gap so PAM can load the module referenced above. -if [ -f "$chroot/usr/lib/x86_64-linux-gnu/security/pam_lastlog2.so" ] && \ +# (/usr/lib//security/) but PAM's securedir is /usr/lib/security/. +# Bridge the gap so PAM can load the module referenced above. The multiarch +# triplet depends on the target architecture. +multiarch_triplet="$(stemcell_gnu_arch)-linux-gnu" +if [ -f "$chroot/usr/lib/${multiarch_triplet}/security/pam_lastlog2.so" ] && \ [ ! -e "$chroot/usr/lib/security/pam_lastlog2.so" ]; then mkdir -p "$chroot/usr/lib/security" - ln -sf /usr/lib/x86_64-linux-gnu/security/pam_lastlog2.so \ + ln -sf "/usr/lib/${multiarch_triplet}/security/pam_lastlog2.so" \ "$chroot/usr/lib/security/pam_lastlog2.so" fi diff --git a/stemcell_builder/stages/static_libraries_config/apply.sh b/stemcell_builder/stages/static_libraries_config/apply.sh index 0d3dd4ec75..1fa2fd2e77 100755 --- a/stemcell_builder/stages/static_libraries_config/apply.sh +++ b/stemcell_builder/stages/static_libraries_config/apply.sh @@ -7,7 +7,17 @@ source $base_dir/lib/prelude_apply.bash source $base_dir/lib/prelude_bosh.bash source $base_dir/etc/settings.bash -cp -p "${assets_dir}/static_libraries_list.txt" $chroot/var/vcap/bosh/etc/static_libraries_list +# amd64 keeps the original list file; other architectures use a suffixed list +# because the library paths contain the multiarch triplet. +list_file="${assets_dir}/static_libraries_list.txt" +if [ "$(stemcell_target_arch)" != "amd64" ]; then + list_file="${assets_dir}/static_libraries_list_$(stemcell_target_arch).txt" +fi +if [ ! -f "${list_file}" ]; then + echo "No static libraries list for architecture $(stemcell_target_arch): ${list_file}" >&2 + exit 1 +fi +cp -p "${list_file}" $chroot/var/vcap/bosh/etc/static_libraries_list kernel_suffix="-generic" major_kernel_version="6.8" diff --git a/stemcell_builder/stages/static_libraries_config/assets/static_libraries_list_arm64.txt b/stemcell_builder/stages/static_libraries_config/assets/static_libraries_list_arm64.txt new file mode 100644 index 0000000000..73d0fb94d2 --- /dev/null +++ b/stemcell_builder/stages/static_libraries_config/assets/static_libraries_list_arm64.txt @@ -0,0 +1,79 @@ +/usr/lib/gcc/aarch64-linux-gnu/13/libasan.a +/usr/lib/gcc/aarch64-linux-gnu/13/libatomic.a +/usr/lib/gcc/aarch64-linux-gnu/13/libbacktrace.a +/usr/lib/gcc/aarch64-linux-gnu/13/libstdc++_libbacktrace.a +/usr/lib/gcc/aarch64-linux-gnu/13/libgcc.a +/usr/lib/gcc/aarch64-linux-gnu/13/libgcc_eh.a +/usr/lib/gcc/aarch64-linux-gnu/13/libgcov.a +/usr/lib/gcc/aarch64-linux-gnu/13/libgomp.a +/usr/lib/gcc/aarch64-linux-gnu/13/libhwasan.a +/usr/lib/gcc/aarch64-linux-gnu/13/libitm.a +/usr/lib/gcc/aarch64-linux-gnu/13/liblsan.a +/usr/lib/gcc/aarch64-linux-gnu/13/libobjc.a +/usr/lib/gcc/aarch64-linux-gnu/13/libobjc_gc.a +/usr/lib/gcc/aarch64-linux-gnu/13/libquadmath.a +/usr/lib/gcc/aarch64-linux-gnu/13/libssp_nonshared.a +/usr/lib/gcc/aarch64-linux-gnu/13/libstdc++.a +/usr/lib/gcc/aarch64-linux-gnu/13/libstdc++exp.a +/usr/lib/gcc/aarch64-linux-gnu/13/libstdc++fs.a +/usr/lib/gcc/aarch64-linux-gnu/13/libsupc++.a +/usr/lib/gcc/aarch64-linux-gnu/13/libtsan.a +/usr/lib/gcc/aarch64-linux-gnu/13/libubsan.a +/usr/lib/libsupp.a +/usr/lib/aarch64-linux-gnu/gprofng/libgp-collectorAPI.a +/usr/lib/aarch64-linux-gnu/libBrokenLocale.a +/usr/lib/aarch64-linux-gnu/libanl.a +/usr/lib/aarch64-linux-gnu/libbz2.a +/usr/lib/aarch64-linux-gnu/libc.a +/usr/lib/aarch64-linux-gnu/libc_nonshared.a +/usr/lib/aarch64-linux-gnu/libcap.a +/usr/lib/aarch64-linux-gnu/libcrypt.a +/usr/lib/aarch64-linux-gnu/libcrypto.a +/usr/lib/aarch64-linux-gnu/libcurl.a +/usr/lib/aarch64-linux-gnu/libcurses.a +/usr/lib/aarch64-linux-gnu/libdl.a +/usr/lib/aarch64-linux-gnu/libform.a +/usr/lib/aarch64-linux-gnu/libformw.a +/usr/lib/aarch64-linux-gnu/libg.a +/usr/lib/aarch64-linux-gnu/libgcrypt.a +/usr/lib/aarch64-linux-gnu/libgpg-error.a +/usr/lib/aarch64-linux-gnu/libhistory.a +/usr/lib/aarch64-linux-gnu/libicudata.a +/usr/lib/aarch64-linux-gnu/libicui18n.a +/usr/lib/aarch64-linux-gnu/libicuio.a +/usr/lib/aarch64-linux-gnu/libicutest.a +/usr/lib/aarch64-linux-gnu/libicutu.a +/usr/lib/aarch64-linux-gnu/libicuuc.a +/usr/lib/aarch64-linux-gnu/libm-2.35.a +/usr/lib/aarch64-linux-gnu/libm-2.38.a +/usr/lib/aarch64-linux-gnu/libm-2.39.a +/usr/lib/aarch64-linux-gnu/libm.a +/usr/lib/aarch64-linux-gnu/libmcheck.a +/usr/lib/aarch64-linux-gnu/libmenu.a +/usr/lib/aarch64-linux-gnu/libmenuw.a +/usr/lib/aarch64-linux-gnu/libmvec.a +/usr/lib/aarch64-linux-gnu/libncurses++.a +/usr/lib/aarch64-linux-gnu/libncurses++w.a +/usr/lib/aarch64-linux-gnu/libncurses.a +/usr/lib/aarch64-linux-gnu/libncursesw.a +/usr/lib/aarch64-linux-gnu/libnsl.a +/usr/lib/aarch64-linux-gnu/libpanel.a +/usr/lib/aarch64-linux-gnu/libpanelw.a +/usr/lib/aarch64-linux-gnu/libpsx.a +/usr/lib/aarch64-linux-gnu/libpthread.a +/usr/lib/aarch64-linux-gnu/libpthread_nonshared.a +/usr/lib/aarch64-linux-gnu/libreadline.a +/usr/lib/aarch64-linux-gnu/libresolv.a +/usr/lib/aarch64-linux-gnu/librt.a +/usr/lib/aarch64-linux-gnu/libssl.a +/usr/lib/aarch64-linux-gnu/libtermcap.a +/usr/lib/aarch64-linux-gnu/libtic.a +/usr/lib/aarch64-linux-gnu/libtinfo.a +/usr/lib/aarch64-linux-gnu/libtirpc.a +/usr/lib/aarch64-linux-gnu/libutil.a +/usr/lib/aarch64-linux-gnu/libuuid.a +/usr/lib/aarch64-linux-gnu/libxml2.a +/usr/lib/aarch64-linux-gnu/libz.a +/usr/src/linux-headers-__KERNEL_VERSION__/tools/bpf/resolve_btfids/libbpf/libbpf.a +/usr/src/linux-headers-__KERNEL_VERSION__/tools/bpf/resolve_btfids/libsubcmd/libsubcmd.a +/usr/src/linux-headers-__KERNEL_VERSION__/tools/objtool/libsubcmd/libsubcmd.a diff --git a/stemcell_builder/stages/system_grub/apply.sh b/stemcell_builder/stages/system_grub/apply.sh index 60798c3b0c..82f2b2748f 100755 --- a/stemcell_builder/stages/system_grub/apply.sh +++ b/stemcell_builder/stages/system_grub/apply.sh @@ -5,7 +5,13 @@ set -e base_dir=$(readlink -nf $(dirname $0)/../..) source $base_dir/lib/prelude_apply.bash -pkg_mgr install grub2 grub-efi-amd64-bin grub-efi-amd64-signed shim-signed +# Install the GRUB EFI packages matching the target architecture. +if [ "$(stemcell_target_arch)" == "arm64" ]; then + # ARM64 has no "grub2" metapackage; grub-efi-arm64 is the equivalent. + pkg_mgr install grub-efi-arm64 grub-efi-arm64-bin grub-efi-arm64-signed shim-signed +else + pkg_mgr install grub2 grub-efi-amd64-bin grub-efi-amd64-signed shim-signed +fi # When a kernel is installed, update-grub is run per /etc/kernel-img.conf. # It complains when /boot/grub/menu.lst doesn't exist, so create it.