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)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id B3F87608A0 for ; Sat, 6 Feb 2021 14:02:13 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A443C11408 for ; Sat, 6 Feb 2021 14:01:43 +0100 (CET) Received: from kvmformation1.odiso.net (globalOdiso.M6Lille.odiso.net [89.248.211.242]) by firstgate.proxmox.com (Proxmox) with ESMTP id F2E5E113FE for ; Sat, 6 Feb 2021 14:01:38 +0100 (CET) Received: by kvmformation1.odiso.net (Postfix, from userid 0) id 99E5646FF1; Sat, 6 Feb 2021 14:01:31 +0100 (CET) From: Alexandre Derumier To: pve-devel@lists.proxmox.com Date: Sat, 6 Feb 2021 14:01:29 +0100 Message-Id: <20210206130129.2381426-1-aderumier@odiso.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.192 Adjusted score from AWL reputation of From: address HEADER_FROM_DIFFERENT_DOMAINS 0.25 From and EnvelopeFrom 2nd level mail domains are different 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 KHOP_HELO_FCRDNS 0.4 Relay HELO differs from its IP's reverse DNS NO_DNS_FOR_FROM 0.379 Envelope sender has no MX or A DNS records 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 qemu-server] cloudinit: add opennebula config format 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: Sat, 06 Feb 2021 13:02:13 -0000 This is an alternative format for cloudinit use by opennebula, https://cloudinit.readthedocs.io/en/latest/topics/datasources/opennebula.html but it can be also used by opennebula context scripts https://github.com/OpenNebula/addon-context-linux https://github.com/OpenNebula/addon-context-windows This context scripts are simple udev trigger/bash scripts and allow live configuration changes. Signed-off-by: Alexandre Derumier --- PVE/QemuServer.pm | 2 +- PVE/QemuServer/Cloudinit.pm | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 9c65d76..4d4efd9 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -718,7 +718,7 @@ my $confdesc_cloudinit = { description => 'Specifies the cloud-init configuration format. The default depends on the' .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,' .' and `configdrive2` for windows.', - enum => ['configdrive2', 'nocloud'], + enum => ['configdrive2', 'nocloud', 'opennebula'], }, ciuser => { optional => 1, diff --git a/PVE/QemuServer/Cloudinit.pm b/PVE/QemuServer/Cloudinit.pm index 52a4203..c464bf3 100644 --- a/PVE/QemuServer/Cloudinit.pm +++ b/PVE/QemuServer/Cloudinit.pm @@ -6,6 +6,7 @@ use warnings; use File::Path; use Digest::SHA; use URI::Escape; +use MIME::Base64 qw(encode_base64); use PVE::Tools qw(run_command file_set_contents); use PVE::Storage; @@ -241,6 +242,96 @@ sub generate_configdrive2 { commit_cloudinit_disk($conf, $vmid, $drive, $volname, $storeid, $files, 'config-2'); } +sub generate_opennebula { + my ($conf, $vmid, $drive, $volname, $storeid) = @_; + + my ($hostname, $fqdn) = get_hostname_fqdn($conf, $vmid); + + my $content = ""; + + my $username = $conf->{ciuser} || "root"; + my $password = encode_base64($conf->{cipassword}) if defined($conf->{cipassword}); + + $content .= "USERNAME=$username\n" if defined($username); + $content .= "CRYPTED_PASSWORD_BASE64=$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_PUBLIC_KEY=\""; + + foreach my $k (@$keys) { + $content .= "$k\n"; + } + $content .= "\"\n"; + + } + + my ($searchdomains, $nameservers) = get_dns_conf($conf); + if ($nameservers && @$nameservers) { + $nameservers = join(' ', @$nameservers); + $content .= "DNS=\"$nameservers\"\n"; + } + + $content .= "SET_HOSTNAME=$hostname\n"; + + if ($searchdomains && @$searchdomains) { + $searchdomains = join(' ', @$searchdomains); + $content .= "SEARCH_DOMAIN=\"$searchdomains\"\n"; + } + + my $networkenabled = undef; + my @ifaces = grep { /^net(\d+)$/ } keys %$conf; + foreach my $iface (sort @ifaces) { + (my $id = $iface) =~ s/^net//; + my $net = PVE::QemuServer::parse_net($conf->{$iface}); + next if !$conf->{"ipconfig$id"}; + my $ipconfig = PVE::QemuServer::parse_ipconfig($conf->{"ipconfig$id"}); + my $ethid = "ETH$id"; + + my $mac = lc $net->{hwaddr}; + + if ($ipconfig->{ip}) { + $networkenabled = 1; + + if ($ipconfig->{ip} eq 'dhcp') { + $content .= $ethid."_DHCP=YES\n"; + } else { + my ($addr, $mask) = split_ip4($ipconfig->{ip}); + $content .= $ethid."_IP=$addr\n"; + $content .= $ethid."_MASK=$mask\n"; + $content .= $ethid."_MAC=$mac\n"; + $content .= $ethid."_GATEWAY=$ipconfig->{gw}\n" if $ipconfig->{gw}; + } + $content .= $ethid."_MTU=$net->{mtu}\n" if $net->{mtu}; + } + + if ($ipconfig->{ip6}) { + $networkenabled = 1; + if ($ipconfig->{ip6} eq 'dhcp') { + $content .= $ethid."_DHCP6=YES\n"; + } elsif ($ipconfig->{ip6} eq 'auto') { + $content .= $ethid."_AUTO6=YES\n"; + } else { + my ($addr, $mask) = split('/', $ipconfig->{ip6}); + $content .= $ethid."_IP6=$addr\n"; + $content .= $ethid."_MASK6=$mask\n"; + $content .= $ethid."_MAC6=$mac\n"; + $content .= $ethid."_GATEWAY6=$ipconfig->{gw6}\n" if $ipconfig->{gw6}; + } + $content .= $ethid."_MTU=$net->{mtu}\n" if $net->{mtu}; + } + } + + $content .= "NETWORK=YES\n" if $networkenabled; + + my $files = { + '/context.sh' => $content, + }; + commit_cloudinit_disk($conf, $vmid, $drive, $volname, $storeid, $files, 'CONTEXT'); +} + sub nocloud_network_v2 { my ($conf) = @_; @@ -459,6 +550,7 @@ sub read_cloudinit_snippets_file { my $cloudinit_methods = { configdrive2 => \&generate_configdrive2, nocloud => \&generate_nocloud, + opennebula => \&generate_opennebula, }; sub generate_cloudinitconfig { -- 2.20.1