]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXCSetup/Base.pm
PVE::LXCCreate, use our own class instead of running extenal lxc-create
[pve-container.git] / src / PVE / LXCSetup / Base.pm
index b10712d5a6505daaad4359e54949bfa0a1b53ad0..8eb976ed59c55217577d9b1b3e583f71a08ac576 100644 (file)
@@ -3,8 +3,52 @@ package PVE::LXCSetup::Base;
 use strict;
 use warnings;
 
+use File::stat;
+use Digest::SHA;
+use IO::File;
+use Encode;
+
+use PVE::INotify;
 use PVE::Tools;
 
+sub new {
+    my ($class, $conf, $rootdir) = @_;
+
+    return bless { conf => $conf, rootdir => $rootdir }, $class;
+}
+
+my $lookup_dns_conf = sub {
+    my ($conf) = @_;
+
+    my $nameserver = $conf->{'pve.nameserver'};
+    my $searchdomains = $conf->{'pve.searchdomain'};
+
+    if (!($nameserver && $searchdomains)) {
+
+       if ($conf->{'pve.test_mode'}) {
+           
+           $nameserver = "8.8.8.8 8.8.8.9";
+           $searchdomains = "promxox.com";
+       
+       } else {
+
+           my $host_resolv_conf = PVE::INotify::read_file('resolvconf');
+
+           $searchdomains = $host_resolv_conf->{search};
+
+           my @list = ();
+           foreach my $k ("dns1", "dns2", "dns3") {
+               if (my $ns = $host_resolv_conf->{$k}) {
+                   push @list, $ns;
+               }
+           }
+           $nameserver = join(' ', @list);
+       }
+    }
+
+    return ($searchdomains, $nameserver);
+};
+
 my $update_etc_hosts = sub {
     my ($etc_hosts_data, $hostip, $oldname, $newname, $searchdomains) = @_;
 
@@ -29,7 +73,7 @@ my $update_etc_hosts = sub {
            push @lines, $line;
            next;
        }
-       
+
        my $found = 0;
        foreach my $name (@names) {
            if ($name eq $oldname || $name eq $newname) {
@@ -43,7 +87,7 @@ my $update_etc_hosts = sub {
        if ($found) {
            if (!$done) {
                if (defined($hostip)) {
-                   push @lines, "$ip $extra_names $newname";
+                   push @lines, "$hostip $extra_names $newname";
                } else {
                    push @lines, "127.0.1.1 $newname";
                }
@@ -80,64 +124,154 @@ my $update_etc_hosts = sub {
     return $etc_hosts_data;
 };
 
+sub set_dns {
+    my ($self, $conf) = @_;
+
+    my ($searchdomains, $nameserver) = &$lookup_dns_conf($conf);
+    
+    my $rootdir = $self->{rootdir};
+    
+    my $filename = "$rootdir/etc/resolv.conf";
+
+    my $data = '';
+
+    $data .= "search " . join(' ', PVE::Tools::split_list($searchdomains)) . "\n"
+       if $searchdomains;
+
+    foreach my $ns ( PVE::Tools::split_list($nameserver)) {
+       $data .= "nameserver $ns\n";
+    }
+
+    PVE::Tools::file_set_contents($filename, $data);
+}
+
 sub set_hostname {
-    my ($class, $conf) = @_;
+    my ($self, $conf) = @_;
     
     my $hostname = $conf->{'lxc.utsname'} || 'localhost';
 
     $hostname =~ s/\..*$//;
 
-    my $rootfs = $conf->{'lxc.rootfs'};
+    my $rootdir = $self->{rootdir};
 
-    my $hostname_fn = "$rootfs/etc/hostname";
+    my $hostname_fn = "$rootdir/etc/hostname";
     
     my $oldname = PVE::Tools::file_read_firstline($hostname_fn) || 'localhost';
 
-    my $hosts_fn = "$rootfs/etc/hosts";
+    my $hosts_fn = "$rootdir/etc/hosts";
     my $etc_hosts_data = '';
     
     if (-f $hosts_fn) {
        $etc_hosts_data =  PVE::Tools::file_get_contents($hosts_fn);
     }
 
-    my $hostip = undef; # fixme;
-    
+    my ($ipv4, $ipv6) = PVE::LXC::get_primary_ips($conf);
+    my $hostip = $ipv4 || $ipv6;
+
+    my ($searchdomains) = &$lookup_dns_conf($conf);
+
     $etc_hosts_data = &$update_etc_hosts($etc_hosts_data, $hostip, $oldname, 
-                                        $hostname, $conf->{'pve.searchdomain'});
-  
+                                        $hostname, $searchdomains);
+    
     PVE::Tools::file_set_contents($hostname_fn, "$hostname\n");
     PVE::Tools::file_set_contents($hosts_fn, $etc_hosts_data);
 }
 
 sub setup_network {
-    my ($class, $conf) = @_;
+    my ($self, $conf) = @_;
 
     die "please implement this inside subclass"
 }
 
 sub setup_init {
-    my ($class, $conf) = @_;
+    my ($self, $conf) = @_;
 
     die "please implement this inside subclass"
 }
 
+my $replacepw  = sub {
+    my ($file, $user, $epw) = @_;
+
+    my $tmpfile = "$file.$$";
+
+    eval  {
+       my $src = IO::File->new("<$file") ||
+           die "unable to open file '$file' - $!";
+
+       my $st = File::stat::stat($src) ||
+           die "unable to stat file - $!";
+
+       my $dst = IO::File->new(">$tmpfile") ||
+           die "unable to open file '$tmpfile' - $!";
+
+       # copy owner and permissions
+       chmod $st->mode, $dst;
+       chown $st->uid, $st->gid, $dst;
+       
+       while (defined (my $line = <$src>)) {
+           $line =~ s/^${user}:[^:]*:/${user}:${epw}:/;
+           print $dst $line;
+       }
+
+       $src->close() || die "close '$file' failed - $!\n";
+       $dst->close() || die "close '$tmpfile' failed - $!\n";
+    };
+    if (my $err = $@) {
+       unlink $tmpfile;
+    } else {
+       rename $tmpfile, $file;
+       unlink $tmpfile; # in case rename fails
+    }  
+};
+
+sub set_user_password {
+    my ($self, $conf, $user, $opt_password) = @_;
+
+    my $rootdir = $self->{rootdir};
+
+    my $pwfile = "$rootdir/etc/passwd";
+
+    return if ! -f $pwfile;
+
+    my $shadow = "$rootdir/etc/shadow";
+    
+    if (defined($opt_password)) {
+       if ($opt_password !~ m/^\$/) {
+           my $time = substr (Digest::SHA::sha1_base64 (time), 0, 8);
+           $opt_password = crypt(encode("utf8", $opt_password), "\$1\$$time\$");
+       };
+    } else {
+       $opt_password = '*';
+    }
+    
+    if (-f $shadow) {
+       &$replacepw ($shadow, $user, $opt_password);
+       &$replacepw ($pwfile, $user, 'x');
+    } else {
+       &$replacepw ($pwfile, $user, $opt_password);
+    }
+}
+
 sub pre_start_hook {
-    my ($class, $conf) = @_;
+    my ($self, $conf) = @_;
 
-    $class->setup_init($conf);
-    $class->setup_network($conf);
-    $class->set_hostname($conf);
+    $self->setup_init($conf);
+    $self->setup_network($conf);
+    $self->set_hostname($conf);
+    $self->set_dns($conf);
 
     # fixme: what else ?
 }
 
 sub post_create_hook {
-    my ($class, $conf) = @_;
-
-    $class->setup_init($conf);
-    $class->setup_network($conf);
-    $class->set_hostname($conf);
+    my ($self, $conf, $root_password) = @_;
 
+    $self->set_user_password($conf, 'root', $root_password);
+    $self->setup_init($conf);
+    $self->setup_network($conf);
+    $self->set_hostname($conf);
+    $self->set_dns($conf);
+    
     # fixme: what else ?
 }