1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

selftest: Add testenv for testing backup/restore

This adds a new testenv for testing that a DC created using the
samba-tool backup/restore can actually be started up. This actually
requires 2 new testenvs:

1. A 'backupfromdc' that solely exists to make a online backup of.
2. A 'restoredc' which takes the backup, and then uses the backup file
to do a restore, which we then start the DC based on.

The backupfromdc is just a plain vanilla AD DC. We use a separate test
env purely for this purpose, because the restoredc will use the same
domain (and so using an existing testenv would potentially interfere
with existing test cases).

Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
This commit is contained in:
Tim Beale 2018-05-29 16:05:02 +12:00 committed by Andrew Bartlett
parent 70b73f3ca6
commit ccba77a9d8
3 changed files with 217 additions and 1 deletions

View File

@ -246,7 +246,9 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
raise CommandError('Backup file not found.')
if targetdir is None:
raise CommandError('Please specify a target directory')
if os.path.exists(targetdir) and os.listdir(targetdir):
# allow restoredc to install into a directory prepopulated by selftest
if (os.path.exists(targetdir) and os.listdir(targetdir) and
os.environ.get('SAMBA_SELFTEST') != '1'):
raise CommandError('Target directory is not empty')
if not newservername:
raise CommandError('Server name required')

View File

@ -407,6 +407,8 @@ sub get_interface($)
$interfaces{"fakednsforwarder2"} = 37;
$interfaces{"s4member_dflt"} = 38;
$interfaces{"vampire2000dc"} = 39;
$interfaces{"backupfromdc"} = 40;
$interfaces{"restoredc"} = 41;
# update lib/socket_wrapper/socket_wrapper.c
# #define MAX_WRAPPED_INTERFACES 64

View File

