PNG  IHDR* pHYs+ IDATx]n#; cdLb Ǚ[at¤_:uP}>!Usă cag޿ ֵNu`ݼTâabO7uL&y^wFٝA"l[|ŲHLN밪4*sG3|Dv}?+y߉{OuOAt4Jj.u]Gz*҉sP'VQKbA1u\`& Af;HWj hsO;ogTu uj7S3/QzUr&wS`M$X_L7r2;aE+ώ%vikDA:dR+%KzƉo>eOth$z%: :{WwaQ:wz%4foɹE[9<]#ERINƻv溂E%P1i01 |Jvҗ&{b?9g=^wζXn/lK::90KwrюO\!ջ3uzuGv^;騢wq<Iatv09:tt~hEG`v;3@MNZD.1]L:{ծI3`L(÷ba")Y.iljCɄae#I"1 `3*Bdz>j<fU40⨬%O$3cGt]j%Fߠ_twJ;ABU8vP3uEԑwQ V:h%))LfraqX-ۿX]v-\9I gl8tzX ]ecm)-cgʒ#Uw=Wlێn(0hPP/ӨtQ“&J35 $=]r1{tLuǮ*i0_;NƝ8;-vݏr8+U-kruȕYr0RnC]*ެ(M:]gE;{]tg(#ZJ9y>utRDRMdr9㪩̞zֹb<ģ&wzJM"iI( .ꮅX)Qw:9,i좜\Ԛi7&N0:asϓc];=ΗOӣ APqz93 y $)A*kVHZwBƺnWNaby>XMN*45~ղM6Nvm;A=jֲ.~1}(9`KJ/V F9[=`~[;sRuk]rєT!)iQO)Y$V ی ۤmzWz5IM Zb )ˆC`6 rRa}qNmUfDsWuˤV{ Pݝ'=Kֳbg,UҘVz2ﴻnjNgBb{? ߮tcsͻQuxVCIY۠:(V뺕 ٥2;t`@Fo{Z9`;]wMzU~%UA蛚dI vGq\r82iu +St`cR.6U/M9IENDB`# Author: Antti Myyrä # # This file is part of cloud-init. See LICENSE file for license information. import json import logging from cloudinit import dmi from cloudinit import net as cloudnet from cloudinit import url_helper LOG = logging.getLogger(__name__) def convert_to_network_config_v1(config): """ Convert the UpCloud network metadata description into Cloud-init's version 1 netconfig format. Example JSON: { "interfaces": [ { "index": 1, "ip_addresses": [ { "address": "94.237.105.53", "dhcp": true, "dns": [ "94.237.127.9", "94.237.40.9" ], "family": "IPv4", "floating": false, "gateway": "94.237.104.1", "network": "94.237.104.0/22" }, { "address": "94.237.105.50", "dhcp": false, "dns": [], "family": "IPv4", "floating": true, "gateway": "", "network": "94.237.105.50/32" } ], "mac": "32:d5:ba:4a:36:e7", "network_id": "031457f4-0f8c-483c-96f2-eccede02909c", "type": "public" }, { "index": 2, "ip_addresses": [ { "address": "10.6.3.27", "dhcp": true, "dns": [], "family": "IPv4", "floating": false, "gateway": "10.6.0.1", "network": "10.6.0.0/22" } ], "mac": "32:d5:ba:4a:84:cc", "network_id": "03d82553-5bea-4132-b29a-e1cf67ec2dd1", "type": "utility" }, { "index": 3, "ip_addresses": [ { "address": "2a04:3545:1000:720:38d6:baff:fe4a:63e7", "dhcp": true, "dns": [ "2a04:3540:53::1", "2a04:3544:53::1" ], "family": "IPv6", "floating": false, "gateway": "2a04:3545:1000:720::1", "network": "2a04:3545:1000:720::/64" } ], "mac": "32:d5:ba:4a:63:e7", "network_id": "03000000-0000-4000-8046-000000000000", "type": "public" }, { "index": 4, "ip_addresses": [ { "address": "172.30.1.10", "dhcp": true, "dns": [], "family": "IPv4", "floating": false, "gateway": "172.30.1.1", "network": "172.30.1.0/24" } ], "mac": "32:d5:ba:4a:8a:e1", "network_id": "035a0a4a-77b4-4de5-820d-189fc8135714", "type": "private" } ], "dns": [ "94.237.127.9", "94.237.40.9" ] } """ def _get_subnet_config(ip_addr, dns): if ip_addr.get("dhcp"): dhcp_type = "dhcp" if ip_addr.get("family") == "IPv6": # UpCloud currently passes IPv6 addresses via # StateLess Address Auto Configuration (SLAAC) dhcp_type = "ipv6_dhcpv6-stateless" return {"type": dhcp_type} static_type = "static" if ip_addr.get("family") == "IPv6": static_type = "static6" subpart = { "type": static_type, "control": "auto", "address": ip_addr.get("address"), } if ip_addr.get("gateway"): subpart["gateway"] = ip_addr.get("gateway") if "/" in ip_addr.get("network"): subpart["netmask"] = ip_addr.get("network").split("/")[1] if dns != ip_addr.get("dns") and ip_addr.get("dns"): subpart["dns_nameservers"] = ip_addr.get("dns") return subpart nic_configs = [] macs_to_interfaces = cloudnet.get_interfaces_by_mac() LOG.debug("NIC mapping: %s", macs_to_interfaces) for raw_iface in config.get("interfaces"): LOG.debug("Considering %s", raw_iface) mac_address = raw_iface.get("mac") if mac_address not in macs_to_interfaces: raise RuntimeError( "Did not find network interface on system " "with mac '%s'. Cannot apply configuration: %s" % (mac_address, raw_iface) ) iface_type = raw_iface.get("type") sysfs_name = macs_to_interfaces.get(mac_address) LOG.debug( "Found %s interface '%s' with address '%s' (index %d)", iface_type, sysfs_name, mac_address, raw_iface.get("index"), ) interface = { "type": "physical", "name": sysfs_name, "mac_address": mac_address, } subnets = [] for ip_address in raw_iface.get("ip_addresses"): sub_part = _get_subnet_config(ip_address, config.get("dns")) subnets.append(sub_part) interface["subnets"] = subnets nic_configs.append(interface) if config.get("dns"): LOG.debug("Setting DNS nameservers to %s", config.get("dns")) nic_configs.append( {"type": "nameserver", "address": config.get("dns")} ) return {"version": 1, "config": nic_configs} def convert_network_config(config): return convert_to_network_config_v1(config) def read_metadata(url, timeout=2, sec_between=2, retries=30): response = url_helper.readurl( url, timeout=timeout, sec_between=sec_between, retries=retries ) if not response.ok(): raise RuntimeError("unable to read metadata at %s" % url) return json.loads(response.contents.decode()) def read_sysinfo(): # UpCloud embeds vendor ID and server UUID in the # SMBIOS information # Detect if we are on UpCloud and return the UUID vendor_name = dmi.read_dmi_data("system-manufacturer") if vendor_name != "UpCloud": return False, None server_uuid = dmi.read_dmi_data("system-uuid") if server_uuid: LOG.debug( "system identified via SMBIOS as UpCloud server: %s", server_uuid ) else: msg = ( "system identified via SMBIOS as a UpCloud server, but " "did not provide an ID. Please contact support via" "https://hub.upcloud.com or via email with support@upcloud.com" ) LOG.critical(msg) raise RuntimeError(msg) return True, server_uuid