App-LXC-Container
view release on metacpan or search on metacpan
t/06-update.t view on Meta::CPAN
is($_->{x11}, 0, 'master test 4 X11 is correct');
$_ = App::LXC::Container::Update->new('update-test-1', 'update-test-2');
$_->_parse_master();
is($_->{audio}, 1, 'master test 5 audio is correct');
is($_->{network}, 2, 'master test 5 network is correct');
is($_->{network_from}, 'update-test-2',
'master test 5 network has correct origin');
is_deeply([sort keys %{$_->{users}}], [1001, 1002, 1003],
'master test 5 user ids are correct');
is_deeply([sort values %{$_->{users}}], ['u1', 'u2', 'u3'],
'master test 5 users are correct');
is_deeply($_->{users_from}, ['update-test-1', 'update-test-2'],
'master test 5 users have correct origin');
is($_->{x11}, 1, 'master test 5 X11 is correct');
$_ = App::LXC::Container::Update->new('update-test-1', 'update-test-2');
$_->_parse_master();
is($_->{audio}, 1, 'master test 6 audio is correct');
is($_->{network}, 2, 'master test 6 network is correct');
is($_->{network_from}, 'update-test-2',
'master test 6 network has correct origin');
is_deeply([sort keys %{$_->{users}}], [1001, 1002, 1003],
'master test 6 user ids are correct');
is_deeply([sort values %{$_->{users}}], ['u1', 'u2', 'u3'],
'master test 6 users are correct');
is_deeply($_->{users_from}, ['update-test-1', 'update-test-2'],
'master test 6 users have correct origin');
is($_->{x11}, 1, 'master test 6 X11 is correct');
$_ = App::LXC::Container::Update->new('update-test-3');
output_like
{ $_->_parse_master(); }
qr{^$},
qr{^audio will not work without local or global network$re_msg_tail\Z},
'audio without network prints warning';
is($_->{audio}, 1, 'master test 7 audio is correct');
is($_->{network}, 0, 'master test 7 network is correct');
is($_->{network_from}, '???',
'master test 7 network has correct origin');
is_deeply([sort keys %{$_->{users}}], [1003, 1004],
'master test 7 user ids are correct');
is_deeply([sort values %{$_->{users}}], ['u3', 'u4'],
'master test 7 users are correct');
is_deeply($_->{users_from}, ['update-test-3'],
'master test 7 users have correct origin');
is($_->{x11}, 1, 'master test 7 X11 is correct');
$_ = App::LXC::Container::Update->new('update-test-4');
$_->_parse_master();
is($_->{audio}, 0, 'master test 8 audio is correct');
is($_->{network}, 0, 'master test 8 network is correct');
is_deeply([sort keys %{$_->{users}}], [0],
'master test 8 users are correct');
is_deeply([sort values %{$_->{users}}], ['root'],
'master test 8 users are correct');
is_deeply($_->{users_from}, ['update-test-4'],
'master test 8 users have correct origin');
is($_->{x11}, 0, 'master test 8 X11 is correct');
$_->_parse_users();
like($_->{mount_entry}{'/root'}, qr{^/root\s+root\s+none create=dir,rw,bind$},
'user test 8 created correct mount entry');
is($_->{mount_source}{'/root'}, 'container users',
'user test 8 created correct mount source');
is($_->{mounts_of_source}{'container users'}[0], '/root',
'user test 8 created correct mount source list');
#########################################################################
# test for packages files:
_setup_file('/lxc/conf/u1-PKG-update-test-1.packages',
'# 2 identical', '', 'chromium', 'chromium');
_setup_file('/lxc/conf/u2-PKG-update-test-2.packages',
'# 2 different', '', 'chromium', 'evince');
$_ = App::LXC::Container::Update->new('update-test-1');
$_->_parse_packages();
is_deeply($_->{package_sources},
['30-PKG-default.packages', 'u1-PKG-update-test-1.packages'],
'packages test 1 has correct source list');
# some Smokers don't have a dash, so it's not part of the default package list:
if (5 == @{$_->{packages}})
{
is_deeply($_->{packages},
[qw(coreutils dash libc-bin util-linux chromium)],
'packages test 1 has correct content');
}
else
{
diag(join(' ', 'PACKAGES:', @{$_->{packages}}));
is_deeply($_->{packages},
[qw(coreutils libc-bin util-linux chromium)],
'packages test 1a has correct content');
}
is($_->{package_source}{chromium}, 'u1-PKG-update-test-1.packages',
'packages test 1 chromium entry is correct');
$_ = App::LXC::Container::Update->new('update-test-2');
$_->_parse_packages();
is_deeply($_->{package_sources},
['30-PKG-default.packages', 'u2-PKG-update-test-2.packages'],
'packages test 2 has correct source list');
if (6 == @{$_->{packages}})
{
is_deeply($_->{packages},
[qw(coreutils dash libc-bin util-linux chromium evince)],
'packages test 2 has correct content');
}
else
{
is_deeply($_->{packages},
[qw(coreutils libc-bin util-linux chromium evince)],
'packages test 2a has correct content');
}
is($_->{package_source}{chromium}, 'u2-PKG-update-test-2.packages',
'packages test 2 chromium entry is correct');
is($_->{package_source}{evince}, 'u2-PKG-update-test-2.packages',
'packages test 2 evince entry is correct');
$_ = App::LXC::Container::Update->new('update-test-1', 'update-test-2');
$_->_parse_packages();
is_deeply($_->{package_sources},
t/06-update.t view on Meta::CPAN
'packages test 3 chromium entry is correct');
is($_->{package_source}{evince}, 'u2-PKG-update-test-2.packages',
'packages test 3 evince entry is correct');
$_ = App::LXC::Container::Update->new('update-test-2', 'update-test-1');
$_->_parse_master(); # now with audio packages!
$_->_parse_packages();
is_deeply($_->{package_sources},
['30-PKG-default.packages',
'31-PKG-network.packages',
'60-PKG-X11.packages',
'70-PKG-audio.packages',
'u2-PKG-update-test-2.packages',
'u1-PKG-update-test-1.packages'],
'packages test 4 has correct source list');
if (9 == @{$_->{packages}})
{
is_deeply($_->{packages},
[qw(coreutils dash libc-bin util-linux iproute2
fontconfig-config pulseaudio-utils chromium evince)],
'packages test 4 has correct content');
}
else
{
diag(join(' ', 'PACKAGES:', @{$_->{packages}}));
is_deeply($_->{packages},
[qw(coreutils libc-bin util-linux iproute2
fontconfig-config pulseaudio-utils chromium evince)],
'packages test 4a has correct content');
}
is($_->{package_source}{evince}, 'u2-PKG-update-test-2.packages',
'packages test 4 evince entry is correct');
is($_->{package_source}{'pulseaudio-utils'}, '70-PKG-audio.packages',
'packages test 4 evince entry is correct');
#########################################################################
# test for mounts files:
my $path2something = TMP_PATH . '/usr/bin/2something';
_setup_file('/lxc/conf/u1-MNT-update-test-1.mounts',
'# 1st gets overwritten by 2nd',
'',
TMP_PATH . '/usr/bin/2something create=unused tmpfs',
$path2something);
_setup_file('/lxc/conf/u2-MNT-update-test-2.mounts',
'# same as in u1...',
'',
$path2something);
_setup_file('/lxc/conf/u1-SPC-update-test-1.special',
'# special test entry:',
'',
'lxc.namespace.keep=ipc');
$update_object = App::LXC::Container::Update->new('update-test-1');
$update_object->_parse_mounts();
obj_keys_in_range('mount_entry', 8, 12,
'mounts test 1 has correct entry count');
obj_keys_in_range('mount_source', 8, 12,
'mounts test 1 has correct source count');
is($update_object->{mount_entry}{$path2something},
$path2something . ' ' . substr($path2something, 1)
. ' none create=file,ro,bind 0 0',
'mounts test 1 source entry is correct');
is($update_object->{mount_source}{$path2something}, 'u1-MNT-update-test-1.mounts',
'mounts test 1 source entry is correct');
$update_object = App::LXC::Container::Update->new('update-test-2');
$update_object->_parse_master(); # now with X11 mounts!
$update_object->_parse_mounts();
obj_keys_in_range('mount_entry', 18, 22,
'mounts test 2 has correct entry count');
obj_keys_in_range('mount_source', 18, 22,
'mounts test 2 has correct source count');
is($update_object->{mount_entry}{$path2something},
$path2something . ' ' . substr($path2something, 1)
. ' none create=file,ro,bind 0 0',
'mounts test 2 source entry is correct');
is($update_object->{mount_source}{$path2something}, 'u2-MNT-update-test-2.mounts',
'mounts test 2 source entry is correct');
is($update_object->{mount_entry}{'/usr/share/icons'},
'/usr/share/icons usr/share/icons none create=dir,ro,bind 0 0',
'mounts test 2 source entry for X11 is correct');
is($update_object->{mount_source}{'/usr/share/icons'}, '61-MNT-X11.mounts',
'mounts test 2 source entry for X11 is correct');
$update_object = App::LXC::Container::Update->new('update-test-1', 'update-test-2');
$update_object->_parse_mounts();
obj_keys_in_range('mount_entry', 8, 12,
'mounts test 3 has correct entry count');
obj_keys_in_range('mount_source', 8, 12,
'mounts test 3 has correct source count');
is($update_object->{mount_entry}{$path2something},
$path2something . ' ' . substr($path2something, 1)
. ' none create=file,ro,bind 0 0',
'mounts test 3 source entry is correct');
is($update_object->{mount_source}{$path2something}, 'u2-MNT-update-test-2.mounts',
'mounts test 3 source entry is correct');
$update_object = App::LXC::Container::Update->new('update-test-2', 'update-test-1');
$update_object->_parse_mounts();
obj_keys_in_range('mount_entry', 8, 12,
'mounts test 4 has correct entry count');
obj_keys_in_range('mount_source', 8, 12,
'mounts test 4 has correct source count');
is($update_object->{mount_entry}{$path2something},
$path2something . ' ' . substr($path2something, 1)
. ' none create=file,ro,bind 0 0',
'mounts test 4 source entry is correct');
is($update_object->{mount_source}{$path2something}, 'u1-MNT-update-test-1.mounts',
'mounts test 4 source entry is correct');
#########################################################################
# test for filter files:
_setup_file('/lxc/conf/u1-NOT-update-test-1.filter',
'# 2nd overwrites 1st',
TMP_PATH . '/usr/lib nomerge',
TMP_PATH . '/var/log empty',
TMP_PATH . '/.Xdummy empty');
_setup_file('/lxc/conf/u2-NOT-update-test-2.filter',
'# 2nd overwrites 1st',
TMP_PATH . '/var/log copy');
$update_object = App::LXC::Container::Update->new('update-test-1');
$update_object->_parse_filter();
is($update_object->{filter}{TMP_PATH . '/usr/lib'}, 'nomerge',
'filter test 1 /usr/lib entry is correct');
is($update_object->{filter}{TMP_PATH . '/var/log'}, 'empty',
'filter test 1 /var/log entry is correct');
my $count1 = scalar(keys %{$update_object->{filter}});
$update_object = App::LXC::Container::Update->new('update-test-2');
$update_object->_parse_filter();
is(scalar(keys %{$update_object->{filter}}), $count1 - 2,
'filter test 2 has correct count');
is($update_object->{filter}{TMP_PATH . '/var/log'}, 'copy',
'filter test 2 /var/log entry is correct');
$update_object =
App::LXC::Container::Update->new('update-test-1', 'update-test-2');
$update_object->_parse_filter();
is($update_object->{filter}{TMP_PATH . '/var/log'}, 'copy',
'filter test 3 /var/log entry is correct');
$update_object =
App::LXC::Container::Update->new('update-test-2', 'update-test-1');
$update_object->_parse_filter();
is($update_object->{filter}{TMP_PATH . '/var/log'}, 'empty',
'filter test 4 /var/log entry is correct');
#########################################################################
# full test:
SKIP:{
# Some smokers don't have the needed directory /usr/share/ssl-cert, so
# hopefully we can create it:
unless (-d '/usr/share/ssl-cert')
{
$< == 0
or skip 'rest of tests not possible without /usr/share/ssl-cert', 62;
mkdir '/usr/share/ssl-cert'
or warn 'failed to mkdir /usr/share/ssl-cert';
}
# Running these tests in a sub-directory below /tmp cause
# inconsistencies as that is one of our special directories:
TMP_PATH =~ m|^/tmp/| and skip 'rest of tests not working below /tmp', 62;
_setup_link(TMP_PATH . '/usr/bin/3link', '2something');
t/06-update.t view on Meta::CPAN
output_like # last name becomes container name!
{ App::LXC::Container::update('update-test-2', 'update-test-1'); }
qr{^$},
qr{\A$re_err2$re_err4$re_err_o1$re_err3\Z},
'full test run with expected output';
ok(-f CONF_ROOT . '/update-test-1.conf',
'LXC configuration file has been created');
$re = join
("\n",
'^# container description created by App::LXC::Container::Update',
'# MASTER: G5,X,A',
'lxc\.uts\.name = update-test-1',
'lxc\.rootfs\.path = /.+/tmp/lxc/update-test-1',
'lxc\.rootfs\.options = idmap=container',
'',
'#+ update-test-2, 10-NET-default\.conf #+',
'lxc\.net\.0\.type = veth',
'lxc\.net\.0\.flags = up',
'lxc\.net\.0\.link = lxcbr0',
'lxc\.net\.0\.name = eth0',
'lxc\.net\.0\.ipv4\.address = 10\.0\.3\.5/24',
'lxc\.net\.0\.hwaddr = 00:16:3e:xx:xx:xx',
'',
'#+ 20-DEV-default\.conf #+',
'lxc\.pty\.max = 8',
'lxc\.mount\.auto = cgroup:ro proc:mixed sys:ro',
'',
'#+ update-test-2, update-test-1 #+',
'# root:',
'lxc\.idmap = u 0 0 1',
'lxc\.idmap = u 1 100001 1000',
'# u1:',
'lxc\.idmap = u 1001 1001 1',
'# u2:',
'lxc\.idmap = u 1002 1002 1',
'# u3:',
'lxc\.idmap = u 1003 1003 1',
'lxc\.idmap = u 1004 101004 64532',
'# root:',
'lxc\.idmap = g 0 0 1',
'lxc\.idmap = g 1 100001 1000',
'# u1:',
'lxc\.idmap = g 1001 1001 1',
'# u2:',
'lxc\.idmap = g 1002 1002 1',
'# u3:',
'lxc\.idmap = g 1003 1003 1',
'lxc\.idmap = g 1004 101004 64532',
'',
'#+ special configuration #+',
'lxc.namespace.keep=ipc',
'',
'#+ container users #+',
'',
'#+ 40-MNT-default\.mounts #+',
# distributions may have additional non-symlink directories here,
# some are missing /dev/shm:
'.*(lxc\.mount\.entry = tmpfs dev/shm tmpfs create=dir,rw 0 0',
')?lxc\.mount\.entry = /etc/login.defs etc/login.defs none create=file,ro,bind 0 0',
'lxc\.mount\.entry = /etc/pam.d etc/pam.d none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /etc/security etc/security none create=dir,ro,bind 0 0',
'.*lxc\.mount\.entry = tmpfs root tmpfs create=dir,rw,mode=700 0 0',
'.*lxc\.mount\.entry = /tmp tmp none create=dir,rw,bind 0 0',
'lxc\.mount\.entry = tmpfs var/tmp tmpfs create=dir,rw 0 0',
'(lxc\.mount\.entry = /etc/debian_version etc/debian_version none create=file,ro,bind 0 0',
')?',
'#+ 41-MNT-network\.mounts #+',
'lxc\.mount\.entry = /etc/ssl/certs etc/ssl/certs none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/lib/ssl usr/lib/ssl none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/share/ca-certificates usr/share/ca-certificates none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/share/ssl-cert usr/share/ssl-cert none create=dir,ro,bind 0 0',
'',
'#+ 61-MNT-X11\.mounts #+',
'[^#]+#+ u2-MNT-update-test-2\.mounts #+',
'',
'#+ u1-MNT-update-test-1\.mounts #+',
'lxc\.mount\.entry = /.+/bin/2something none create=file,ro,bind 0 0',
'lxc\.mount\.entry = /.+/bin/2something none create=file,ro,bind 0 0',
'',
'#+ 30-PKG-default\.packages #+',
'# coreutils',
'# dash',
'# libc-bin',
'# util-linux',
'#+ 31-PKG-network.packages #+',
'# iproute2',
'#+ 60-PKG-X11.packages #+',
'# fontconfig-config',
'#+ 70-PKG-audio\.packages #+',
'# pulseaudio-utils',
'#+ u2-PKG-update-test-2\.packages #+',
'# chromium',
'# evince',
'#+ u1-PKG-update-test-1\.packages #+',
'',
'#+ empty filters #+',
'lxc\.mount\.entry = tmpfs .+/tmp/var/log tmpfs create=dir,rw 0 0',
'lxc\.mount\.entry = tmpfs var/log tmpfs create=dir,rw 0 0',
'',
'#+ mounts derived from above packages #+',
'lxc\.mount\.entry = /.+/tmp/usr/bin/1chromium .+/tmp/usr/bin/1chromium none create=file,ro,bind 0 0',
'lxc\.mount\.entry = /.+/tmp/usr/lib/some/directory/with .+/tmp/usr/lib/some/directory/with none create=dir,ro,bind 0 0'
# helper expression to update test after modifying Data/*.pm (move up/down):
#(1?():(
##))
);
my $conf = '';
if (-f CONF_ROOT . '/update-test-1.conf')
{
open my $in, '<', CONF_ROOT . '/update-test-1.conf'
or die "can't open ", CONF_ROOT, '/update-test-1.conf: ', $!;
$conf = join('', <$in>);
close $in;
}
like($conf, qr{^$re}s, 'LXC configuration file looks correct');
foreach (qw(bin lib lib32 lib64 libx32 sbin))
{
SKIP:{
-l '/' . $_ or skip "/$_ not symbolic link on $os", 1;
ok(-l CONF_ROOT . '/update-test-1/' . $_, 'got link: /' . $_);
}
}
my $tmp_sub = substr(TMP_PATH, 1);
foreach (qw(root tmp var var/log),
map { $tmp_sub . '/' . $_ }
qw(usr usr/bin usr/lib usr/lib/some/directory/with var var/log))
{
ok(-d CONF_ROOT . '/update-test-1/' . $_, 'got directory: /' . $_);
}
ok(! -e CONF_ROOT . '/update-test-1/usr/lib/some/directory/with/file-1.txt',
'no file-1.txt in /update-test-1/usr/lib/some/directory/with');
foreach my $bin (qw(1chromium 2something 3link))
{
$_ = $tmp_sub . '/usr/bin/' . $bin;
ok(-f CONF_ROOT . '/update-test-1/' . $_, 'got file: /' . $_);
}
$_ = $tmp_sub . '/usr/bin/3link';
ok(-l CONF_ROOT . '/update-test-1/' . $_, 'got link: /' . $_);
is((stat(CONF_ROOT . '/update-test-1/root'))[2] & 07777, 0700,
'/root has correct permission');
is((stat(CONF_ROOT . '/update-test-1/tmp'))[2] & 07777, 01777,
'/tmp has correct permission');
#####################################################################
# tests of local-network and network container:
foreach my $network ('local-network', 'network')
{
output_like # last name becomes container name!
{ App::LXC::Container::update($network); }
qr{^$},
qr{\A$re_err2$re_err3\Z},
'test run for container "' . $network . '" had expected output';
my $conf_file = CONF_ROOT . '/' . $network . '.conf';
ok(-f $conf_file,
'LXC configuration file has been created - ' . $network);
my $net_key = $network eq 'network' ? 'G' : 'L';
my $net_id = $network eq 'network' ? 3 : 2;
$re = join
("\n",
'^# container description created by App::LXC::Container::Update',
'# MASTER: ' . $net_key . $net_id . ',-,-',
'lxc\.uts\.name = ' . $network,
'lxc\.rootfs\.path = /.+/tmp/lxc/' . $network,
'lxc\.rootfs\.options = idmap=container',
'',
'#+ ' . $network . ', 10-NET-default\.conf #+',
'lxc\.net\.0\.type = veth',
'lxc\.net\.0\.flags = up',
'lxc\.net\.0\.link = lxcbr0',
'lxc\.net\.0\.name = eth0',
'lxc\.net\.0\.ipv4\.address = 10\.0\.3\.' . $net_id . '/24',
'lxc\.net\.0\.hwaddr = 00:16:3e:xx:xx:xx',
'',
'#+ 20-DEV-default\.conf #+',
'lxc\.pty\.max = 8',
'lxc\.mount\.auto = cgroup:ro proc:mixed sys:ro',
'',
'#+ -no privileged users- #+',
'lxc\.idmap = u 0 100000 65536',
'lxc\.idmap = g 0 100000 65536',
'',
'#+ 40-MNT-default\.mounts #+',
# distributions may have additional non-symlink directories here,
# some are missing /dev/shm:
'.*(lxc\.mount\.entry = tmpfs dev/shm tmpfs create=dir,rw 0 0',
')?lxc\.mount\.entry = /etc/login.defs etc/login.defs none create=file,ro,bind 0 0',
'lxc\.mount\.entry = /etc/pam.d etc/pam.d none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /etc/security etc/security none create=dir,ro,bind 0 0',
'.*lxc\.mount\.entry = tmpfs root tmpfs create=dir,rw,mode=700 0 0',
'.*lxc\.mount\.entry = /tmp tmp none create=dir,rw,bind 0 0',
'lxc\.mount\.entry = tmpfs var/tmp tmpfs create=dir,rw 0 0',
'(lxc\.mount\.entry = /etc/debian_version etc/debian_version none create=file,ro,bind 0 0',
')?',
'#+ 41-MNT-network\.mounts #+',
'lxc\.mount\.entry = /etc/ssl/certs etc/ssl/certs none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/lib/ssl usr/lib/ssl none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/share/ca-certificates usr/share/ca-certificates none create=dir,ro,bind 0 0',
'lxc\.mount\.entry = /usr/share/ssl-cert usr/share/ssl-cert none create=dir,ro,bind 0 0',
'',
'#+ 30-PKG-default\.packages #+',
'# coreutils',
'# dash',
'# libc-bin',
'# util-linux',
'#+ 31-PKG-network.packages #+',
'# iproute2',
'',
'#+ empty filters #+',
'lxc.mount.entry = tmpfs var/log tmpfs create=dir,rw 0 0',
'',
'#+ mounts derived from above packages #+',
'lxc\.mount\.entry = /.+/tmp/usr/bin/2something .+/tmp/usr/bin/2something none create=file,ro,bind 0 0'
# helper expression to update test after modifying Data/*.pm (move up/down):
#(1?():(
#))
);
if (-f $conf_file)
{
open my $in, '<', $conf_file
or die "can't open ", $conf_file . ': ', $!;
$conf = join('', <$in>);
close $in;
}
like($conf, qr{^$re}s,
'LXC configuration file looks correct - ' . $network);
my $conf_dir = CONF_ROOT . '/' . $network . '/';
foreach (qw(bin lib lib32 lib64 libx32 sbin))
{
SKIP:{
-l '/' . $_ or skip "/$_ not symbolic link on $os", 1;
ok(-l $conf_dir . $_, 'got link /' . $_ . ' in ' . $network);
}
}
foreach (qw(root tmp var var/log),
map { $tmp_sub . '/' . $_ } qw(usr usr/bin))
{
ok(-d $conf_dir . $_, 'got directory /' . $_ . ' in ' . $network);
}
$_ = $tmp_sub . '/usr/bin/2something';
ok(-f $conf_dir . $_, 'got file /' . $_ . ' in ' . $network);
is((stat(CONF_ROOT . '/' . $network . '/root'))[2] & 07777, 0700,
'/root has correct permission in ' . $network);
is((stat(CONF_ROOT . '/' . $network . '/tmp'))[2] & 07777, 01777,
'/tmp has correct permission in ' . $network);
}
} # end of big SKIP block
( run in 0.603 second using v1.01-cache-2.11-cpan-2398b32b56e )