@ -2142,6 +2142,7 @@ sub check_env($$)
ad_dc_no_nss => [],
ad_dc_no_ntlm => [],
ad_dc_ntvfs => [],
backupfromdc => [],
fl2008r2dc => ["ad_dc"],
fl2003dc => ["ad_dc"],
@ -2159,6 +2160,8 @@ sub check_env($$)
s4member_dflt_domain => ["ad_dc_ntvfs"],
s4member => ["ad_dc_ntvfs"],
restoredc => ["backupfromdc"],
none => [],
);
@ -2578,6 +2581,215 @@ sub setup_ad_dc_no_ntlm
return $env;
}
# Sets up a DC that's solely used to do a domain backup from. We then use the
# backupfrom-DC to create the restore-DC - this proves that the backup/restore
# process will create a Samba DC that will actually start up.
# We don't use the backup-DC for anything else because its domain will conflict
# with the restore DC.
sub setup_backupfromdc
{
my ($self, $path) = @_;
# If we didn't build with ADS, pretend this env was never available
if (not $self->{target3}->have_ads()) {
return "UNKNOWN";
}
my $env = $self->provision_ad_dc($path, "backupfromdc", "BACKUPDOMAIN",
"backupdom.samba.example.com", "");
unless ($env) {
return undef;
}
if (not defined($self->check_or_start($env, "standard"))) {
return undef;
}
my $upn_array = ["$env->{REALM}.upn"];
my $spn_array = ["$env->{REALM}.spn"];
$self->setup_namespaces($env, $upn_array, $spn_array);
return $env;
}
# Creates a backup of a running testenv DC
sub create_backup
{
# note: dcvars contains the env info for the backup DC testenv
my ($self, $env, $dcvars, $backupdir, $backup_cmd) = @_;
# get all the env variables we pass in with the samba-tool command
my $cmd_env = "";
$cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
if (defined($env->{RESOLV_WRAPPER_CONF})) {
$cmd_env .= "RESOLV_WRAPPER_CONF=\"$env->{RESOLV_WRAPPER_CONF}\" ";
} else {
$cmd_env .= "RESOLV_WRAPPER_HOSTS=\"$env->{RESOLV_WRAPPER_HOSTS}\" ";
}
# Note: use the backupfrom-DC's krb5.conf to do the backup
$cmd_env .= " KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
$cmd_env .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
# use samba-tool to create a backup from the 'backupfromdc' DC
my $cmd = "";
my $samba_tool = Samba::bindir_path($self, "samba-tool");
my $server = $dcvars->{DC_SERVER_IP};
$cmd .= "$cmd_env $samba_tool domain backup $backup_cmd --server=$server";
$cmd .= " --targetdir=$backupdir -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
print "Executing: $cmd\n";
unless(system($cmd) == 0) {
warn("Failed to create backup using: \n$cmd");
return undef;
}
# get the name of the backup file created
opendir(DIR, $backupdir);
my @files = grep(/\.tar/, readdir(DIR));
closedir(DIR);
if(scalar @files != 1) {
warn("Backup file not found in directory $backupdir\n");
return undef;
}
my $backup_file = "$backupdir/$files[0]";
print "Using backup file $backup_file...\n";
return $backup_file;
}
# Restores a backup-file to populate a testenv for a new DC
sub restore_backup_file
{
my ($self, $backup_file, $restore_opts, $restoredir, $smbconf) = @_;
# pass the restore command the testenv's smb.conf that we've already
# generated. But move it to a temp-dir first, so that the restore doesn't
# overwrite it
my $tmpdir = File::Temp->newdir();
my $tmpconf = "$tmpdir/smb.conf";
my $cmd = "cp $smbconf $tmpconf";
unless(system($cmd) == 0) {
warn("Failed to backup smb.conf using: \n$cmd");
return -1;
}
my $samba_tool = Samba::bindir_path($self, "samba-tool");
$cmd = "$samba_tool domain backup restore --backup-file=$backup_file";
$cmd .= " --targetdir=$restoredir $restore_opts --configfile=$tmpconf";
print "Executing: $cmd\n";
unless(system($cmd) == 0) {
warn("Failed to restore backup using: \n$cmd");
return -1;
}
print "Restore complete\n";
return 0
}
# sets up the initial directory and returns the new testenv's env info
# (without actually doing a 'domain join')
sub prepare_dc_testenv
{
my ($self, $prefix, $dcname, $domain, $realm, $password) = @_;
my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
$dcname,
$domain,
$realm,
undef,
"2008",
$password,
undef,
undef);
# the restore uses a slightly different state-dir location to other testenvs
$ctx->{statedir} = "$ctx->{prefix_abs}/state";
push(@{$ctx->{directories}}, "$ctx->{statedir}");
# add support for sysvol/netlogon/tmp shares
$ctx->{share} = "$ctx->{prefix_abs}/share";
push(@{$ctx->{directories}}, "$ctx->{share}");
$ctx->{smb_conf_extra_options} = "
max xmit = 32K
server max protocol = SMB2
[sysvol]
path = $ctx->{statedir}/sysvol
read only = no
[netlogon]
path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
read only = no
[tmp]
path = $ctx->{share}
read only = no
posix:sharedelay = 10000
posix:oplocktimeout = 3
posix:writetimeupdatedelay = 50000
";
my $env = $self->provision_raw_step1($ctx);
$env->{DC_SERVER} = $env->{SERVER};
$env->{DC_SERVER_IP} = $env->{SERVER_IP};
$env->{DC_SERVER_IPV6} = $env->{SERVER_IPV6};
$env->{DC_NETBIOSNAME} = $env->{NETBIOSNAME};
$env->{DC_USERNAME} = $env->{USERNAME};
$env->{DC_PASSWORD} = $env->{PASSWORD};
return $env;
}
# Set up a DC testenv solely by using the samba-tool domain backup/restore
# commands. This proves that we can backup an online DC ('backupfromdc') and
# use the backup file to create a valid, working samba DC.
sub setup_restoredc
{
# note: dcvars contains the env info for the dependent testenv ('backupfromdc')
my ($self, $prefix, $dcvars) = @_;
print "Preparing RESTORE DC...\n";
my $env = $self->prepare_dc_testenv($prefix, "restoredc",
$dcvars->{DOMAIN}, $dcvars->{REALM},
$dcvars->{PASSWORD});
# create a backup of the 'backupfromdc'
my $backupdir = File::Temp->newdir();
my $backup_file = $self->create_backup($env, $dcvars, $backupdir, "online");
unless($backup_file) {
return undef;
}
# restore the backup file to populate the restore-DC testenv
my $restore_dir = abs_path($prefix);
my $ret = $self->restore_backup_file($backup_file,
"--newservername=$env->{SERVER}",
$restore_dir, $env->{SERVERCONFFILE});
unless ($ret == 0) {
return undef;
}
# start samba for the restored DC
if (not defined($self->check_or_start($env, "standard"))) {
return undef;
}
my $upn_array = ["$env->{REALM}.upn"];
my $spn_array = ["$env->{REALM}.spn"];
$self->setup_namespaces($env, $upn_array, $spn_array);
return $env;
}
sub setup_none
{
my ($self, $path) = @_;