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="))
62 '''print some information'''
63 if not self
.list_mode
:
64 print(self
.substitute(msg
))
66 def load_config(self
, fname
):
67 '''load the config file'''
71 if len(line
) == 0 or line
[0] == '#':
73 colon
= line
.find(':')
75 raise RuntimeError("Invalid config line '%s'" % line
)
76 varname
= line
[0:colon
].strip()
77 value
= line
[colon
+1:].strip()
78 self
.setvar(varname
, value
)
80 def list_steps_mode(self
):
81 '''put wintest in step listing mode'''
84 def set_skip(self
, skiplist
):
85 '''set a list of tests to skip'''
86 self
.skiplist
= skiplist
.split(',')
88 def set_vms(self
, vms
):
89 '''set a list of VMs to test'''
91 self
.vms
= vms
.split(',')
94 '''return True if we should skip a step'''
98 return step
in self
.skiplist
100 def substitute(self
, text
):
101 """Substitute strings of the form ${NAME} in text, replacing
102 with substitutions from vars.
104 if isinstance(text
, list):
106 for i
in range(len(ret
)):
107 ret
[i
] = self
.substitute(ret
[i
])
110 """We may have objects such as pexpect.EOF that are not strings"""
111 if not isinstance(text
, str):
114 var_start
= text
.find("${")
117 var_end
= text
.find("}", var_start
)
120 var_name
= text
[var_start
+2:var_end
]
121 if not var_name
in self
.vars:
122 raise RuntimeError("Unknown substitution variable ${%s}" % var_name
)
123 text
= text
.replace("${%s}" % var_name
, self
.vars[var_name
])
126 def have_var(self
, varname
):
127 '''see if a variable has been set'''
128 return varname
in self
.vars
130 def have_vm(self
, vmname
):
131 '''see if a VM should be used'''
132 if not self
.have_var(vmname
+ '_VM'):
136 return vmname
in self
.vms
138 def putenv(self
, key
, value
):
139 '''putenv with substitution'''
140 os
.putenv(key
, self
.substitute(value
))
142 def chdir(self
, dir):
143 '''chdir with substitution'''
144 os
.chdir(self
.substitute(dir))
146 def del_files(self
, dirs
):
147 '''delete all files in the given directory'''
149 self
.run_cmd("find %s -type f | xargs rm -f" % d
)
151 def write_file(self
, filename
, text
, mode
='w'):
152 '''write to a file'''
153 f
= open(self
.substitute(filename
), mode
=mode
)
154 f
.write(self
.substitute(text
))
157 def run_cmd(self
, cmd
, dir=".", show
=None, output
=False, checkfail
=True):
159 cmd
= self
.substitute(cmd
)
160 if isinstance(cmd
, list):
161 self
.info('$ ' + " ".join(cmd
))
163 self
.info('$ ' + cmd
)
165 return subprocess
.Popen([cmd
], shell
=True, stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
, cwd
=dir).communicate()[0]
166 if isinstance(cmd
, list):
171 return subprocess
.check_call(cmd
, shell
=shell
, cwd
=dir)
173 return subprocess
.call(cmd
, shell
=shell
, cwd
=dir)
176 def run_child(self
, cmd
, dir="."):
177 '''create a child and return the Popen handle to it'''
179 cmd
= self
.substitute(cmd
)
180 if isinstance(cmd
, list):
181 self
.info('$ ' + " ".join(cmd
))
183 self
.info('$ ' + cmd
)
184 if isinstance(cmd
, list):
189 ret
= subprocess
.Popen(cmd
, shell
=shell
, stderr
=subprocess
.STDOUT
)
193 def cmd_output(self
, cmd
):
194 '''return output from and command'''
195 cmd
= self
.substitute(cmd
)
196 return self
.run_cmd(cmd
, output
=True)
198 def cmd_contains(self
, cmd
, contains
, nomatch
=False, ordered
=False, regex
=False,
200 '''check that command output contains the listed strings'''
202 if isinstance(contains
, str):
203 contains
= [contains
]
205 out
= self
.cmd_output(cmd
)
207 for c
in self
.substitute(contains
):
212 m
= re
.search(c
, out
)
220 start
= out
.upper().find(c
.upper())
227 raise RuntimeError("Expected to not see %s in %s" % (c
, cmd
))
230 raise RuntimeError("Expected to see %s in %s" % (c
, cmd
))
231 if ordered
and start
!= -1:
234 def retry_cmd(self
, cmd
, contains
, retries
=30, delay
=2, wait_for_fail
=False,
235 ordered
=False, regex
=False, casefold
=True):
236 '''retry a command a number of times'''
239 self
.cmd_contains(cmd
, contains
, nomatch
=wait_for_fail
,
240 ordered
=ordered
, regex
=regex
, casefold
=casefold
)
245 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
246 raise RuntimeError("Failed to find %s" % contains
)
248 def pexpect_spawn(self
, cmd
, timeout
=60, crlf
=True, casefold
=True):
249 '''wrapper around pexpect spawn'''
250 cmd
= self
.substitute(cmd
)
251 self
.info("$ " + cmd
)
252 ret
= pexpect
.spawn(cmd
, logfile
=sys
.stdout
, timeout
=timeout
)
254 def sendline_sub(line
):
255 line
= self
.substitute(line
)
257 line
= line
.replace('\n', '\r\n') + '\r'
258 return ret
.old_sendline(line
)
260 def expect_sub(line
, timeout
=ret
.timeout
, casefold
=casefold
):
261 line
= self
.substitute(line
)
263 if isinstance(line
, list):
264 for i
in range(len(line
)):
265 if isinstance(line
[i
], str):
266 line
[i
] = '(?i)' + line
[i
]
267 elif isinstance(line
, str):
269 return ret
.old_expect(line
, timeout
=timeout
)
271 ret
.old_sendline
= ret
.sendline
272 ret
.sendline
= sendline_sub
273 ret
.old_expect
= ret
.expect
274 ret
.expect
= expect_sub
278 def get_nameserver(self
):
279 '''Get the current nameserver from /etc/resolv.conf'''
280 child
= self
.pexpect_spawn('cat /etc/resolv.conf', crlf
=False)
281 i
= child
.expect(['Generated by wintest', 'nameserver'])
283 child
.expect('your original resolv.conf')
284 child
.expect('nameserver')
285 child
.expect('\d+.\d+.\d+.\d+')
288 def rndc_cmd(self
, cmd
, checkfail
=True):
289 '''run a rndc command'''
290 self
.run_cmd("${RNDC} -c ${PREFIX}/etc/rndc.conf %s" % cmd
, checkfail
=checkfail
)
292 def named_supports_gssapi_keytab(self
):
293 '''see if named supports tkey-gssapi-keytab'''
294 self
.write_file("${PREFIX}/named.conf.test",
295 'options { tkey-gssapi-keytab "test"; };')
297 self
.run_cmd("${NAMED_CHECKCONF} ${PREFIX}/named.conf.test")
298 except subprocess
.CalledProcessError
:
302 def set_nameserver(self
, nameserver
):
303 '''set the nameserver in resolv.conf'''
304 self
.write_file("/etc/resolv.conf.wintest", '''
305 # Generated by wintest, the Samba v Windows automated testing system
308 # your original resolv.conf appears below:
309 ''' % self
.substitute(nameserver
))
310 child
= self
.pexpect_spawn("cat /etc/resolv.conf", crlf
=False)
311 i
= child
.expect(['your original resolv.conf appears below:', pexpect
.EOF
])
313 child
.expect(pexpect
.EOF
)
314 contents
= child
.before
.lstrip().replace('\r', '')
315 self
.write_file('/etc/resolv.conf.wintest', contents
, mode
='a')
316 self
.write_file('/etc/resolv.conf.wintest-bak', contents
)
317 self
.run_cmd("mv -f /etc/resolv.conf.wintest /etc/resolv.conf")
318 self
.resolv_conf_backup
= '/etc/resolv.conf.wintest-bak';
320 def configure_bind(self
, kerberos_support
=False, include
=None):
321 self
.chdir('${PREFIX}')
323 nameserver
= self
.get_nameserver()
324 if nameserver
== self
.getvar('INTERFACE_IP'):
325 raise RuntimeError("old /etc/resolv.conf must not contain %s as a nameserver, this will create loops with the generated dns configuration" % nameserver
)
326 self
.setvar('DNSSERVER', nameserver
)
328 if self
.getvar('INTERFACE_IPV6'):
329 ipv6_listen
= 'listen-on-v6 port 53 { ${INTERFACE_IPV6}; };'
332 self
.setvar('BIND_LISTEN_IPV6', ipv6_listen
)
334 if not kerberos_support
:
335 self
.setvar("NAMED_TKEY_OPTION", "")
337 if self
.named_supports_gssapi_keytab():
338 self
.setvar("NAMED_TKEY_OPTION",
339 'tkey-gssapi-keytab "${PREFIX}/private/dns.keytab";')
341 self
.info("LCREALM=${LCREALM}")
342 self
.setvar("NAMED_TKEY_OPTION",
343 '''tkey-gssapi-credential "DNS/${LCREALM}";
344 tkey-domain "${LCREALM}";
346 self
.putenv("KRB5_CONFIG", '${PREFIX}/private/krb5.conf')
347 self
.putenv('KEYTAB_FILE', '${PREFIX}/private/dns.keytab')
348 self
.putenv('KRB5_KTNAME', '${PREFIX}/private/dns.keytab')
351 self
.setvar("NAMED_INCLUDE", 'include "%s";' % include
)
353 self
.setvar("NAMED_INCLUDE", '')
355 self
.run_cmd("mkdir -p ${PREFIX}/etc")
357 self
.write_file("etc/named.conf", '''
359 listen-on port 53 { ${INTERFACE_IP}; };
361 directory "${PREFIX}/var/named";
362 dump-file "${PREFIX}/var/named/data/cache_dump.db";
363 pid-file "${PREFIX}/var/named/named.pid";
364 statistics-file "${PREFIX}/var/named/data/named_stats.txt";
365 memstatistics-file "${PREFIX}/var/named/data/named_mem_stats.txt";
366 allow-query { any; };
381 secret "lA/cTrno03mt5Ju17ybEYw==";
385 inet ${INTERFACE_IP} port 953
386 allow { any; } keys { "rndc-key"; };
392 # add forwarding for the windows domains
393 domains
= self
.get_domains()
395 self
.write_file('etc/named.conf',
404 ''' % (d
, domains
[d
]),
408 self
.write_file("etc/rndc.conf", '''
412 secret "lA/cTrno03mt5Ju17ybEYw==";
416 default-key "rndc-key";
417 default-server ${INTERFACE_IP};
424 '''Stop our private BIND from listening and operating'''
425 self
.rndc_cmd("stop", checkfail
=False)
426 self
.port_wait("${INTERFACE_IP}", 53, wait_for_fail
=True)
428 self
.run_cmd("rm -rf var/named")
431 def start_bind(self
):
432 '''restart the test environment version of bind'''
433 self
.info("Restarting bind9")
434 self
.chdir('${PREFIX}')
436 self
.set_nameserver(self
.getvar('INTERFACE_IP'))
438 self
.run_cmd("mkdir -p var/named/data")
439 self
.run_cmd("chown -R ${BIND_USER} var/named")
441 self
.bind_child
= self
.run_child("${BIND9} -u ${BIND_USER} -n 1 -c ${PREFIX}/etc/named.conf -g")
443 self
.port_wait("${INTERFACE_IP}", 53)
444 self
.rndc_cmd("flush")
446 def restart_bind(self
, kerberos_support
=False, include
=None):
447 self
.configure_bind(keberos_support
=kerberos_support
, include
=include
)
451 def restore_resolv_conf(self
):
452 '''restore the /etc/resolv.conf after testing is complete'''
453 if getattr(self
, 'resolv_conf_backup', False):
454 self
.info("restoring /etc/resolv.conf")
455 self
.run_cmd("mv -f %s /etc/resolv.conf" % self
.resolv_conf_backup
)
458 def vm_poweroff(self
, vmname
, checkfail
=True):
460 self
.setvar('VMNAME', vmname
)
461 self
.run_cmd("${VM_POWEROFF}", checkfail
=checkfail
)
463 def vm_reset(self
, vmname
):
465 self
.setvar('VMNAME', vmname
)
466 self
.run_cmd("${VM_RESET}")
468 def vm_restore(self
, vmname
, snapshot
):
470 self
.setvar('VMNAME', vmname
)
471 self
.setvar('SNAPSHOT', snapshot
)
472 self
.run_cmd("${VM_RESTORE}")
474 def ping_wait(self
, hostname
):
475 '''wait for a hostname to come up on the network'''
476 hostname
= self
.substitute(hostname
)
480 self
.run_cmd("ping -c 1 -w 10 %s" % hostname
)
485 raise RuntimeError("Failed to ping %s" % hostname
)
486 self
.info("Host %s is up" % hostname
)
488 def port_wait(self
, hostname
, port
, retries
=200, delay
=3, wait_for_fail
=False):
489 '''wait for a host to come up on the network'''
490 self
.retry_cmd("nc -v -z -w 1 %s %u" % (hostname
, port
), ['succeeded'],
491 retries
=retries
, delay
=delay
, wait_for_fail
=wait_for_fail
)
493 def run_net_time(self
, child
):
494 '''run net time on windows'''
495 child
.sendline("net time \\\\${HOSTNAME} /set")
496 child
.expect("Do you want to set the local computer")
498 child
.expect("The command completed successfully")
500 def run_date_time(self
, child
, time_tuple
=None):
501 '''run date and time on windows'''
502 if time_tuple
is None:
503 time_tuple
= time
.localtime()
504 child
.sendline("date")
505 child
.expect("Enter the new date:")
506 i
= child
.expect(["dd-mm-yy", "mm-dd-yy"])
508 child
.sendline(time
.strftime("%d-%m-%y", time_tuple
))
510 child
.sendline(time
.strftime("%m-%d-%y", time_tuple
))
512 child
.sendline("time")
513 child
.expect("Enter the new time:")
514 child
.sendline(time
.strftime("%H:%M:%S", time_tuple
))
517 def get_ipconfig(self
, child
):
518 '''get the IP configuration of the child'''
519 child
.sendline("ipconfig /all")
520 child
.expect('Ethernet adapter ')
521 child
.expect("[\w\s]+")
522 self
.setvar("WIN_NIC", child
.after
)
523 child
.expect(['IPv4 Address', 'IP Address'])
524 child
.expect('\d+.\d+.\d+.\d+')
525 self
.setvar('WIN_IPV4_ADDRESS', child
.after
)
526 child
.expect('Subnet Mask')
527 child
.expect('\d+.\d+.\d+.\d+')
528 self
.setvar('WIN_SUBNET_MASK', child
.after
)
529 child
.expect('Default Gateway')
530 child
.expect('\d+.\d+.\d+.\d+')
531 self
.setvar('WIN_DEFAULT_GATEWAY', child
.after
)
534 def get_is_dc(self
, child
):
535 '''check if a windows machine is a domain controller'''
536 child
.sendline("dcdiag")
537 i
= child
.expect(["is not a Directory Server",
538 "is not recognized as an internal or external command",
540 "passed test Replications"])
545 child
.sendline("net config Workstation")
546 child
.expect("Workstation domain")
547 child
.expect('[\S]+')
549 i
= child
.expect(["Workstation Domain DNS Name", "Logon domain"])
550 '''If we get the Logon domain first, we are not in an AD domain'''
553 if domain
.upper() == self
.getvar("WIN_DOMAIN").upper():
556 child
.expect('[\S]+')
557 hostname
= child
.after
558 if hostname
.upper() == self
.getvar("WIN_HOSTNAME").upper():
561 def set_noexpire(self
, child
, username
):
562 '''Ensure this user's password does not expire'''
563 child
.sendline('wmic useraccount where name="%s" set PasswordExpires=FALSE' % username
)
564 child
.expect("update successful")
567 def run_tlntadmn(self
, child
):
568 '''remove the annoying telnet restrictions'''
569 child
.sendline('tlntadmn config maxconn=1024')
570 child
.expect("The settings were successfully updated")
573 def disable_firewall(self
, child
):
574 '''remove the annoying firewall'''
575 child
.sendline('netsh advfirewall set allprofiles state off')
576 i
= child
.expect(["Ok", "The following command was not found: advfirewall set allprofiles state off"])
579 child
.sendline('netsh firewall set opmode mode = DISABLE profile = ALL')
580 i
= child
.expect(["Ok", "The following command was not found"])
582 self
.info("Firewall disable failed - ignoring")
585 def set_dns(self
, child
):
586 child
.sendline('netsh interface ip set dns "${WIN_NIC}" static ${INTERFACE_IP} primary')
587 i
= child
.expect(['C:', pexpect
.EOF
, pexpect
.TIMEOUT
], timeout
=5)
593 def set_ip(self
, child
):
594 """fix the IP address to the same value it had when we
595 connected, but don't use DHCP, and force the DNS server to our
596 DNS server. This allows DNS updates to run"""
597 self
.get_ipconfig(child
)
598 if self
.getvar("WIN_IPV4_ADDRESS") != self
.getvar("WIN_IP"):
599 raise RuntimeError("ipconfig address %s != nmblookup address %s" % (self
.getvar("WIN_IPV4_ADDRESS"),
600 self
.getvar("WIN_IP")))
601 child
.sendline('netsh')
602 child
.expect('netsh>')
603 child
.sendline('offline')
604 child
.expect('netsh>')
605 child
.sendline('routing ip add persistentroute dest=0.0.0.0 mask=0.0.0.0 name="${WIN_NIC}" nhop=${WIN_DEFAULT_GATEWAY}')
606 child
.expect('netsh>')
607 child
.sendline('interface ip set address "${WIN_NIC}" static ${WIN_IPV4_ADDRESS} ${WIN_SUBNET_MASK} ${WIN_DEFAULT_GATEWAY} 1 store=persistent')
608 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)
610 child
.sendline('interface ip set address "${WIN_NIC}" static ${WIN_IPV4_ADDRESS} ${WIN_SUBNET_MASK} ${WIN_DEFAULT_GATEWAY} 1')
611 child
.expect('netsh>')
612 child
.sendline('commit')
613 child
.sendline('online')
614 child
.sendline('exit')
616 child
.expect([pexpect
.EOF
, pexpect
.TIMEOUT
], timeout
=5)
620 def resolve_ip(self
, hostname
, retries
=60, delay
=5):
621 '''resolve an IP given a hostname, assuming NBT'''
623 child
= self
.pexpect_spawn("bin/nmblookup %s" % hostname
)
624 i
= child
.expect(['\d+.\d+.\d+.\d+', "Lookup failed"])
629 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
630 raise RuntimeError("Failed to resolve IP of %s" % hostname
)
633 def open_telnet(self
, hostname
, username
, password
, retries
=60, delay
=5, set_time
=False, set_ip
=False,
634 disable_firewall
=True, run_tlntadmn
=True, set_noexpire
=False):
635 '''open a telnet connection to a windows server, return the pexpect child'''
638 if self
.getvar('WIN_IP'):
639 ip
= self
.getvar('WIN_IP')
641 ip
= self
.resolve_ip(hostname
)
642 self
.setvar('WIN_IP', ip
)
644 child
= self
.pexpect_spawn("telnet " + ip
+ " -l '" + username
+ "'")
645 i
= child
.expect(["Welcome to Microsoft Telnet Service",
646 "Denying new connections due to the limit on number of connections",
647 "No more connections are allowed to telnet server",
648 "Unable to connect to remote host",
650 "Connection refused",
656 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
658 child
.expect("password:")
659 child
.sendline(password
)
660 i
= child
.expect(["C:",
661 "Denying new connections due to the limit on number of connections",
662 "No more connections are allowed to telnet server",
663 "Unable to connect to remote host",
665 "Connection refused",
671 self
.info("retrying (retries=%u delay=%u)" % (retries
, delay
))
675 if self
.set_dns(child
):
678 child
.sendline('route add 0.0.0.0 mask 0.0.0.0 ${WIN_DEFAULT_GATEWAY}')
682 self
.run_date_time(child
, None)
685 self
.run_tlntadmn(child
)
688 self
.set_noexpire(child
, username
)
691 self
.disable_firewall(child
)
692 disable_firewall
= False
695 if self
.set_ip(child
):
700 raise RuntimeError("Failed to connect with telnet")
702 def kinit(self
, username
, password
):
703 '''use kinit to setup a credentials cache'''
704 self
.run_cmd("kdestroy")
705 self
.putenv('KRB5CCNAME', "${PREFIX}/ccache.test")
706 username
= self
.substitute(username
)
707 s
= username
.split('@')
710 username
= '@'.join(s
)
711 child
= self
.pexpect_spawn('kinit ' + username
)
712 child
.expect("Password")
713 child
.sendline(password
)
714 child
.expect(pexpect
.EOF
)
716 if child
.exitstatus
!= 0:
717 raise RuntimeError("kinit failed with status %d" % child
.exitstatus
)
719 def get_domains(self
):
720 '''return a dictionary of DNS domains and IPs for named.conf'''
723 if v
[-6:] == "_REALM":
725 if base
+ '_IP' in self
.vars:
726 ret
[self
.vars[base
+ '_REALM']] = self
.vars[base
+ '_IP']
729 def wait_reboot(self
, retries
=3):
730 '''wait for a VM to reboot'''
732 # first wait for it to shutdown
733 self
.port_wait("${WIN_IP}", 139, wait_for_fail
=True, delay
=6)
735 # now wait for it to come back. If it fails to come back
736 # then try resetting it
739 self
.port_wait("${WIN_IP}", 139)
743 self
.vm_reset("${WIN_VM}")
744 self
.info("retrying reboot (retries=%u)" % retries
)
745 raise RuntimeError(self
.substitute("VM ${WIN_VM} failed to reboot"))
748 '''return a dictionary of all the configured VM names'''
752 ret
.append(self
.vars[v
])
756 def run_dcpromo_as_first_dc(self
, vm
, func_level
=None):
758 self
.info("Configuring a windows VM ${WIN_VM} at the first DC in the domain using dcpromo")
759 child
= self
.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_time
=True)
760 if self
.get_is_dc(child
):
763 if func_level
== '2008r2':
764 self
.setvar("FUNCTION_LEVEL_INT", str(4))
765 elif func_level
== '2003':
766 self
.setvar("FUNCTION_LEVEL_INT", str(1))
768 self
.setvar("FUNCTION_LEVEL_INT", str(0))
770 child
= self
.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip
=True, set_noexpire
=True)
772 """This server must therefore not yet be a directory server, so we must promote it"""
773 child
.sendline("copy /Y con answers.txt")
776 ; New forest promotion
777 ReplicaOrNewDomain=Domain
779 NewDomainDNSName=${WIN_REALM}
780 ForestLevel=${FUNCTION_LEVEL_INT}
781 DomainNetbiosName=${WIN_DOMAIN}
782 DomainLevel=${FUNCTION_LEVEL_INT}
785 CreateDNSDelegation=No
786 DatabasePath="C:\Windows\NTDS"
787 LogPath="C:\Windows\NTDS"
788 SYSVOLPath="C:\Windows\SYSVOL"
789 ; Set SafeModeAdminPassword to the correct value prior to using the unattend file
790 SafeModeAdminPassword=${WIN_PASS}
791 ; Run-time flags (optional)
792 RebootOnCompletion=No
795 child
.expect("copied.")
798 child
.sendline("dcpromo /answer:answers.txt")
799 i
= child
.expect(["You must restart this computer", "failed", "Active Directory Domain Services was not installed", "C:"], timeout
=240)
801 raise Exception("dcpromo failed")
802 child
.sendline("shutdown -r -t 0")
803 self
.port_wait("${WIN_IP}", 139, wait_for_fail
=True)
804 self
.port_wait("${WIN_IP}", 139)
807 def setup(self
, testname
, subdir
):
808 '''setup for main tests, parsing command line'''
809 self
.parser
.add_option("--conf", type='string', default
='', help='config file')
810 self
.parser
.add_option("--skip", type='string', default
='', help='list of steps to skip (comma separated)')
811 self
.parser
.add_option("--vms", type='string', default
=None, help='list of VMs to use (comma separated)')
812 self
.parser
.add_option("--list", action
='store_true', default
=False, help='list the available steps')
813 self
.parser
.add_option("--rebase", action
='store_true', default
=False, help='do a git pull --rebase')
814 self
.parser
.add_option("--clean", action
='store_true', default
=False, help='clean the tree')
815 self
.parser
.add_option("--prefix", type='string', default
=None, help='override install prefix')
816 self
.parser
.add_option("--sourcetree", type='string', default
=None, help='override sourcetree location')
817 self
.parser
.add_option("--nocleanup", action
='store_true', default
=False, help='disable cleanup code')
819 self
.opts
, self
.args
= self
.parser
.parse_args()
821 if not self
.opts
.conf
:
822 print("Please specify a config file with --conf")
825 # we don't need fsync safety in these tests
826 self
.putenv('TDB_NO_FSYNC', '1')
828 self
.load_config(self
.opts
.conf
)
830 self
.set_skip(self
.opts
.skip
)
831 self
.set_vms(self
.opts
.vms
)
834 self
.list_steps_mode()
837 self
.setvar('PREFIX', self
.opts
.prefix
)
839 if self
.opts
.sourcetree
:
840 self
.setvar('SOURCETREE', self
.opts
.sourcetree
)
843 self
.info('rebasing')
844 self
.chdir('${SOURCETREE}')
845 self
.run_cmd('git pull --rebase')
848 self
.info('cleaning')
849 self
.chdir('${SOURCETREE}/' + subdir
)
850 self
.run_cmd('make clean')