+ child.expect(pexpect.EOF)
+ child.close()
+ if child.exitstatus != 0:
+ raise RuntimeError("kinit failed with status %d" % child.exitstatus)
+
+ def get_domains(self):
+ '''return a dictionary of DNS domains and IPs for named.conf'''
+ ret = {}
+ for v in self.vars:
+ if v[-6:] == "_REALM":
+ base = v[:-6]
+ if base + '_IP' in self.vars:
+ ret[self.vars[base + '_REALM']] = self.vars[base + '_IP']
+ return ret
+
+ def wait_reboot(self, retries=3):
+ '''wait for a VM to reboot'''
+
+ # first wait for it to shutdown
+ self.port_wait("${WIN_IP}", 139, wait_for_fail=True, delay=6)
+
+ # now wait for it to come back. If it fails to come back
+ # then try resetting it
+ while retries > 0:
+ try:
+ self.port_wait("${WIN_IP}", 139)
+ return
+ except:
+ retries -= 1
+ self.vm_reset("${WIN_VM}")
+ self.info("retrying reboot (retries=%u)" % retries)
+ raise RuntimeError(self.substitute("VM ${WIN_VM} failed to reboot"))
+
+ def get_vms(self):
+ '''return a dictionary of all the configured VM names'''
+ ret = []
+ for v in self.vars:
+ if v[-3:] == "_VM":
+ ret.append(self.vars[v])
+ return ret
+
+
+ def run_dcpromo_as_first_dc(self, vm, func_level=None):
+ self.setwinvars(vm)
+ self.info("Configuring a windows VM ${WIN_VM} at the first DC in the domain using dcpromo")
+ child = self.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_time=True)
+ if self.get_is_dc(child):
+ return
+
+ if func_level == '2008r2':
+ self.setvar("FUNCTION_LEVEL_INT", str(4))
+ elif func_level == '2003':
+ self.setvar("FUNCTION_LEVEL_INT", str(1))
+ else:
+ self.setvar("FUNCTION_LEVEL_INT", str(0))
+
+ child = self.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip=True, set_noexpire=True)
+
+ """This server must therefore not yet be a directory server, so we must promote it"""
+ child.sendline("copy /Y con answers.txt")
+ child.sendline('''
+[DCInstall]
+; New forest promotion
+ReplicaOrNewDomain=Domain
+NewDomain=Forest
+NewDomainDNSName=${WIN_REALM}
+ForestLevel=${FUNCTION_LEVEL_INT}
+DomainNetbiosName=${WIN_DOMAIN}
+DomainLevel=${FUNCTION_LEVEL_INT}
+InstallDNS=Yes
+ConfirmGc=Yes
+CreateDNSDelegation=No
+DatabasePath="C:\Windows\NTDS"
+LogPath="C:\Windows\NTDS"
+SYSVOLPath="C:\Windows\SYSVOL"
+; Set SafeModeAdminPassword to the correct value prior to using the unattend file
+SafeModeAdminPassword=${WIN_PASS}
+; Run-time flags (optional)
+RebootOnCompletion=No
+\1a
+''')
+ child.expect("copied.")
+ child.expect("C:")
+ child.expect("C:")
+ child.sendline("dcpromo /answer:answers.txt")
+ i = child.expect(["You must restart this computer", "failed", "Active Directory Domain Services was not installed", "C:", pexpect.TIMEOUT], timeout=240)
+ if i == 1 or i == 2:
+ raise Exception("dcpromo failed")
+ if i == 4: # timeout
+ child = self.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}")
+
+ child.sendline("shutdown -r -t 0")
+ self.port_wait("${WIN_IP}", 139, wait_for_fail=True)
+ self.port_wait("${WIN_IP}", 139)
+
+ child = self.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}")
+ # Check if we became a DC by now
+ if not self.get_is_dc(child):
+ raise Exception("dcpromo failed (and wasn't a DC even after rebooting)")
+ # Give DNS registration a kick
+ child.sendline("ipconfig /registerdns")
+
+ self.retry_cmd("host -t SRV _ldap._tcp.${WIN_REALM} ${WIN_IP}", ['has SRV record'], retries=60, delay=5 )
+
+
+ def start_winvm(self, vm):
+ '''start a Windows VM'''
+ self.setwinvars(vm)
+
+ self.info("Joining a windows box to the domain")
+ self.vm_poweroff("${WIN_VM}", checkfail=False)
+ self.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
+
+ def run_winjoin(self, vm, domain, username="administrator", password="${PASSWORD1}"):
+ '''join a windows box to a domain'''
+ child = self.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time=True, set_ip=True, set_noexpire=True)
+ retries = 5
+ while retries > 0:
+ child.sendline("ipconfig /flushdns")
+ child.expect("C:")
+ child.sendline("netdom join ${WIN_HOSTNAME} /Domain:%s /UserD:%s /PasswordD:%s" % (domain, username, password))
+ i = child.expect(["The command completed successfully",
+ "The specified domain either does not exist or could not be contacted."], timeout=120)
+ if i == 0:
+ break
+ time.sleep(10)
+ retries -= 1
+
+ child.expect("C:")
+ child.sendline("shutdown /r -t 0")
+ self.wait_reboot()
+ child = self.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time=True, set_ip=True)
+ child.sendline("ipconfig /registerdns")
+ child.expect("Registration of the DNS resource records for all adapters of this computer has been initiated. Any errors will be reported in the Event Viewer")
+ child.expect("C:")
+
+
+ def test_remote_smbclient(self, vm, username="${WIN_USER}", password="${WIN_PASS}", args=""):
+ '''test smbclient against remote server'''
+ self.setwinvars(vm)
+ self.info('Testing smbclient')
+ self.chdir('${PREFIX}')
+ smbclient = self.getvar("smbclient")
+ self.cmd_contains("%s --version" % (smbclient), ["${SAMBA_VERSION}"])
+ self.retry_cmd('%s -L ${WIN_HOSTNAME} -U%s%%%s %s' % (smbclient, username, password, args), ["IPC"], retries=60, delay=5)
+
+ def test_net_use(self, vm, realm, domain, username, password):
+ self.setwinvars(vm)
+ self.info('Testing net use against Samba3 member')
+ child = self.open_telnet("${WIN_HOSTNAME}", "%s\\%s" % (domain, username), password)
+ child.sendline("net use t: \\\\${HOSTNAME}.%s\\test" % realm)
+ child.expect("The command completed successfully")
+
+
+ def setup(self, testname, subdir):
+ '''setup for main tests, parsing command line'''
+ self.parser.add_option("--conf", type='string', default='', help='config file')
+ self.parser.add_option("--skip", type='string', default='', help='list of steps to skip (comma separated)')
+ self.parser.add_option("--vms", type='string', default=None, help='list of VMs to use (comma separated)')
+ self.parser.add_option("--list", action='store_true', default=False, help='list the available steps')
+ self.parser.add_option("--rebase", action='store_true', default=False, help='do a git pull --rebase')
+ self.parser.add_option("--clean", action='store_true', default=False, help='clean the tree')
+ self.parser.add_option("--prefix", type='string', default=None, help='override install prefix')
+ self.parser.add_option("--sourcetree", type='string', default=None, help='override sourcetree location')
+ self.parser.add_option("--nocleanup", action='store_true', default=False, help='disable cleanup code')
+ self.parser.add_option("--use-ntvfs", action='store_true', default=False, help='use NTVFS for the fileserver')
+ self.parser.add_option("--dns-backend", type="choice",
+ choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
+ help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), " \
+ "BIND9_FLATFILE uses bind9 text database to store zone information, " \
+ "BIND9_DLZ uses samba4 AD to store zone information, " \
+ "NONE skips the DNS setup entirely (not recommended)",
+ default="SAMBA_INTERNAL")
+
+ self.opts, self.args = self.parser.parse_args()
+
+ if not self.opts.conf:
+ print("Please specify a config file with --conf")
+ sys.exit(1)
+
+ # we don't need fsync safety in these tests
+ self.putenv('TDB_NO_FSYNC', '1')
+
+ self.load_config(self.opts.conf)
+
+ nameserver = self.get_nameserver()
+ if nameserver == self.getvar('NAMED_INTERFACE_IP'):
+ raise RuntimeError("old /etc/resolv.conf must not contain %s as a nameserver, this will create loops with the generated dns configuration" % nameserver)
+ self.setvar('DNSSERVER', nameserver)
+
+ self.set_skip(self.opts.skip)
+ self.set_vms(self.opts.vms)
+
+ if self.opts.list:
+ self.list_steps_mode()
+
+ if self.opts.prefix:
+ self.setvar('PREFIX', self.opts.prefix)
+
+ if self.opts.sourcetree:
+ self.setvar('SOURCETREE', self.opts.sourcetree)
+
+ if self.opts.rebase:
+ self.info('rebasing')
+ self.chdir('${SOURCETREE}')
+ self.run_cmd('git pull --rebase')
+
+ if self.opts.clean:
+ self.info('cleaning')
+ self.chdir('${SOURCETREE}/' + subdir)
+ self.run_cmd('make clean')
+
+ if self.opts.use_ntvfs:
+ self.setvar('USE_NTVFS', "--use-ntvfs")
+ else:
+ self.setvar('USE_NTVFS', "")
+
+ self.setvar('NAMESERVER_BACKEND', self.opts.dns_backend)
+
+ self.setvar('DNS_FORWARDER', "--option=dns forwarder=%s" % nameserver)