akutz | 77457a6 | 2018-08-22 16:07:21 -0500 | [diff] [blame] | 1 | # vi: ts=4 expandtab |
| 2 | # |
| 3 | # Copyright (C) 2017 VMware Inc. |
| 4 | # |
| 5 | # Author: Anish Swaminathan <anishs@vmware.com> |
| 6 | # |
| 7 | import os |
| 8 | import base64 |
| 9 | |
| 10 | from cloudinit import log as logging |
| 11 | from cloudinit import sources |
| 12 | from cloudinit import util |
| 13 | |
| 14 | from distutils.spawn import find_executable |
| 15 | |
| 16 | LOG = logging.getLogger(__name__) |
| 17 | |
| 18 | class DataSourceVmxGuestinfo(sources.DataSource): |
| 19 | def __init__(self, sys_cfg, distro, paths, ud_proc=None): |
| 20 | sources.DataSource.__init__(self, sys_cfg, distro, paths, ud_proc) |
| 21 | self.metadata = {} |
| 22 | self.userdata_raw = '' |
| 23 | self.vmtoolsd = find_executable("vmtoolsd") |
| 24 | if not self.vmtoolsd: |
| 25 | LOG.error("Failed to find vmtoolsd") |
| 26 | |
| 27 | def get_data(self): |
| 28 | if not self.vmtoolsd: |
| 29 | LOG.error("vmtoolsd is required to fetch guestinfo value") |
| 30 | return False |
| 31 | hostname = self._get_guestinfo_value('hostname') |
| 32 | if hostname: |
| 33 | self.distro.set_hostname(hostname) |
| 34 | ud = self._get_guestinfo_value('userdata') |
| 35 | if ud: |
| 36 | LOG.debug("Decoding base64 format guestinfo.userdata") |
| 37 | self.userdata_raw = base64.b64decode(ud) |
| 38 | found = True |
| 39 | dev_index = 0 |
| 40 | network_settings = '' |
| 41 | while found: |
| 42 | key_begin = 'interface.' + str(dev_index) |
| 43 | key_iname = key_begin + '.name' |
| 44 | interface_name = self._get_guestinfo_value(key_iname) |
| 45 | if interface_name: |
| 46 | network_settings += 'auto ' + interface_name + '\n' |
| 47 | network_settings += 'iface ' + interface_name |
| 48 | key_proto = key_begin + '.dhcp' |
| 49 | dhcp_enabled = self._get_guestinfo_value(key_proto) |
| 50 | key_address = key_begin + '.address' |
| 51 | address = self._get_guestinfo_value(key_address) |
| 52 | bootproto = 'dhcp' |
| 53 | if dhcp_enabled: |
| 54 | if dhcp_enabled == 'yes': |
| 55 | network_settings += ' dhcp\n' |
| 56 | elif dhcp_enabled == 'no': |
| 57 | network_settings += ' static\n' |
| 58 | bootproto = 'static' |
| 59 | else: |
| 60 | LOG.warning("Invalid value for yes/no parameter for %s, setting to dhcp", key_proto) |
| 61 | elif address: |
| 62 | bootproto = 'static' |
| 63 | dhcp_enabled == 'no' |
| 64 | network_settings += ' static\n' |
| 65 | else: |
| 66 | dhcp_enabled == 'yes' |
| 67 | network_settings += ' dhcp\n' |
| 68 | LOG.debug("Setting network bootproto to dhcp by default") |
| 69 | key_mac = key_begin + '.mac' |
| 70 | mac = self._get_guestinfo_value(key_mac) |
| 71 | if address: |
| 72 | network_settings += 'address ' + address + '\n' |
| 73 | if mac: |
| 74 | network_settings += 'hwaddress ' + mac + '\n' |
| 75 | key_netmask = key_begin + '.netmask' |
| 76 | netmask = self._get_guestinfo_value(key_netmask) |
| 77 | if netmask: |
| 78 | network_settings += 'netmask ' + netmask + '\n' |
| 79 | key_dnsserver = 'dns.servers' |
| 80 | dnsserver = self._get_guestinfo_value(key_dnsserver) |
| 81 | if dnsserver: |
| 82 | network_settings += 'dns-nameservers ' |
| 83 | dnsserver = dnsserver.split(',') |
| 84 | for d in dnsserver: |
| 85 | network_settings += d + ' ' |
| 86 | network_settings += '\n' |
| 87 | key_dnsdomain = 'dns.domains' |
| 88 | dnsdomain = self._get_guestinfo_value(key_dnsdomain) |
| 89 | if dnsdomain: |
| 90 | network_settings += 'dns-search ' |
| 91 | dnsdomain = dnsdomain.split(',') |
| 92 | for d in dnsdomain: |
| 93 | network_settings += d + ' ' |
| 94 | network_settings += '\n' |
| 95 | route_index = 0 |
| 96 | default_destination_set = False |
| 97 | while True: |
| 98 | key_route = key_begin + '.route.' + str(route_index) |
| 99 | route = self._get_guestinfo_value(key_route) |
| 100 | if route: |
| 101 | network_settings += "routes.%s " % (route_index) |
| 102 | route = route.split(',') |
| 103 | if len(route) > 2: |
| 104 | LOG.debug("Route information for %s route in %s device incorrect - ", |
| 105 | "expected 2 values", route_index, dev_index) |
| 106 | continue |
| 107 | elif len(route) == 2: |
| 108 | network_settings += route[0] + ' ' + route[1] + '\n'# Gateway Destination |
| 109 | else: #length = 1 |
| 110 | if not default_destination_set: |
| 111 | network_settings += route[0] + ' 0.0.0.0/0' + '\n' |
| 112 | default_destination_set = True |
| 113 | else: |
| 114 | LOG.debug("Default destination set previously, not setting route %s", route_index) |
| 115 | else: |
| 116 | break |
| 117 | route_index += 1 |
| 118 | else: |
| 119 | found = False |
| 120 | dev_index += 1 |
| 121 | self.distro.apply_network(network_settings, False) |
| 122 | return True |
| 123 | |
| 124 | def _get_guestinfo_value(self, key): |
| 125 | LOG.debug("Getting guestinfo value for key %s", key) |
| 126 | value = '' |
| 127 | try: |
| 128 | (value, _err) = util.subp([self.vmtoolsd, "--cmd", "info-get guestinfo." + key]) |
| 129 | if _err: |
| 130 | LOG.error("Failed to get guestinfo value for key %s", key) |
| 131 | except util.ProcessExecutionError as error: |
| 132 | util.logexc(LOG,"Failed to get guestinfo value for key %s: %s", key, error) |
| 133 | except Exception: |
| 134 | util.logexc(LOG,"Unexpected error while trying to get guestinfo value for key %s", key) |
| 135 | return value.rstrip() |
| 136 | |
| 137 | def get_instance_id(self): |
| 138 | with open('/sys/class/dmi/id/product_uuid', 'r') as id_file: |
| 139 | return str(id_file.read()).rstrip() |
| 140 | |
| 141 | def get_datasource_list(depends): |
| 142 | """ |
| 143 | Return a list of data sources that match this set of dependencies |
| 144 | """ |
| 145 | return [DataSourceVmxGuestinfo] |