From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 805C91FF173 for <inbox@lore.proxmox.com>; Mon, 10 Feb 2025 13:07:38 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 17E0DA515; Mon, 10 Feb 2025 13:07:28 +0100 (CET) From: Daniel Herzig <d.herzig@proxmox.com> To: pve-devel@lists.proxmox.com Date: Mon, 10 Feb 2025 13:07:16 +0100 Message-Id: <20250210120722.163622-3-d.herzig@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250210120722.163622-1-d.herzig@proxmox.com> References: <20250210120722.163622-1-d.herzig@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.549 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 KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pve-devel] [PATCH 2/8 container] cloudinit: basic implementation X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Cc: Leo Nunner <l.nunner@proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> From: Leo Nunner <l.nunner@proxmox.com> The code to generate the actual configuration works pretty much the same as with the VM system. We generate an instance ID by hashing the user configuration, causing cloud-init to run every time said configuration changes. Instead of creating a config drive, we write files directly into the volume of the container. We create a folder at '/var/lib/cloud/seed/nocloud-net' and write the files 'user-data', 'vendor-data' and 'meta-data'. Cloud-init looks at the instance ID inside 'meta-data' to decide whether it should run (again) or not. Custom scripts need to be located inside the snippets directory, and overwrite the default generated configuration file. Signed-off-by: Leo Nunner <l.nunner@proxmox.com> --- src/PVE/LXC.pm | 1 + src/PVE/LXC/Cloudinit.pm | 114 ++++++++++++++++++++++++++++++++++++++ src/PVE/LXC/Makefile | 1 + src/lxc-pve-prestart-hook | 5 ++ 4 files changed, 121 insertions(+) create mode 100644 src/PVE/LXC/Cloudinit.pm diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 4d20645..35bb6b5 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -40,6 +40,7 @@ use PVE::Tools qw( use PVE::Syscall qw(:fsmount); use PVE::LXC::CGroup; +use PVE::LXC::Cloudinit; use PVE::LXC::Config; use PVE::LXC::Monitor; use PVE::LXC::Tools; diff --git a/src/PVE/LXC/Cloudinit.pm b/src/PVE/LXC/Cloudinit.pm new file mode 100644 index 0000000..3e8617b --- /dev/null +++ b/src/PVE/LXC/Cloudinit.pm @@ -0,0 +1,114 @@ +package PVE::LXC::Cloudinit; + +use strict; +use warnings; + +use Digest::SHA; +use File::Path; + +use PVE::LXC; + +sub gen_cloudinit_metadata { + my ($user) = @_; + + my $uuid_str = Digest::SHA::sha1_hex($user); + return cloudinit_metadata($uuid_str); +} + +sub cloudinit_metadata { + my ($uuid) = @_; + my $raw = ""; + + $raw .= "instance-id: $uuid\n"; + + return $raw; +} + +sub cloudinit_userdata { + my ($conf) = @_; + + my $content = "#cloud-config\n"; + + my $username = $conf->{ciuser}; + my $password = $conf->{cipassword}; + + $content .= "user: $username\n" if defined($username); + $content .= "password: $password\n" if defined($password); + + if (defined(my $keys = $conf->{sshkeys})) { + $keys = URI::Escape::uri_unescape($keys); + $keys = [map { my $key = $_; chomp $key; $key } split(/\n/, $keys)]; + $keys = [grep { /\S/ } @$keys]; + $content .= "ssh_authorized_keys:\n"; + foreach my $k (@$keys) { + $content .= " - $k\n"; + } + } + $content .= "chpasswd:\n"; + $content .= " expire: False\n"; + + if (!defined($username) || $username ne 'root') { + $content .= "users:\n"; + $content .= " - default\n"; + } + + $content .= "package_upgrade: true\n" if $conf->{ciupgrade}; + + return $content; +} + +sub read_cloudinit_snippets_file { + my ($storage_conf, $volid) = @_; + + my ($full_path, undef, $type) = PVE::Storage::path($storage_conf, $volid); + die "$volid is not in the snippets directory\n" if $type ne 'snippets'; + return PVE::Tools::file_get_contents($full_path, 1 * 1024 * 1024); +} + +sub read_custom_cloudinit_files { + my ($conf) = @_; + + my $cloudinit_conf = $conf->{cicustom}; + my $files = $cloudinit_conf ? PVE::JSONSchema::parse_property_string('pve-pct-cicustom', $cloudinit_conf) : {}; + + my $user_volid = $files->{user}; + my $vendor_volid = $files->{vendor}; + + my $storage_conf = PVE::Storage::config(); + + my $user_data; + if ($user_volid) { + $user_data = read_cloudinit_snippets_file($storage_conf, $user_volid); + } + + my $vendor_data; + if ($vendor_volid) { + $user_data = read_cloudinit_snippets_file($storage_conf, $vendor_volid); + } + + return ($user_data, $vendor_data); +} + +sub create_cloudinit_files { + my ($conf, $setup) = @_; + + my $cloudinit_dir = "/var/lib/cloud/seed/nocloud-net"; + + my ($user_data, $vendor_data) = read_custom_cloudinit_files($conf); + $user_data = cloudinit_userdata($conf) if !defined($user_data); + $vendor_data = '' if !defined($vendor_data); + + my $meta_data = gen_cloudinit_metadata($user_data); + + $setup->protected_call(sub { + my $plugin = $setup->{plugin}; + + $plugin->ct_make_path($cloudinit_dir); + + $plugin->ct_file_set_contents("$cloudinit_dir/user-data", $user_data); + $plugin->ct_file_set_contents("$cloudinit_dir/vendor-data", $vendor_data); + $plugin->ct_file_set_contents("$cloudinit_dir/meta-data", $meta_data); + }); +} + +1; diff --git a/src/PVE/LXC/Makefile b/src/PVE/LXC/Makefile index a190260..5d595ba 100644 --- a/src/PVE/LXC/Makefile +++ b/src/PVE/LXC/Makefile @@ -1,5 +1,6 @@ SOURCES= \ CGroup.pm \ + Cloudinit.pm \ Command.pm \ Config.pm \ Create.pm \ diff --git a/src/lxc-pve-prestart-hook b/src/lxc-pve-prestart-hook index fdaead2..c9f8ff0 100755 --- a/src/lxc-pve-prestart-hook +++ b/src/lxc-pve-prestart-hook @@ -13,6 +13,7 @@ use POSIX; use PVE::CGroup; use PVE::Cluster; use PVE::LXC::Config; +use PVE::LXC::Cloudinit; use PVE::LXC::Setup; use PVE::LXC::Tools; use PVE::LXC; @@ -173,6 +174,10 @@ PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub { my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); $lxc_setup->pre_start_hook(); + if ($conf->{cienable}) { + PVE::LXC::Cloudinit::create_cloudinit_files($conf, $lxc_setup) + } + if (PVE::CGroup::cgroup_mode() == 2) { if (!$lxc_setup->unified_cgroupv2_support()) { log_warn($vmid, "old systemd (< v232) detected, container won't run in a pure cgroupv2" -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel