ostype => {
optional => 1,
type => 'string',
- enum => ['debian', 'ubuntu', 'centos', 'fedora', 'archlinux'],
+ enum => ['debian', 'ubuntu', 'centos', 'fedora', 'opensuse', 'archlinux'],
description => "OS type. Corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf.",
},
console => {
my $custom_idmap = grep { $_->[0] eq 'lxc.id_map' } @{$conf->{lxc}};
my $ostype = $conf->{ostype} || die "missing 'ostype' - internal error";
- if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | archlinux)$/x) {
+ if ($ostype =~ /^(?:debian | ubuntu | centos | fedora | opensuse | archlinux)$/x) {
$raw .= "lxc.include = /usr/share/lxc/config/$ostype.common.conf\n";
if ($unprivileged || $custom_idmap) {
$raw .= "lxc.include = /usr/share/lxc/config/$ostype.userns.conf\n"
use PVE::LXC::Setup::Ubuntu;
use PVE::LXC::Setup::Redhat;
use PVE::LXC::Setup::Fedora;
+use PVE::LXC::Setup::SUSE;
use PVE::LXC::Setup::ArchLinux;
my $plugins = {
ubuntu => 'PVE::LXC::Setup::Ubuntu',
redhat => 'PVE::LXC::Setup::Redhat',
fedora => 'PVE::LXC::Setup::Fedora',
+ opensuse => 'PVE::LXC::Setup::SUSE',
archlinux => 'PVE::LXC::Setup::ArchLinux',
};
if (-f "$rootdir/etc/debian_version") {
return "debian";
+ } elsif (-f "$rootdir/etc/SuSE-brand" || -f "$rootdir/etc/SuSE-release") {
+ return "opensuse";
} elsif (-f "$rootdir/etc/fedora-release") {
return "fedora";
} elsif (-f "$rootdir/etc/redhat-release") {
$self->ct_reset_ownership($file);
}
+# Modify a marked portion of a file and move it to the beginning of the file.
+# If the file becomes empty it will be deleted.
+sub ct_modify_file_head_portion {
+ my ($self, $file, $head, $tail, $data) = @_;
+ if ($self->ct_file_exists($file)) {
+ my $old = $self->ct_file_get_contents($file);
+ # remove the portion between $head and $tail (all instances via /g)
+ $old =~ s/(?:^|(?<=\n))\Q$head\E.*\Q$tail\E//gs;
+ chomp $old;
+ if ($old) {
+ # old data existed, append and add the trailing newline
+ if ($data) {
+ $self->ct_file_set_contents($file, $head.$data.$tail . $old."\n");
+ } else {
+ $self->ct_file_set_contents($file, $old."\n");
+ }
+ } elsif ($data) {
+ # only our own data will be added
+ $self->ct_file_set_contents($file, $head.$data.$tail);
+ } else {
+ # empty => delete
+ $self->ct_unlink($file);
+ }
+ } else {
+ $self->ct_file_set_contents($file, $head.$data.$tail);
+ }
+}
+
1;
-SOURCES=Base.pm Debian.pm Ubuntu.pm Redhat.pm Fedora.pm ArchLinux.pm
+SOURCES=Base.pm Debian.pm Ubuntu.pm Redhat.pm Fedora.pm SUSE.pm ArchLinux.pm
.PHONY: install
install:
# To keep user-defined routes in route-$iface we mark ours:
my $head = "# --- BEGIN PVE ROUTES ---\n";
my $tail = "# --- END PVE ROUTES ---\n";
- $routes = $head . $routes . $tail if $routes;
- if ($self->ct_file_exists($routefile)) {
- # if it exists we update by first removing our old rules
- my $old = $self->ct_file_get_contents($routefile);
- $old =~ s/(?:^|(?<=\n))\Q$head\E.*\Q$tail\E//gs;
- chomp $old;
- if ($old) {
- $self->ct_file_set_contents($routefile, $routes . $old . "\n");
- } else {
- # or delete if we aren't adding routes and the file's now empty
- $self->ct_unlink($routefile);
- }
- } elsif ($routes) {
- $self->ct_file_set_contents($routefile, $routes);
- }
+ $self->ct_modify_file_head_portion($routefile, $head, $tail, $routes);
}
my $sysconfig_network = "/etc/sysconfig/network";
--- /dev/null
+package PVE::LXC::Setup::SUSE;
+
+use strict;
+use warnings;
+
+use PVE::LXC::Setup::Base;
+
+use base qw(PVE::LXC::Setup::Base);
+
+sub new {
+ my ($class, $conf, $rootdir) = @_;
+
+ my $release = eval { -f "$rootdir/etc/SuSE-release"
+ ? PVE::Tools::file_get_contents("$rootdir/etc/SuSE-release")
+ : PVE::Tools::file_get_contents("$rootdir/etc/SuSE-brand") };
+ die "unable to read version info\n" if $@;
+
+ my $version;
+
+ # Fixme: not sure whether the minor part is optional.
+ if ($release =~ m/^\s*VERSION\s*=\s*(\d+)(?:\.(\d+))?\s*$/m) {
+ $version = "$1.$2";
+ # 13.2 seems to get stuck in a mount loop with AppArmor,
+ # and otherwise fails to start up fully. Needs some more work.
+ if ($1 != 13 || ($2//0) > 1) {
+ die "unsupported suse release '$version'\n";
+ }
+ } else {
+ die "unrecognized suse release";
+ }
+
+ my $self = { conf => $conf, rootdir => $rootdir, version => $version };
+
+ $conf->{ostype} = 'opensuse';
+
+ return bless $self, $class;
+}
+
+sub template_fixup {
+ # Nothing to do
+}
+
+sub setup_init {
+ my ($self, $conf) = @_;
+
+ $self->setup_securetty($conf, qw(lxc/console lxc/tty1 lxc/tty2 lxc/tty3 lxc/tty4));
+ $self->setup_systemd_console($conf);
+}
+
+sub setup_network {
+ my ($self, $conf) = @_;
+
+ my ($gw, $gw6);
+
+ $self->ct_make_path('/etc/sysconfig/network');
+
+ foreach my $k (keys %$conf) {
+ next if $k !~ m/^net(\d+)$/;
+ my $d = PVE::LXC::parse_lxc_network($conf->{$k});
+ next if !$d->{name};
+
+ my $filename = "/etc/sysconfig/network/ifcfg-$d->{name}";
+ my $routefile = "/etc/sysconfig/network/ifroute-$d->{name}";
+ my $routes = '';
+
+ my @DHCPMODES = ('static', 'dhcp4', 'dhcp6', 'dhcp');
+ my ($NONE, $DHCP4, $DHCP6, $BOTH) = (0, 1, 2, 3);
+ my $dhcp = $NONE;
+ my @addrs = ();
+
+ my $data = '';
+ my $is_configured = 0;
+
+ if ($d->{ip} && $d->{ip} ne 'manual') {
+ $is_configured = 1;
+ if ($d->{ip} eq 'dhcp') {
+ $dhcp |= $DHCP4;
+ } else {
+ push @addrs, $d->{ip};
+ if (defined($d->{gw})) {
+ if (!PVE::Network::is_ip_in_cidr($d->{gw}, $d->{ip}, 4)) {
+ $routes .= "$d->{gw} 0.0.0.0 255.255.255.255 $d->{name}\n";
+ }
+ $routes .= "default $d->{gw} 0.0.0.0 $d->{name}\n";
+ }
+ }
+ }
+
+ if ($d->{ip6} && $d->{ip6} ne 'manual') {
+ $is_configured = 1;
+ if ($d->{ip6} eq 'auto') {
+ # FIXME: Not sure what to do here...
+ } elsif ($d->{ip6} eq 'dhcp') {
+ $dhcp |= $DHCP6;
+ } else {
+ push @addrs, $d->{ip6};
+ if (defined($d->{gw6})) {
+ if (!PVE::Network::is_ip_in_cidr($d->{gw6}, $d->{ip6}, 6)) {
+ $routes .= "$d->{gw6}/128 - - $d->{name}\n";
+ }
+ $routes .= "default $d->{gw6} - $d->{name}\n";
+ }
+ }
+ }
+
+ if (@addrs > 1) {
+ for my $i (1..@addrs) {
+ $data .= "IPADDR_${i}=$addrs[$i-1]\n";
+ }
+ } elsif (@addrs) {
+ $data .= "IPADDR=$addrs[0]\n";
+ } else {
+ # check for non-manual config with no dhcp and no addresses
+ next if $is_configured && $dhcp == $NONE;
+ }
+
+ $data = "STARTMODE=" . ($is_configured ? 'onboot' : 'manual') . "\n"
+ . "BOOTPROTO=$DHCPMODES[$dhcp]\n"
+ . $data;
+ $self->ct_file_set_contents($filename, $data);
+
+ # To keep user-defined routes in route-$iface we mark ours:
+ my $head = "# --- BEGIN PVE ROUTES ---\n";
+ my $tail = "# --- END PVE ROUTES ---\n";
+ $self->ct_modify_file_head_portion($routefile, $head, $tail, $routes);
+ }
+}
+
+1;
return if system("diff -u '$exp_fn' '$real_fn'") == 0;
- die "files does not match\n";
+ die "files do not match\n";
}
sub run_test {
srand(0);
$lxc_setup->post_create_hook('$TEST$ABCDEF');
- my @testfiles = qw(/etc/hostname /etc/hosts /etc/inittab /etc/network/interfaces /etc/resolv.conf /etc/passwd /etc/shadow /etc/sysconfig/network /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1 /etc/sysconfig/network-scripts/ifcfg-eth2 /etc/sysconfig/network-scripts/ifcfg-eth3 /etc/init/start-ttys.conf /etc/init/tty.conf /etc/init/power-status-changed.conf /etc/securetty /etc/crontab);
+ my @testfiles = qw(/etc/hostname
+ /etc/hosts
+ /etc/inittab
+ /etc/network/interfaces
+ /etc/resolv.conf
+ /etc/passwd
+ /etc/shadow
+ /etc/sysconfig/network
+ /etc/sysconfig/network-scripts/ifcfg-eth0
+ /etc/sysconfig/network-scripts/route-eth0
+ /etc/sysconfig/network-scripts/ifcfg-eth1
+ /etc/sysconfig/network-scripts/route-eth1
+ /etc/sysconfig/network-scripts/ifcfg-eth2
+ /etc/sysconfig/network-scripts/route-eth2
+ /etc/sysconfig/network-scripts/ifcfg-eth3
+ /etc/sysconfig/network-scripts/route-eth3
+ /etc/sysconfig/network/ifcfg-eth0
+ /etc/sysconfig/network/ifroute-eth0
+ /etc/sysconfig/network/ifcfg-eth1
+ /etc/sysconfig/network/ifroute-eth1
+ /etc/sysconfig/network/ifcfg-eth2
+ /etc/sysconfig/network/ifroute-eth2
+ /etc/sysconfig/network/ifcfg-eth3
+ /etc/sysconfig/network/ifroute-eth3
+ /etc/init/start-ttys.conf
+ /etc/init/tty.conf
+ /etc/init/power-status-changed.conf
+ /etc/securetty
+ /etc/crontab);
foreach my $fn (@testfiles) {
next if !-f "$testdir/$fn.exp";
test_file("$testdir/$fn.exp", "$rootfs/$fn");
--- /dev/null
+hostname: pvesuse1
+net0: bridge=vmbr0,name=eth0,ip=1.2.3.4/24,gw=1.2.3.1
+net1: bridge=vmbr0,name=eth1,ip=10.2.3.4/24
+net2: bridge=vmbr0,name=eth2,ip=manual
+net3: bridge=vmbr0,name=eth3
--- /dev/null
+BasedOnopenSUSE
+VERSION = 13.1
--- /dev/null
+127.0.0.1 localhost.localnet localhost
+1.2.3.4 pvesuse1.proxmox.com pvesuse1
--- /dev/null
+search proxmox.com
+nameserver 8.8.8.8
+nameserver 8.8.8.9
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
+lxc/console
+lxc/tty1
+lxc/tty2
+lxc/tty3
+lxc/tty4
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=static
+IPADDR=1.2.3.4/24
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=static
+IPADDR=10.2.3.4/24
--- /dev/null
+STARTMODE=manual
+BOOTPROTO=static
--- /dev/null
+STARTMODE=manual
+BOOTPROTO=static
--- /dev/null
+# --- BEGIN PVE ROUTES ---
+default 1.2.3.1 0.0.0.0 eth0
+# --- END PVE ROUTES ---
--- /dev/null
+# Nothing else
--- /dev/null
+# Nothing else
--- /dev/null
+hostname: pvesuse1
+net0: bridge=vmbr0,name=eth0,ip6=2001:1::/64,gw6=2001:1::ffff
+net1: bridge=vmbr0,name=eth1,ip6=2001:2::/64
+net2: bridge=vmbr0,name=eth2,ip6=manual
--- /dev/null
+BasedOnopenSUSE
+VERSION = 13.1
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
+lxc/console
+lxc/tty1
+lxc/tty2
+lxc/tty3
+lxc/tty4
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=static
+IPADDR=2001:1::/64
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=static
+IPADDR=2001:2::/64
--- /dev/null
+STARTMODE=manual
+BOOTPROTO=static
--- /dev/null
+# --- BEGIN PVE ROUTES ---
+default 2001:1::ffff - eth0
+# --- END PVE ROUTES ---
--- /dev/null
+hostname: pvesuse1
+net0: bridge=vmbr0,name=eth0,ip=1.2.3.4/24,gw=4.3.2.1,ip6=2001:1::/64,gw6=2001:1::ffff
+net1: bridge=vmbr0,name=eth1,ip=dhcp
+net2: bridge=vmbr0,name=eth2,ip6=dhcp
+net3: bridge=vmbr0,name=eth3,ip=dhcp,ip6=dhcp
--- /dev/null
+BasedOnopenSUSE
+VERSION = 13.1
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
--- /dev/null
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+console
+lxc/console
+lxc/tty1
+lxc/tty2
+lxc/tty3
+lxc/tty4
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=static
+IPADDR_1=1.2.3.4/24
+IPADDR_2=2001:1::/64
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=dhcp4
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=dhcp6
--- /dev/null
+STARTMODE=onboot
+BOOTPROTO=dhcp
--- /dev/null
+# --- BEGIN PVE ROUTES ---
+4.3.2.1 0.0.0.0 255.255.255.255 eth0
+default 4.3.2.1 0.0.0.0 eth0
+default 2001:1::ffff - eth0
+# --- END PVE ROUTES ---