package Proxmox::Install::Config; use strict; use warnings; use Carp; use JSON qw(from_json to_json); use Proxmox::Log; use Proxmox::Install::ISOEnv; use Proxmox::Sys::Net; sub parse_kernel_cmdline { my ($cfg) = @_; my $cmdline = Proxmox::Install::RunEnv::get('kernel_cmdline'); if ($cmdline =~ s/\b(ext4|xfs)\s?//i) { $cfg->{filesys} = $1; } if ($cmdline =~ s/\bhdsize=(\d+(\.\d+)?)\s?//i) { $cfg->{hdsize} = $1; } if ($cmdline =~ s/\bswapsize=(\d+(\.\d+)?)\s?//i) { $cfg->{swapsize} = $1; } if ($cmdline =~ s/\bmaxroot=(\d+(\.\d+)?)\s?//i) { $cfg->{maxroot} = $1; } if ($cmdline =~ s/\bminfree=(\d+(\.\d+)?)\s?//i) { $cfg->{minfree} = $1; } my $iso_env = Proxmox::Install::ISOEnv::get(); if ($iso_env->{product} eq 'pve') { if ($cmdline =~ s/\bmaxvz=(\d+(\.\d+)?)\s?//i) { $cfg->{maxvz} = $1; } } my @filtered = grep { $_ !~ m/^(BOOT_IMAGE|root|ramdisk_size|splash|vga)=\S+$/ && $_ !~ m/^(ro|rw|quiet)$/ && $_ !~ m/^(prox(debug|tui|auto)|proxmox-\S+)$/ } split(/\s+/, $cmdline); $cfg->{target_cmdline} = join(' ', @filtered); return $cfg; } my sub init_cfg { my $iso_env = Proxmox::Install::ISOEnv::get(); my $country = Proxmox::Install::RunEnv::get('country'); if (defined($country) && !defined($iso_env->{locales}->{country}->{$country})) { log_warn("ignoring detected country '$country', invalid or unknown\n"); $country = undef; } my $initial = { # installer behavior related autoreboot => 1, # disk and filesystem related filesys => 'ext4', hdsize => undef, swapsize => undef, maxroot => undef, minfree => undef, maxvz => undef, zfs_opts => { ashift => 12, compress => 'on', checksum => 'on', copies => 1, arc_max => Proxmox::Install::RunEnv::default_zfs_arc_max(), # in MiB }, btrfs_opts => { compress => 'off', }, # TODO: single disk selection config target_hd => undef, disk_selection => {}, existing_storage_auto_rename => 0, # locale country => $country, timezone => 'Europe/Vienna', keymap => 'en-us', # root credentials & details root_password => undef, mailto => 'mail@example.invalid', root_ssh_keys => [], # network related mngmt_nic => undef, # FIXME: fix call sites and remove below, it's just an ugly relict of GTK GUI and time # pressure on creating the single source of truth for installation config mngmt_nic_id => undef, hostname => undef, domain => undef, cidr => undef, gateway => undef, dns => undef, target_cmdline => undef, }; $initial = parse_kernel_cmdline($initial); return $initial; } # merge a $new hash into the current config, with $new taking precedence sub merge { my ($new) = @_; my $current = get(); for my $k (sort keys $new->%*) { # first check all croak "unknown key '$k'" if !exists($current->{$k}) } $current->{$_} = $new->{$_} for sort keys $new->%*; # then merge return $current; } my $_cfg = undef; # NOTE: global singleton sub get { my ($k) = @_; $_cfg = init_cfg() if !defined($_cfg); return defined($k) ? $_cfg->{$k} : $_cfg; } sub set_key { my ($k, $v) = @_; my $cfg = get(); croak "unknown key '$k'" if !exists($cfg->{$k}); $cfg->{$k} = $v; } sub set_autoreboot { set_key('autoreboot', $_[0]); } sub get_autoreboot { return get('autoreboot'); } sub set_filesys { set_key('filesys', $_[0]); } sub get_filesys { return get('filesys'); } sub set_hdsize { set_key('hdsize', $_[0]); } sub get_hdsize { return get('hdsize'); } sub set_swapsize { set_key('swapsize', $_[0]); } sub get_swapsize { return get('swapsize'); } sub set_maxroot { set_key('maxroot', $_[0]); } sub get_maxroot { return get('maxroot'); } sub set_minfree { set_key('minfree', $_[0]); } sub get_minfree { return get('minfree'); } sub set_maxvz { set_key('maxvz', $_[0]); } sub get_maxvz { return get('maxvz'); } sub set_zfs_opt { my ($k, $v) = @_; my $zfs_opts = get('zfs_opts'); croak "unknown zfs opts key '$k'" if !exists($zfs_opts->{$k}); $zfs_opts->{$k} = $v; } sub get_zfs_opt { my ($k) = @_; my $zfs_opts = get('zfs_opts'); return defined($k) ? $zfs_opts->{$k} : $zfs_opts; } sub set_btrfs_opt { my ($k, $v) = @_; my $opts = get('btrfs_opts'); croak "unknown btrfs opts key '$k'" if !exists($opts->{$k}); $opts->{$k} = $v; } sub get_btrfs_opt { my ($k) = @_; my $opts = get('btrfs_opts'); return defined($k) ? $opts->{$k} : $opts; } sub set_target_hd { set_key('target_hd', $_[0]); } sub get_target_hd { return get('target_hd'); } sub set_disk_selection { my ($id, $v) = @_; my $disk_selection = get('disk_selection'); $disk_selection->{$id} = $v; } sub get_disk_selection { my ($id) = @_; my $disk_selection = get('disk_selection'); return defined($id) ? $disk_selection->{$id} : $disk_selection; } sub set_country { set_key('country', $_[0]); } sub get_country { return get('country'); } sub set_timezone { set_key('timezone', $_[0]); } sub get_timezone { return get('timezone'); } sub set_keymap { set_key('keymap', $_[0]); } sub get_keymap { return get('keymap'); } sub set_root_password { my ($key) = @_; croak "unknown root password option '$key'" if $key ne 'plain' && $key ne 'hashed'; set_key('root_password', { $_[0] => $_[1] }); } sub get_root_password { my ($key) = @_; croak "unknown root password option '$key'" if $key ne 'plain' && $key ne 'hashed'; my $password = get('root_password'); return defined($password->{$key}) ? $password->{$key} : undef; } sub set_mailto { set_key('mailto', $_[0]); } sub get_mailto { return get('mailto'); } sub set_root_ssh_keys { set_key('root_ssh_keys', $_[0]); } sub get_root_ssh_keys { return get('root_ssh_keys'); } sub set_mngmt_nic { set_key('mngmt_nic', $_[0]); } sub get_mngmt_nic { return get('mngmt_nic'); } sub set_mngmt_nic_id { set_key('mngmt_nic_id', $_[0]); } sub get_mngmt_nic_id { return get('mngmt_nic_id'); } sub set_hostname { set_key('hostname', $_[0]); } sub get_hostname { return get('hostname'); } sub set_domain { set_key('domain', $_[0]); } sub get_domain { return get('domain'); } sub get_fqdn { # virtual config my ($hostname, $domain) = (get('hostname'), get('domain')); return defined($hostname) && defined($domain) ? "${hostname}.${domain}" : undef; } sub set_cidr { set_key('cidr', $_[0]); } sub get_cidr { return get('cidr'); } sub get_ip_addr { #'virtual config my $cidr = get('cidr') // return; my ($ip, $mask) = split('/', $cidr); return $ip; } sub get_ip_version { # virtual config my $ip = get_ip_addr() // return; return Proxmox::Sys::Net::parse_ip_address($ip); } sub set_gateway { set_key('gateway', $_[0]); } sub get_gateway { return get('gateway'); } sub set_dns { set_key('dns', $_[0]); } sub get_dns { return get('dns'); } sub set_target_cmdline { set_key('target_cmdline', $_[0]); } sub get_target_cmdline { return get('target_cmdline'); } sub set_existing_storage_auto_rename { set_key('existing_storage_auto_rename', $_[0]); } sub get_existing_storage_auto_rename { return get('existing_storage_auto_rename'); } 1;