From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 5AA97BB0B for ; Mon, 3 Jul 2023 12:00:42 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 44D8E1B5C2 for ; Mon, 3 Jul 2023 12:00:12 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Mon, 3 Jul 2023 12:00:10 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 628AB438F4 for ; Mon, 3 Jul 2023 12:00:10 +0200 (CEST) Date: Mon, 3 Jul 2023 12:00:08 +0200 From: Christoph Heiss To: Proxmox VE development discussion Message-ID: References: <20230228105911.217085-1-c.heiss@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230228105911.217085-1-c.heiss@proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL -0.073 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: Re: [pve-devel] [PATCH container] setup: Fix architecture detection for NixOS containers X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Jul 2023 10:00:42 -0000 Ping? Still applies & works fine on current master. On Tue, Feb 28, 2023 at 11:59:11AM +0100, Christoph Heiss wrote: > NixOS is special and deviates in many places from a "standard" Linux > system. In this case, /bin/sh does not exist on the actual filesystem, > at least not before the initial activation - which creates a symlink at > /bin/sh. > > Thus try a bit harder to detect the architecture for NixOS containers by > inspecting the init script, which contains a shebang-line with the full > path to the system shell. > > This moves the architecture detection code to the end of the container > creation lifecycle, so that it can be implemented as a plugin > subroutine. Therefore this mechanism is now generic enough that it can > be adapted to other container OS's in the future if needed. AFAICS > `arch` is only used when writing the actual LXC config, so determining > it later during creation does not change anything. > > Tested by creating a NixOS and a Debian container (to verify that > nothing regressed) and checking if the warning "Architecure detection > failed: [..]" no longer appears for the NixOS CT and if `arch` in the > CT config is correct. Also tested restoring both containers from a local > and a PBS backup, as well as migrating both container. > > Signed-off-by: Christoph Heiss > --- > src/PVE/LXC/Create.pm | 76 ------------------------------------- > src/PVE/LXC/Setup.pm | 64 +++++++++++++++++++++++++++++++ > src/PVE/LXC/Setup/Base.pm | 8 ++++ > src/PVE/LXC/Setup/NixOS.pm | 17 +++++++++ > src/PVE/LXC/Setup/Plugin.pm | 5 +++ > 5 files changed, 94 insertions(+), 76 deletions(-) > > diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm > index b2e3d00..adf917c 100644 > --- a/src/PVE/LXC/Create.pm > +++ b/src/PVE/LXC/Create.pm > @@ -16,72 +16,6 @@ use PVE::VZDump::ConvertOVZ; > use PVE::Tools; > use POSIX; > > -sub detect_architecture { > - my ($rootdir) = @_; > - > - # see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format > - > - my $supported_elf_machine = { > - 0x03 => 'i386', > - 0x3e => 'amd64', > - 0x28 => 'armhf', > - 0xb7 => 'arm64', > - 0xf3 => 'riscv', > - }; > - > - my $elf_fn = '/bin/sh'; # '/bin/sh' is POSIX mandatory > - my $detect_arch = sub { > - # chroot avoids a problem where we check the binary of the host system > - # if $elf_fn is an absolut symlink (e.g. $rootdir/bin/sh -> /bin/bash) > - chroot($rootdir) or die "chroot '$rootdir' failed: $!\n"; > - chdir('/') or die "failed to change to root directory\n"; > - > - open(my $fh, "<", $elf_fn) or die "open '$elf_fn' failed: $!\n"; > - binmode($fh); > - > - my $length = read($fh, my $data, 20) or die "read failed: $!\n"; > - > - # 4 bytes ELF magic number and 1 byte ELF class, padding, machine > - my ($magic, $class, undef, $machine) = unpack("A4CA12n", $data); > - > - die "'$elf_fn' does not resolve to an ELF!\n" > - if (!defined($class) || !defined($magic) || $magic ne "\177ELF"); > - > - my $arch = $supported_elf_machine->{$machine}; > - die "'$elf_fn' has unknown ELF machine '$machine'!\n" > - if !defined($arch); > - > - if ($arch eq 'riscv') { > - if ($class eq 1) { > - $arch = 'riscv32'; > - } elsif ($class eq 2) { > - $arch = 'riscv64'; > - } else { > - die "'$elf_fn' has invalid class '$class'!\n"; > - } > - } > - > - return $arch; > - }; > - > - my $arch = eval { PVE::Tools::run_fork_with_timeout(10, $detect_arch); }; > - my $err = $@; > - > - if (!defined($arch) && !defined($err)) { > - # on timeout > - die "Architecture detection failed: timeout\n"; > - } elsif ($err) { > - # any other error > - $arch = 'amd64'; > - print "Architecture detection failed: $err\nFalling back to $arch.\n" . > - "Use `pct set VMID --arch ARCH` to change.\n"; > - } else { > - print "Detected container architecture: $arch\n"; > - } > - > - return $arch; > -} > - > sub restore_archive { > my ($storage_cfg, $archive, $rootdir, $conf, $no_unpack_error, $bwlimit) = @_; > > @@ -118,11 +52,6 @@ sub restore_proxmox_backup_archive { > > PVE::Storage::PBSPlugin::run_raw_client_cmd( > $scfg, $storeid, $cmd, $param, userns_cmd => $userns_cmd); > - > - # if arch is set, we do not try to autodetect it > - return if defined($conf->{arch}); > - > - $conf->{arch} = detect_architecture($rootdir); > } > > sub restore_tar_archive { > @@ -183,11 +112,6 @@ sub restore_tar_archive { > my $err = $@; > close($archive_fh) if defined $archive_fh; > die $err if $err && !$no_unpack_error; > - > - # if arch is set, we do not try to autodetect it > - return if defined($conf->{arch}); > - > - $conf->{arch} = detect_architecture($rootdir); > } > > sub recover_config { > diff --git a/src/PVE/LXC/Setup.pm b/src/PVE/LXC/Setup.pm > index 891231f..4346c5e 100644 > --- a/src/PVE/LXC/Setup.pm > +++ b/src/PVE/LXC/Setup.pm > @@ -131,6 +131,20 @@ sub new { > $plugin->{rootgid} = $rootgid; > } > > + # if arch is unset, we try to autodetect it > + if (!defined($conf->{arch})) { > + my $arch = eval { $self->protected_call(sub { $plugin->detect_architecture() }) }; > + > + if (!defined($arch)) { > + $arch = 'amd64'; > + print "Falling back to $arch.\nUse `pct set VMID --arch ARCH` to change.\n"; > + } else { > + print "Detected container architecture: $arch\n"; > + } > + > + $conf->{arch} = $arch; > + } > + > return $self; > } > > @@ -346,4 +360,54 @@ sub get_ct_init_path { > return $init; > } > > +sub detect_architecture { > + my ($elf_fn) = @_; > + > + # see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format > + > + my $supported_elf_machine = { > + 0x03 => 'i386', > + 0x3e => 'amd64', > + 0x28 => 'armhf', > + 0xb7 => 'arm64', > + 0xf3 => 'riscv', > + }; > + > + my $detect_arch = sub { > + open(my $fh, "<", $elf_fn) or die "open '$elf_fn' failed: $!\n"; > + binmode($fh); > + > + my $length = read($fh, my $data, 20) or die "read failed: $!\n"; > + > + # 4 bytes ELF magic number and 1 byte ELF class, padding, machine > + my ($magic, $class, undef, $machine) = unpack("A4CA12n", $data); > + > + die "'$elf_fn' does not resolve to an ELF!\n" > + if (!defined($class) || !defined($magic) || $magic ne "\177ELF"); > + > + my $arch = $supported_elf_machine->{$machine}; > + die "'$elf_fn' has unknown ELF machine '$machine'!\n" > + if !defined($arch); > + > + if ($arch eq 'riscv') { > + if ($class eq 1) { > + $arch = 'riscv32'; > + } elsif ($class eq 2) { > + $arch = 'riscv64'; > + } else { > + die "'$elf_fn' has invalid class '$class'!\n"; > + } > + } > + > + return $arch; > + }; > + > + my $arch = eval { PVE::Tools::run_fork_with_timeout(10, $detect_arch); }; > + my $err = $@ // "timeout\n"; > + > + die "Architecture detection failed: $err" if !defined($arch); > + > + return $arch; > +} > + > 1; > diff --git a/src/PVE/LXC/Setup/Base.pm b/src/PVE/LXC/Setup/Base.pm > index 547abdb..93c1d34 100644 > --- a/src/PVE/LXC/Setup/Base.pm > +++ b/src/PVE/LXC/Setup/Base.pm > @@ -18,6 +18,7 @@ use PVE::INotify; > use PVE::Tools; > use PVE::Network; > > +use PVE::LXC::Setup; > use PVE::LXC::Setup::Plugin; > use base qw(PVE::LXC::Setup::Plugin); > > @@ -574,6 +575,13 @@ sub ssh_host_key_types_to_generate { > }; > } > > +sub detect_architecture { > + my ($self) = @_; > + > + # '/bin/sh' is POSIX mandatory > + return PVE::LXC::Setup::detect_architecture('/bin/sh'); > +} > + > sub pre_start_hook { > my ($self, $conf) = @_; > > diff --git a/src/PVE/LXC/Setup/NixOS.pm b/src/PVE/LXC/Setup/NixOS.pm > index 845d2d5..4f7b93e 100644 > --- a/src/PVE/LXC/Setup/NixOS.pm > +++ b/src/PVE/LXC/Setup/NixOS.pm > @@ -5,6 +5,7 @@ use warnings; > > use File::Path 'make_path'; > > +use PVE::LXC::Setup; > use PVE::LXC::Setup::Base; > > use base qw(PVE::LXC::Setup::Base); > @@ -37,4 +38,20 @@ sub setup_init { > my ($self, $conf) = @_; > } > > +sub detect_architecture { > + my ($self) = @_; > + > + # /bin/sh only exists as a symlink after the initial system activaction on first boot. > + # To detect the actual architecture of the system, examine the shebang line of the /sbin/init > + # script, which has the full path to the system shell. > + my $init_path = '/sbin/init'; > + open(my $fh, '<', $init_path) or die "open '$init_path' failed: $!\n"; > + > + if (<$fh> =~ /^#! ?(\S*)/) { > + return PVE::LXC::Setup::detect_architecture($1); > + } > + > + die "Architecture detection failed: could not find a shell\n"; > +} > + > 1; > diff --git a/src/PVE/LXC/Setup/Plugin.pm b/src/PVE/LXC/Setup/Plugin.pm > index 3d968e7..b9d9c2d 100644 > --- a/src/PVE/LXC/Setup/Plugin.pm > +++ b/src/PVE/LXC/Setup/Plugin.pm > @@ -62,6 +62,11 @@ sub ssh_host_key_types_to_generate { > croak "implement me in sub-class\n"; > } > > +sub detect_architecture { > + my ($self) = @_; > + croak "implement me in sub-class\n"; > +} > + > # hooks > > sub pre_start_hook { > -- > 2.39.2 > > > > _______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > >