3 '''automated testing library for testing Samba against windows'''
5 import pexpect
, subprocess
7 import sys
, os
, time
, re
10 '''testing of Samba against windows VMs'''
14 self
.list_mode
= False
16 os
.putenv('PYTHONUNBUFFERED', '1')
17 self
.parser
= optparse
.OptionParser("wintest")
19 def check_prerequesites(self
):
20 self
.info("Checking prerequesites")
21 self
.setvar('HOSTNAME', self
.cmd_output("hostname -s").strip())
23 raise Exception("You must run this script as root")
24 self
.run_cmd('ifconfig ${INTERFACE} ${INTERFACE_NET} up')
25 if self
.getvar('INTERFACE_IPV6'):
26 self
.run_cmd('ifconfig ${INTERFACE} inet6 del ${INTERFACE_IPV6}/64', checkfail
=False)
27 self
.run_cmd('ifconfig ${INTERFACE} inet6 add ${INTERFACE_IPV6}/64 up')
30 '''Shut down any existing alive VMs, so they do not collide with what we are doing'''
31 self
.info('Shutting down any of our VMs already running')
34 self
.vm_poweroff(v
, checkfail
=False)
36 def setvar(self
, varname
, value
):
37 '''set a substitution variable'''
38 self
.vars[varname
] = value
40 def getvar(self
, varname
):
41 '''return a substitution variable'''
42 if not varname
in self
.vars:
44 return self
.vars[varname
]
46 def setwinvars(self
, vm
, prefix
='WIN'):
47 '''setup WIN_XX vars based on a vm name'''
48 for v
in ['VM', 'HOSTNAME', 'USER', 'PASS', 'SNAPSHOT', 'REALM', 'DOMAIN', 'IP']:
49 vname
= '%s_%s' % (vm
, v
)
50 if vname
in self
.vars:
51 self
.setvar("%s_%s" % (prefix
,v
), self
.substitute("${%s}" % vname
))
53 self
.vars.pop("%s_%s" % (prefix
,v
), None)
55 if self
.getvar("WIN_REALM"):
56 self
.setvar("WIN_REALM", self
.getvar("WIN_REALM").upper())
57 self
.setvar("WIN_LCREALM", self
.getvar("WIN_REALM").lower())
58 dnsdomain
= self
.getvar("WIN_REALM")
59 self
.setvar("WIN_BASEDN", "DC=" + dnsdomain
.replace(".", ",DC="))
60 if self
.getvar("WIN_USER") is None:
61 self
.setvar("WIN_USER", "administrator")
64 '''print some information'''
65 if not self
.list_mode
:
66 print(self
.substitute(msg
))
68 def load_config(self
, fname
):
69 '''load the config file'''
73 if len(line
) == 0 or line
[0] == '#':
75 colon
= line
.find(':')
77 raise RuntimeError("Invalid config line '%s'" % line
)
78 varname
= line
[0:colon
].strip()
79 value
= line
[colon
+1:].strip()
80 self
.setvar(varname
, value
)
82 def list_steps_mode(self
):
83 '''put wintest in step listing mode'''
86 def set_skip(self
, skiplist
):
87 '''set a list of tests to skip'''
88 self
.skiplist
= skiplist
.split(',')
90 def set_vms(self
, vms
):
91 '''set a list of VMs to test'''
93 self
.vms
= vms
.split(',')
96 '''return True if we should skip a step'''
100 return step
in self
.skiplist
102 def substitute(self
, text
):
103 """Substitute strings of the form ${NAME} in text, replacing
104 with substitutions from vars.
106 if isinstance(text
, list):
108 for i
in range(len(ret
)):
109 ret
[i
] = self
.substitute(ret
[i
])
112 """We may have objects such as pexpect.EOF that are not strings"""
113 if not isinstance(text
, str):
116 var_start
= text
.find("${")
119 var_end
= text
.find("}", var_start
)
122 var_name
= text
[var_start
+2:var_end
]
123 if not var_name
in self
.vars:
124 raise RuntimeError("Unknown substitution variable ${%s}" % var_name
)
125 text
= text
.replace("${%s}" % var_name
, self
.vars[var_name
])
128 def have_var(self
, varname
):
129 '''see if a variable has been set'''
130 return varname
in self
.vars
132 def have_vm(self
, vmname
):
133 '''see if a VM should be used'''
134 if not self
.have_var(vmname
+ '_VM'):
138 return vmname
in self
.vms
140 def putenv(self
, key
, value
):
141 '''putenv with substitution'''
142 os
.putenv(key
, self
.substitute(value
))
144 def chdir(self
, dir):
145 '''chdir with substitution'''
146 os
.chdir(self
.substitute(dir))
148 def del_files(self
, dirs
):
149 '''delete all files in the given directory'''
151 self
.run_cmd("find %s -type f | xargs rm -f" % d
)
153 def write_file(self
, filename
, text
, mode
='w'):
154 '''write to a file'''
155 f
= open(self
.substitute(filename
), mode
=mode
)
156 f
.write(self
.substitute(text
))
159 def run_cmd(self
, cmd
, dir=".", show
=None, output
=False, checkfail
=True):
161 cmd
= self
.substitute(cmd
)
162 if isinstance(cmd
, list):
163 self
.info('$ ' + " ".join(cmd
))
165 self
.info('$ ' + cmd
)
167 return subprocess
.Popen([cmd
], shell
=True, stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
, cwd
=dir).communicate()[0]
168 if isinstance(cmd
, list):
173 return subprocess
.check_call(cmd
, shell
=shell
, cwd
=dir)
175 return subprocess
.call(cmd
, shell
=shell
, cwd
=dir)
178 def run_child(self
, cmd
, dir="."):
179 '''create a child and return the Popen handle to it'''
181 cmd
= self
.substitute(cmd
)
182 if isinstance(cmd
, list):
183 self
.info('$ ' + " ".join(cmd
))
185 self
.info('$ ' + cmd
)
186 if isinstance(cmd
, list):
191 ret
= subprocess
.Popen(cmd
, shell
=shell
, stderr
=subprocess
.STDOUT
)
195 def cmd_output(self
, cmd
):
196 '''return output from and command'''
197 cmd
= self
.substitute(cmd
)
198 return self
.run_cmd(cmd
, output
=True)
200 def cmd_contains(self
, cmd
, contains
, nomatch
=False, ordered
=False, regex
=False,
202 '''check that command output contains the listed strings'''
204 if isinstance(contains
, str):
205 contains
= [contains
]
207 out
= self
.cmd_output(cmd
)
209 for c
in self
.substitute(contains
):
214 m
= re
.search(c
, out
)
222 start
= out
.upper().find(c
.upper())
229 raise RuntimeError("Expected to not see %s in %s" % (c
, cmd
))
232 raise RuntimeError("Expected to see %s in %s" % (c
, cmd
))
233 if ordered
and start
!= -1:
236 def retry_cmd(self
, cmd
, contains
, retries
=30, delay
=2, wait_for_fail
=False,
237 ordered
=False, regex
=False, casefold
=True):
238 '''retry a command a number of times'''
241 self
.cmd_contains(cmd
, contains
, nomatch
=wait_for_fail
,
242 ordered
=ordered
, regex
=regex
, casefold
=casefold
)
247 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
248 raise RuntimeError("Failed to find %s" % contains
)
250 def pexpect_spawn(self
, cmd
, timeout
=60, crlf
=True, casefold
=True):
251 '''wrapper around pexpect spawn'''
252 cmd
= self
.substitute(cmd
)
253 self
.info("$ " + cmd
)
254 ret
= pexpect
.spawn(cmd
, logfile
=sys
.stdout
, timeout
=timeout
)
256 def sendline_sub(line
):
257 line
= self
.substitute(line
)
259 line
= line
.replace('\n', '\r\n') + '\r'
260 return ret
.old_sendline(line
)
262 def expect_sub(line
, timeout
=ret
.timeout
, casefold
=casefold
):
263 line
= self
.substitute(line
)
265 if isinstance(line
, list):
266 for i
in range(len(line
)):
267 if isinstance(line
[i
], str):
268 line
[i
] = '(?i)' + line
[i
]
269 elif isinstance(line
, str):
271 return ret
.old_expect(line
, timeout
=timeout
)
273 ret
.old_sendline
= ret
.sendline
274 ret
.sendline
= sendline_sub
275 ret
.old_expect
= ret
.expect
276 ret
.expect
= expect_sub
280 def get_nameserver(self
):
281 '''Get the current nameserver from /etc/resolv.conf'''
282 child
= self
.pexpect_spawn('cat /etc/resolv.conf', crlf
=False)
283 i
= child
.expect(['Generated by wintest', 'nameserver'])
285 child
.expect('your original resolv.conf')
286 child
.expect('nameserver')
287 child
.expect('\d+.\d+.\d+.\d+')
290 def rndc_cmd(self
, cmd
, checkfail
=True):
291 '''run a rndc command'''
292 self
.run_cmd("${RNDC} -c ${PREFIX}/etc/rndc.conf %s" % cmd
, checkfail
=checkfail
)
294 def named_supports_gssapi_keytab(self
):
295 '''see if named supports tkey-gssapi-keytab'''
296 self
.write_file("${PREFIX}/named.conf.test",
297 'options { tkey-gssapi-keytab "test"; };')
299 self
.run_cmd("${NAMED_CHECKCONF} ${PREFIX}/named.conf.test")
300 except subprocess
.CalledProcessError
:
304 def set_nameserver(self
, nameserver
):
305 '''set the nameserver in resolv.conf'''
306 self
.write_file("/etc/resolv.conf.wintest", '''
307 # Generated by wintest, the Samba v Windows automated testing system
310 # your original resolv.conf appears below:
311 ''' % self
.substitute(nameserver
))
312 child
= self
.pexpect_spawn("cat /etc/resolv.conf", crlf
=False)
313 i
= child
.expect(['your original resolv.conf appears below:', pexpect
.EOF
])
315 child
.expect(pexpect
.EOF
)
316 contents
= child
.before
.lstrip().replace('\r', '')
317 self
.write_file('/etc/resolv.conf.wintest', contents
, mode
='a')
318 self
.write_file('/etc/resolv.conf.wintest-bak', contents
)
319 self
.run_cmd("mv -f /etc/resolv.conf.wintest /etc/resolv.conf")
320 self
.resolv_conf_backup
= '/etc/resolv.conf.wintest-bak';
322 def configure_bind(self
, kerberos_support
=False, include
=None):
323 self
.chdir('${PREFIX}')
325 nameserver
= self
.get_nameserver()
326 if nameserver
== self
.getvar('INTERFACE_IP'):
327 raise RuntimeError("old /etc/resolv.conf must not contain %s as a nameserver, this will create loops with the generated dns configuration" % nameserver
)
328 self
.setvar('DNSSERVER', nameserver
)
330 if self
.getvar('INTERFACE_IPV6'):
331 ipv6_listen
= 'listen-on-v6 port 53 { ${INTERFACE_IPV6}; };'
334 self
.setvar('BIND_LISTEN_IPV6', ipv6_listen
)
336 if not kerberos_support
:
337 self
.setvar("NAMED_TKEY_OPTION", "")
339 if self
.named_supports_gssapi_keytab():
340 self
.setvar("NAMED_TKEY_OPTION",
341 'tkey-gssapi-keytab "${PREFIX}/private/dns.keytab";')
343 self
.info("LCREALM=${LCREALM}")
344 self
.setvar("NAMED_TKEY_OPTION",
345 '''tkey-gssapi-credential "DNS/${LCREALM}";
346 tkey-domain "${LCREALM}";
348 self
.putenv('KEYTAB_FILE', '${PREFIX}/private/dns.keytab')
349 self
.putenv('KRB5_KTNAME', '${PREFIX}/private/dns.keytab')
352 self
.setvar("NAMED_INCLUDE", 'include "%s";' % include
)
354 self
.setvar("NAMED_INCLUDE", '')
356 self
.run_cmd("mkdir -p ${PREFIX}/etc")
358 self
.write_file("etc/named.conf", '''
360 listen-on port 53 { ${INTERFACE_IP}; };
362 directory "${PREFIX}/var/named";
363 dump-file "${PREFIX}/var/named/data/cache_dump.db";
364 pid-file "${PREFIX}/var/named/named.pid";
365 statistics-file "${PREFIX}/var/named/data/named_stats.txt";
366 memstatistics-file "${PREFIX}/var/named/data/named_mem_stats.txt";
367 allow-query { any; };
382 secret "lA/cTrno03mt5Ju17ybEYw==";
386 inet ${INTERFACE_IP} port 953
387 allow { any; } keys { "rndc-key"; };
393 # add forwarding for the windows domains
394 domains
= self
.get_domains()
396 self
.write_file('etc/named.conf',
405 ''' % (d
, domains
[d
]),
409 self
.write_file("etc/rndc.conf", '''
413 secret "lA/cTrno03mt5Ju17ybEYw==";
417 default-key "rndc-key";
418 default-server ${INTERFACE_IP};
425 '''Stop our private BIND from listening and operating'''
426 self
.rndc_cmd("stop", checkfail
=False)
427 self
.port_wait("${INTERFACE_IP}", 53, wait_for_fail
=True)
429 self
.run_cmd("rm -rf var/named")
432 def start_bind(self
):
433 '''restart the test environment version of bind'''
434 self
.info("Restarting bind9")
435 self
.chdir('${PREFIX}')
437 self
.set_nameserver(self
.getvar('INTERFACE_IP'))
439 self
.run_cmd("mkdir -p var/named/data")
440 self
.run_cmd("chown -R ${BIND_USER} var/named")
442 self
.bind_child
= self
.run_child("${BIND9} -u ${BIND_USER} -n 1 -c ${PREFIX}/etc/named.conf -g")
444 self
.port_wait("${INTERFACE_IP}", 53)
445 self
.rndc_cmd("flush")
447 def restart_bind(self
, kerberos_support
=False, include
=None):
448 self
.configure_bind(keberos_support
=kerberos_support
, include
=include
)
452 def restore_resolv_conf(self
):
453 '''restore the /etc/resolv.conf after testing is complete'''
454 if getattr(self
, 'resolv_conf_backup', False):
455 self
.info("restoring /etc/resolv.conf")
456 self
.run_cmd("mv -f %s /etc/resolv.conf" % self
.resolv_conf_backup
)
459 def vm_poweroff(self
, vmname
, checkfail
=True):
461 self
.setvar('VMNAME', vmname
)
462 self
.run_cmd("${VM_POWEROFF}", checkfail
=checkfail
)
464 def vm_reset(self
, vmname
):
466 self
.setvar('VMNAME', vmname
)
467 self
.run_cmd("${VM_RESET}")
469 def vm_restore(self
, vmname
, snapshot
):
471 self
.setvar('VMNAME', vmname
)
472 self
.setvar('SNAPSHOT', snapshot
)
473 self
.run_cmd("${VM_RESTORE}")
475 def ping_wait(self
, hostname
):
476 '''wait for a hostname to come up on the network'''
477 hostname
= self
.substitute(hostname
)
481 self
.run_cmd("ping -c 1 -w 10 %s" % hostname
)
486 raise RuntimeError("Failed to ping %s" % hostname
)
487 self
.info("Host %s is up" % hostname
)
489 def port_wait(self
, hostname
, port
, retries
=200, delay
=3, wait_for_fail
=False):
490 '''wait for a host to come up on the network'''
491 self
.retry_cmd("nc -v -z -w 1 %s %u" % (hostname
, port
), ['succeeded'],
492 retries
=retries
, delay
=delay
, wait_for_fail
=wait_for_fail
)
494 def run_net_time(self
, child
):
495 '''run net time on windows'''
496 child
.sendline("net time \\\\${HOSTNAME} /set")
497 child
.expect("Do you want to set the local computer")
499 child
.expect("The command completed successfully")
501 def run_date_time(self
, child
, time_tuple
=None):
502 '''run date and time on windows'''
503 if time_tuple
is None:
504 time_tuple
= time
.localtime()
505 child
.sendline("date")
506 child
.expect("Enter the new date:")
507 i
= child
.expect(["dd-mm-yy", "mm-dd-yy"])
509 child
.sendline(time
.strftime("%d-%m-%y", time_tuple
))
511 child
.sendline(time
.strftime("%m-%d-%y", time_tuple
))
513 child
.sendline("time")
514 child
.expect("Enter the new time:")
515 child
.sendline(time
.strftime("%H:%M:%S", time_tuple
))
518 def get_ipconfig(self
, child
):
519 '''get the IP configuration of the child'''
520 child
.sendline("ipconfig /all")
521 child
.expect('Ethernet adapter ')
522 child
.expect("[\w\s]+")
523 self
.setvar("WIN_NIC", child
.after
)
524 child
.expect(['IPv4 Address', 'IP Address'])
525 child
.expect('\d+.\d+.\d+.\d+')
526 self
.setvar('WIN_IPV4_ADDRESS', child
.after
)
527 child
.expect('Subnet Mask')
528 child
.expect('\d+.\d+.\d+.\d+')
529 self
.setvar('WIN_SUBNET_MASK', child
.after
)
530 child
.expect('Default Gateway')
531 child
.expect('\d+.\d+.\d+.\d+')
532 self
.setvar('WIN_DEFAULT_GATEWAY', child
.after
)
535 def get_is_dc(self
, child
):
536 '''check if a windows machine is a domain controller'''
537 child
.sendline("dcdiag")
538 i
= child
.expect(["is not a Directory Server",
539 "is not recognized as an internal or external command",
541 "passed test Replications"])
546 child
.sendline("net config Workstation")
547 child
.expect("Workstation domain")
548 child
.expect('[\S]+')
550 i
= child
.expect(["Workstation Domain DNS Name", "Logon domain"])
551 '''If we get the Logon domain first, we are not in an AD domain'''
554 if domain
.upper() == self
.getvar("WIN_DOMAIN").upper():
557 child
.expect('[\S]+')
558 hostname
= child
.after
559 if hostname
.upper() == self
.getvar("WIN_HOSTNAME").upper():
562 def set_noexpire(self
, child
, username
):
563 '''Ensure this user's password does not expire'''
564 child
.sendline('wmic useraccount where name="%s" set PasswordExpires=FALSE' % username
)
565 child
.expect("update successful")
568 def run_tlntadmn(self
, child
):
569 '''remove the annoying telnet restrictions'''
570 child
.sendline('tlntadmn config maxconn=1024')
571 child
.expect("The settings were successfully updated")
574 def disable_firewall(self
, child
):
575 '''remove the annoying firewall'''
576 child
.sendline('netsh advfirewall set allprofiles state off')
577 i
= child
.expect(["Ok", "The following command was not found: advfirewall set allprofiles state off"])
580 child
.sendline('netsh firewall set opmode mode = DISABLE profile = ALL')
581 i
= child
.expect(["Ok", "The following command was not found"])
583 self
.info("Firewall disable failed - ignoring")
586 def set_dns(self
, child
):
587 child
.sendline('netsh interface ip set dns "${WIN_NIC}" static ${INTERFACE_IP} primary')
588 i
= child
.expect(['C:', pexpect
.EOF
, pexpect
.TIMEOUT
], timeout
=5)
594 def set_ip(self
, child
):
595 """fix the IP address to the same value it had when we
596 connected, but don't use DHCP, and force the DNS server to our
597 DNS server. This allows DNS updates to run"""
598 self
.get_ipconfig(child
)
599 if self
.getvar("WIN_IPV4_ADDRESS") != self
.getvar("WIN_IP"):
600 raise RuntimeError("ipconfig address %s != nmblookup address %s" % (self
.getvar("WIN_IPV4_ADDRESS"),
601 self
.getvar("WIN_IP")))
602 child
.sendline('netsh')
603 child
.expect('netsh>')
604 child
.sendline('offline')
605 child
.expect('netsh>')
606 child
.sendline('routing ip add persistentroute dest=0.0.0.0 mask=0.0.0.0 name="${WIN_NIC}" nhop=${WIN_DEFAULT_GATEWAY}')
607 child
.expect('netsh>')
608 child
.sendline('interface ip set address "${WIN_NIC}" static ${WIN_IPV4_ADDRESS} ${WIN_SUBNET_MASK} ${WIN_DEFAULT_GATEWAY} 1 store=persistent')
609 i
= child
.expect(['The syntax supplied for this command is not valid. Check help for the correct syntax', 'netsh>', pexpect
.EOF
, pexpect
.TIMEOUT
], timeout
=5)
611 child
.sendline('interface ip set address "${WIN_NIC}" static ${WIN_IPV4_ADDRESS} ${WIN_SUBNET_MASK} ${WIN_DEFAULT_GATEWAY} 1')
612 child
.expect('netsh>')
613 child
.sendline('commit')
614 child
.sendline('online')
615 child
.sendline('exit')
617 child
.expect([pexpect
.EOF
, pexpect
.TIMEOUT
], timeout
=5)
621 def resolve_ip(self
, hostname
, retries
=60, delay
=5):
622 '''resolve an IP given a hostname, assuming NBT'''
624 child
= self
.pexpect_spawn("bin/nmblookup %s" % hostname
)
627 i
= child
.expect(["querying", '\d+.\d+.\d+.\d+', hostname
, "Lookup failed"])
634 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
635 raise RuntimeError("Failed to resolve IP of %s" % hostname
)
638 def open_telnet(self
, hostname
, username
, password
, retries
=60, delay
=5, set_time
=False, set_ip
=False,
639 disable_firewall
=True, run_tlntadmn
=True, set_noexpire
=False):
640 '''open a telnet connection to a windows server, return the pexpect child'''
643 if self
.getvar('WIN_IP'):
644 ip
= self
.getvar('WIN_IP')
646 ip
= self
.resolve_ip(hostname
)
647 self
.setvar('WIN_IP', ip
)
649 child
= self
.pexpect_spawn("telnet " + ip
+ " -l '" + username
+ "'")
650 i
= child
.expect(["Welcome to Microsoft Telnet Service",
651 "Denying new connections due to the limit on number of connections",
652 "No more connections are allowed to telnet server",
653 "Unable to connect to remote host",
655 "Connection refused",
661 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
663 child
.expect("password:")
664 child
.sendline(password
)
665 i
= child
.expect(["C:",
666 "Denying new connections due to the limit on number of connections",
667 "No more connections are allowed to telnet server",
668 "Unable to connect to remote host",
670 "Connection refused",
676 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
680 if self
.set_dns(child
):
683 child
.sendline('route add 0.0.0.0 mask 0.0.0.0 ${WIN_DEFAULT_GATEWAY}')
687 self
.run_date_time(child
, None)
690 self
.run_tlntadmn(child
)
693 self
.set_noexpire(child
, username
)
696 self
.disable_firewall(child
)
697 disable_firewall
= False
700 if self
.set_ip(child
):
705 raise RuntimeError("Failed to connect with telnet")
707 def kinit(self
, username
, password
):
708 '''use kinit to setup a credentials cache'''
709 self
.run_cmd("kdestroy")
710 self
.putenv('KRB5CCNAME', "${PREFIX}/ccache.test")
711 username
= self
.substitute(username
)
712 s
= username
.split('@')
715 username
= '@'.join(s
)
716 child
= self
.pexpect_spawn('kinit ' + username
)
717 child
.expect("Password")
718 child
.sendline(password
)
719 child
.expect(pexpect
.EOF
)
721 if child
.exitstatus
!= 0:
722 raise RuntimeError("kinit failed with status %d" % child
.exitstatus
)
724 def get_domains(self
):
725 '''return a dictionary of DNS domains and IPs for named.conf'''
728 if v
[-6:] == "_REALM":
730 if base
+ '_IP' in self
.vars:
731 ret
[self
.vars[base
+ '_REALM']] = self
.vars[base
+ '_IP']
734 def wait_reboot(self
, retries
=3):
735 '''wait for a VM to reboot'''
737 # first wait for it to shutdown
738 self
.port_wait("${WIN_IP}", 139, wait_for_fail
=True, delay
=6)
740 # now wait for it to come back. If it fails to come back
741 # then try resetting it
744 self
.port_wait("${WIN_IP}", 139)
748 self
.vm_reset("${WIN_VM}")
749 self
.info("retrying reboot (retries=%u)" % retries
)
750 raise RuntimeError(self
.substitute("VM ${WIN_VM} failed to reboot"))
753 '''return a dictionary of all the configured VM names'''
757 ret
.append(self
.vars[v
])
761 def run_dcpromo_as_first_dc(self
, vm
, func_level
=None):
763 self
.info("Configuring a windows VM ${WIN_VM} at the first DC in the domain using dcpromo")
764 child
= self
.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_time
=True)
765 if self
.get_is_dc(child
):
768 if func_level
== '2008r2':
769 self
.setvar("FUNCTION_LEVEL_INT", str(4))
770 elif func_level
== '2003':
771 self
.setvar("FUNCTION_LEVEL_INT", str(1))
773 self
.setvar("FUNCTION_LEVEL_INT", str(0))
775 child
= self
.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip
=True, set_noexpire
=True)
777 """This server must therefore not yet be a directory server, so we must promote it"""
778 child
.sendline("copy /Y con answers.txt")
781 ; New forest promotion
782 ReplicaOrNewDomain=Domain
784 NewDomainDNSName=${WIN_REALM}
785 ForestLevel=${FUNCTION_LEVEL_INT}
786 DomainNetbiosName=${WIN_DOMAIN}
787 DomainLevel=${FUNCTION_LEVEL_INT}
790 CreateDNSDelegation=No
791 DatabasePath="C:\Windows\NTDS"
792 LogPath="C:\Windows\NTDS"
793 SYSVOLPath="C:\Windows\SYSVOL"
794 ; Set SafeModeAdminPassword to the correct value prior to using the unattend file
795 SafeModeAdminPassword=${WIN_PASS}
796 ; Run-time flags (optional)
797 RebootOnCompletion=No
800 child
.expect("copied.")
803 child
.sendline("dcpromo /answer:answers.txt")
804 i
= child
.expect(["You must restart this computer", "failed", "Active Directory Domain Services was not installed", "C:"], timeout
=240)
806 raise Exception("dcpromo failed")
807 child
.sendline("shutdown -r -t 0")
808 self
.port_wait("${WIN_IP}", 139, wait_for_fail
=True)
809 self
.port_wait("${WIN_IP}", 139)
810 self
.retry_cmd("host -t SRV _ldap._tcp.${WIN_REALM} ${WIN_IP}", ['has SRV record'] )
813 def start_winvm(self
, vm
):
814 '''start a Windows VM'''
817 self
.info("Joining a windows box to the domain")
818 self
.vm_poweroff("${WIN_VM}", checkfail
=False)
819 self
.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
821 def run_winjoin(self
, vm
, domain
, username
="administrator", password
="${PASSWORD1}"):
822 '''join a windows box to a domain'''
823 child
= self
.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time
=True, set_ip
=True, set_noexpire
=True)
824 child
.sendline("ipconfig /flushdns")
826 child
.sendline("netdom join ${WIN_HOSTNAME} /Domain:%s /UserD:%s /PasswordD:%s" % (domain
, username
, password
))
827 child
.expect("The command completed successfully")
829 child
.sendline("shutdown /r -t 0")
831 child
= self
.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time
=True, set_ip
=True)
832 child
.sendline("ipconfig /registerdns")
833 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")
837 def test_remote_smbclient(self
, vm
, username
="${WIN_USER}", password
="${WIN_PASS}", args
=""):
838 '''test smbclient against remote server'''
840 self
.info('Testing smbclient')
841 self
.chdir('${PREFIX}')
842 self
.cmd_contains("bin/smbclient --version", ["${SAMBA_VERSION}"])
843 self
.retry_cmd('bin/smbclient -L ${WIN_HOSTNAME} -U%s%%%s %s' % (username
, password
, args
), ["IPC"])
846 def setup(self
, testname
, subdir
):
847 '''setup for main tests, parsing command line'''
848 self
.parser
.add_option("--conf", type='string', default
='', help='config file')
849 self
.parser
.add_option("--skip", type='string', default
='', help='list of steps to skip (comma separated)')
850 self
.parser
.add_option("--vms", type='string', default
=None, help='list of VMs to use (comma separated)')
851 self
.parser
.add_option("--list", action
='store_true', default
=False, help='list the available steps')
852 self
.parser
.add_option("--rebase", action
='store_true', default
=False, help='do a git pull --rebase')
853 self
.parser
.add_option("--clean", action
='store_true', default
=False, help='clean the tree')
854 self
.parser
.add_option("--prefix", type='string', default
=None, help='override install prefix')
855 self
.parser
.add_option("--sourcetree", type='string', default
=None, help='override sourcetree location')
856 self
.parser
.add_option("--nocleanup", action
='store_true', default
=False, help='disable cleanup code')
858 self
.opts
, self
.args
= self
.parser
.parse_args()
860 if not self
.opts
.conf
:
861 print("Please specify a config file with --conf")
864 # we don't need fsync safety in these tests
865 self
.putenv('TDB_NO_FSYNC', '1')
867 self
.load_config(self
.opts
.conf
)
869 self
.set_skip(self
.opts
.skip
)
870 self
.set_vms(self
.opts
.vms
)
873 self
.list_steps_mode()
876 self
.setvar('PREFIX', self
.opts
.prefix
)
878 if self
.opts
.sourcetree
:
879 self
.setvar('SOURCETREE', self
.opts
.sourcetree
)
882 self
.info('rebasing')
883 self
.chdir('${SOURCETREE}')
884 self
.run_cmd('git pull --rebase')
887 self
.info('cleaning')
888 self
.chdir('${SOURCETREE}/' + subdir
)
889 self
.run_cmd('make clean')