|
15 | 15 | # limitations under the License.
|
16 | 16 |
|
17 | 17 |
|
| 18 | +import io |
18 | 19 | import xml.etree.ElementTree as ET
|
19 | 20 | import os
|
20 | 21 | import argparse
|
21 | 22 | import json
|
22 | 23 |
|
| 24 | +ADDRESSES_TEMPLATE = """ <IpAddress wcm:action="add" wcm:keyValue="%(order)d">%(cidr)s</IpAddress> |
| 25 | +""" |
| 26 | +INTERFACE_COMPONENT_TEMPLATE = """ |
| 27 | +<component name="Microsoft-Windows-TCPIP" processorArchitecture="amd64" |
| 28 | + publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" |
| 29 | + xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" |
| 30 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
| 31 | + <Interfaces> |
| 32 | + <Interface wcm:action="add"> |
| 33 | + <Ipv4Settings> |
| 34 | + <DhcpEnabled>false</DhcpEnabled> |
| 35 | + </Ipv4Settings> |
| 36 | + <Ipv6Settings> |
| 37 | + <DhcpEnabled>false</DhcpEnabled> |
| 38 | + </Ipv6Settings> |
| 39 | + <Identifier>%(iface_id)s</Identifier> |
| 40 | + <UnicastIpAddresses> |
| 41 | +%(addresses)s </UnicastIpAddresses> |
| 42 | + <Routes>%(routes)s |
| 43 | + </Routes> |
| 44 | + </Interface> |
| 45 | + </Interfaces> |
| 46 | +</component> |
| 47 | +""" |
| 48 | +ROUTE_TEMPLATE = """ |
| 49 | + <Route wcm:action="add"> |
| 50 | + <Identifier>%(id)s</Identifier> |
| 51 | + <Prefix>%(prefix)s</Prefix> |
| 52 | + <NextHopAddress>%(gateway)s</NextHopAddress> |
| 53 | + </Route>""" |
| 54 | +DNS_TEMPLATE = """ |
| 55 | +<component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" |
| 56 | + publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" |
| 57 | + xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" |
| 58 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
| 59 | + <Interfaces>%(interfaces)s |
| 60 | + </Interfaces> |
| 61 | +</component> |
| 62 | +""" |
| 63 | +DNS_INTERFACE_TEMPLATE = """ |
| 64 | + <Interface wcm:action="add"> |
| 65 | + <Identifier>%(iface_id)s</Identifier> |
| 66 | + <DNSServerSearchOrder>%(dns_search_orders)s |
| 67 | + </DNSServerSearchOrder> |
| 68 | + </Interface> |
| 69 | +""" |
| 70 | +DNS_SEARCH_ORDER_TEMPLATE = """ |
| 71 | + <IpAddress wcm:action="add" wcm:keyValue="%(key)s">%(server)s</IpAddress>""" |
| 72 | +INTERFACE_ID = "Ethernet0" |
| 73 | + |
| 74 | + |
23 | 75 | def set_xmlstring(root, location, key, value):
|
24 |
| - setting = root.find(location) |
25 |
| - setting.find(key).text = value |
26 |
| - return setting |
| 76 | + setting = root.find(location) |
| 77 | + setting.find(key).text = value |
| 78 | + return setting |
| 79 | + |
| 80 | + |
| 81 | +def ensure_interfaces(root, interfaces_content): |
| 82 | + setting = root.find("*[@pass='specialize']") |
| 83 | + old_element = setting.find(".//*[@name='Microsoft-Windows-TCPIP']") |
| 84 | + modified = False |
| 85 | + if old_element: |
| 86 | + setting.remove(old_element) |
| 87 | + modified = not interfaces_content |
| 88 | + |
| 89 | + if interfaces_content: |
| 90 | + interface_component_tree = ET.parse(io.StringIO(interfaces_content)) |
| 91 | + new_element = interface_component_tree.getroot() |
| 92 | + setting.append(new_element) |
| 93 | + modified = True |
| 94 | + |
| 95 | + return setting, modified |
| 96 | + |
| 97 | + |
| 98 | +def ensure_dns_settings(root, dns_content): |
| 99 | + setting = root.find("*[@pass='specialize']") |
| 100 | + old_element = setting.find(".//*[@name='Microsoft-Windows-DNS-Client']") |
| 101 | + modified = False |
| 102 | + if old_element: |
| 103 | + setting.remove(old_element) |
| 104 | + modified = not dns_content |
| 105 | + |
| 106 | + if dns_content: |
| 107 | + dns_component_tree = ET.parse(io.StringIO(dns_content)) |
| 108 | + new_element = dns_component_tree.getroot() |
| 109 | + setting.append(new_element) |
| 110 | + modified = True |
| 111 | + |
| 112 | + return setting, modified |
| 113 | + |
27 | 114 |
|
28 | 115 | def main():
|
29 | 116 | parser = argparse.ArgumentParser(
|
@@ -55,32 +142,86 @@ def main():
|
55 | 142 | with open(args.var_file, 'r') as f:
|
56 | 143 | data = json.load(f)
|
57 | 144 |
|
58 |
| - modified=0 |
| 145 | + modified = False |
59 | 146 | os.chdir(args.build_dir)
|
60 |
| - unattend=ET.parse(args.unattend_file) |
| 147 | + unattend = ET.parse(args.unattend_file) |
61 | 148 | ET.register_namespace('', "urn:schemas-microsoft-com:unattend")
|
62 | 149 | ET.register_namespace('wcm', "http://schemas.microsoft.com/WMIConfig/2002/State")
|
63 | 150 | ET.register_namespace('xsi', "http://www.w3.org/2001/XMLSchema-instance")
|
64 |
| - |
| 151 | + |
65 | 152 | root = unattend.getroot()
|
66 | 153 |
|
67 | 154 | if data.get("unattend_timezone"):
|
68 |
| - modified=1 |
69 |
| - setting = set_xmlstring(root, ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']",'{urn:schemas-microsoft-com:unattend}TimeZone', data["unattend_timezone"]) |
70 |
| - print("windows-ova-unattend: Setting Timezone to %s" % data["unattend_timezone"]) |
71 |
| - |
| 155 | + modified = True |
| 156 | + setting = set_xmlstring(root, ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']", |
| 157 | + '{urn:schemas-microsoft-com:unattend}TimeZone', data["unattend_timezone"]) |
| 158 | + print("windows-ova-unattend: Setting Timezone to %s" % data["unattend_timezone"]) |
| 159 | + |
72 | 160 | admin_password = data.get("admin_password")
|
73 | 161 | if admin_password:
|
74 |
| - modified=1 |
75 |
| - set_xmlstring(root, ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']/{*}UserAccounts/{*}AdministratorPassword",'{urn:schemas-microsoft-com:unattend}Value', admin_password) |
76 |
| - set_xmlstring(root, ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']/{*}AutoLogon/{*}Password",'{urn:schemas-microsoft-com:unattend}Value', admin_password) |
77 |
| - print("windows-ova-unattend: Setting Administrator Password") |
78 |
| - |
79 |
| - if modified == 1: |
80 |
| - print("windows-ova-unattend: Updating %s ..." % args.unattend_file) |
81 |
| - unattend.write(args.unattend_file) |
| 162 | + modified = True |
| 163 | + set_xmlstring(root, |
| 164 | + ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']/{*}UserAccounts/{*}AdministratorPassword", |
| 165 | + '{urn:schemas-microsoft-com:unattend}Value', admin_password) |
| 166 | + set_xmlstring(root, |
| 167 | + ".//*[@pass='oobeSystem']/*[@name='Microsoft-Windows-Shell-Setup']/{*}AutoLogon/{*}Password", |
| 168 | + '{urn:schemas-microsoft-com:unattend}Value', admin_password) |
| 169 | + print("windows-ova-unattend: Setting Administrator Password") |
| 170 | + |
| 171 | + addr_elements = [] |
| 172 | + ip_addr_cidr = data.get("ipv4_address_cidr") |
| 173 | + gateway4 = data.get("gateway4") |
| 174 | + if ip_addr_cidr: |
| 175 | + modified = True |
| 176 | + route_configs = [] |
| 177 | + if gateway4: |
| 178 | + route_configs.append(("0.0.0.0/0", gateway4)) |
| 179 | + |
| 180 | + routes = [] |
| 181 | + for i in range(len(route_configs)): |
| 182 | + route_config = route_configs[i] |
| 183 | + routes.append(ROUTE_TEMPLATE % {"id": i + 1, "prefix": route_config[0], "gateway": route_config[1]}) |
| 184 | + print("windows-ova-unattend: Setting Gateway to %s" % route_config[1]) |
| 185 | + |
| 186 | + addrs = [ip_addr_cidr] |
| 187 | + for i in range(len(addrs)): |
| 188 | + addr_elements.append(ADDRESSES_TEMPLATE % {"order": i + 1, |
| 189 | + "cidr": addrs[i]}) |
| 190 | + print("windows-ova-unattend: Setting IP Address to %s" % ip_addr_cidr) |
| 191 | + |
| 192 | + interfaces_content = None |
| 193 | + if addr_elements: |
| 194 | + interfaces_content = INTERFACE_COMPONENT_TEMPLATE % {"iface_id": INTERFACE_ID, |
| 195 | + "addresses": ''.join(addr_elements), |
| 196 | + "routes": ''.join(routes)} |
| 197 | + |
| 198 | + setting, xml_modified = ensure_interfaces(root, interfaces_content) |
| 199 | + if xml_modified: |
| 200 | + modified = True |
| 201 | + |
| 202 | + dns_servers = data.get("dns_servers") |
| 203 | + dns_servers_content = '' |
| 204 | + if dns_servers: |
| 205 | + dns_servers = dns_servers.split() |
| 206 | + search_order_content = [] |
| 207 | + for i in range(len(dns_servers)): |
| 208 | + search_order_content.append(DNS_SEARCH_ORDER_TEMPLATE % {"key": i + 1, |
| 209 | + "server": dns_servers[i]}) |
| 210 | + dns_interface_content = [DNS_INTERFACE_TEMPLATE % {"iface_id": INTERFACE_ID, |
| 211 | + "dns_search_orders": ''.join(search_order_content)}] |
| 212 | + dns_servers_content = DNS_TEMPLATE % {"interfaces": ''.join(dns_interface_content)} |
| 213 | + print("windows-ova-unattend: Setting DNS Addresses to %s" % dns_servers) |
| 214 | + |
| 215 | + setting, xml_modified = ensure_dns_settings(root, dns_servers_content) |
| 216 | + if xml_modified: |
| 217 | + modified = True |
| 218 | + |
| 219 | + if modified: |
| 220 | + print("windows-ova-unattend: Updating %s ..." % args.unattend_file) |
| 221 | + unattend.write(args.unattend_file) |
82 | 222 | else:
|
83 |
| - print("windows-ova-unattend: skipping...") |
| 223 | + print("windows-ova-unattend: skipping...") |
| 224 | + |
84 | 225 |
|
85 | 226 | if __name__ == "__main__":
|
86 | 227 | main()
|
0 commit comments