def apply_locale(locale, sys_path=LOCALE_CONF_FN, keyname='LANG'): """Apply the locale. Run locale-gen for the provided locale and set the default system variable `keyname` appropriately in the provided `sys_path`. If sys_path indicates that `keyname` is already set to `locale` then no changes will be made and locale-gen not called. This allows images built with a locale already generated to not re-run locale-gen which can be very heavy. """ if not locale: raise ValueError('Failed to provide locale value.') if not sys_path: raise ValueError('Invalid path: %s' % sys_path) if os.path.exists(sys_path): locale_content = util.load_file(sys_path) # if LANG isn't present, regen sys_defaults = util.load_shell_content(locale_content) sys_val = sys_defaults.get(keyname, "") if sys_val.lower() == locale.lower(): LOG.debug( "System has '%s=%s' requested '%s', skipping regeneration.", keyname, sys_val, locale) return util.subp(['locale-gen', locale], capture=False) util.subp([ 'update-locale', '--locale-file=' + sys_path, '%s=%s' % (keyname, locale) ], capture=False)
def read_system_locale(sys_path=LOCALE_CONF_FN, keyname='LANG'): """Read system default locale setting, if present""" sys_val = "" if not sys_path: raise ValueError('Invalid path: %s' % sys_path) if os.path.exists(sys_path): locale_content = util.load_file(sys_path) sys_defaults = util.load_shell_content(locale_content) sys_val = sys_defaults.get(keyname, "") return sys_val
def test_comments_handled_correctly(self): """Shell comments should be allowed in the content.""" self.assertEqual( {'key1': 'val1', 'key2': 'val2', 'key3': 'val3 #tricky'}, util.load_shell_content('\n'.join([ "#top of file comment", "key1=val1 #this is a comment", "# second comment", 'key2="val2" # inlin comment' '#badkey=wark', 'key3="val3 #tricky"', ''])))
def _klibc_to_config_entry(content, mac_addrs=None): """Convert a klibc written shell content file to a 'config' entry When ip= is seen on the kernel command line in debian initramfs and networking is brought up, ipconfig will populate /run/net-<name>.cfg. The files are shell style syntax, and examples are in the tests provided here. There is no good documentation on this unfortunately. DEVICE=<name> is expected/required and PROTO should indicate if this is 'none' (static) or 'dhcp' or 'dhcp6' (LP: #1621507). note that IPV6PROTO is also written by newer code to address the possibility of both ipv4 and ipv6 getting addresses. Full syntax is documented at: https://git.kernel.org/pub/scm/libs/klibc/klibc.git/plain/usr/kinit/ipconfig/README.ipconfig """ if mac_addrs is None: mac_addrs = {} data = util.load_shell_content(content) try: name = data["DEVICE"] if "DEVICE" in data else data["DEVICE6"] except KeyError as e: raise ValueError("no 'DEVICE' or 'DEVICE6' entry in data") from e # ipconfig on precise does not write PROTO # IPv6 config gives us IPV6PROTO, not PROTO. proto = data.get("PROTO", data.get("IPV6PROTO")) if not proto: if data.get("filename"): proto = "dhcp" else: proto = "none" if proto not in ("none", "dhcp", "dhcp6"): raise ValueError("Unexpected value for PROTO: %s" % proto) iface = { "type": "physical", "name": name, "subnets": [], } if name in mac_addrs: iface["mac_address"] = mac_addrs[name] # Handle both IPv4 and IPv6 values for pre in ("IPV4", "IPV6"): # if no IPV4ADDR or IPV6ADDR, then go on. if pre + "ADDR" not in data: continue # PROTO for ipv4, IPV6PROTO for ipv6 cur_proto = data.get(pre + "PROTO", proto) # ipconfig's 'none' is called 'static' if cur_proto == "none": cur_proto = "static" subnet = {"type": cur_proto, "control": "manual"} # only populate address for static types. While the rendered config # may have an address for dhcp, that is not really expected. if cur_proto == "static": subnet["address"] = data[pre + "ADDR"] # these fields go right on the subnet for key in ("NETMASK", "BROADCAST", "GATEWAY"): if pre + key in data: subnet[key.lower()] = data[pre + key] dns = [] # handle IPV4DNS0 or IPV6DNS0 for nskey in ("DNS0", "DNS1"): ns = data.get(pre + nskey) # verify it has something other than 0.0.0.0 (or ipv6) if ns and len(ns.strip(":.0")): dns.append(data[pre + nskey]) if dns: subnet["dns_nameservers"] = dns # add search to both ipv4 and ipv6, as it has no namespace search = data.get("DOMAINSEARCH") if search: if "," in search: subnet["dns_search"] = search.split(",") else: subnet["dns_search"] = search.split() iface["subnets"].append(subnet) return name, iface
def _klibc_to_config_entry(content, mac_addrs=None): """Convert a klibc written shell content file to a 'config' entry When ip= is seen on the kernel command line in debian initramfs and networking is brought up, ipconfig will populate /run/net-<name>.cfg. The files are shell style syntax, and examples are in the tests provided here. There is no good documentation on this unfortunately. DEVICE=<name> is expected/required and PROTO should indicate if this is 'static' or 'dhcp' or 'dhcp6' (LP: #1621507). note that IPV6PROTO is also written by newer code to address the possibility of both ipv4 and ipv6 getting addresses. """ if mac_addrs is None: mac_addrs = {} data = util.load_shell_content(content) try: name = data['DEVICE'] if 'DEVICE' in data else data['DEVICE6'] except KeyError: raise ValueError("no 'DEVICE' or 'DEVICE6' entry in data") # ipconfig on precise does not write PROTO # IPv6 config gives us IPV6PROTO, not PROTO. proto = data.get('PROTO', data.get('IPV6PROTO')) if not proto: if data.get('filename'): proto = 'dhcp' else: proto = 'static' if proto not in ('static', 'dhcp', 'dhcp6'): raise ValueError("Unexpected value for PROTO: %s" % proto) iface = { 'type': 'physical', 'name': name, 'subnets': [], } if name in mac_addrs: iface['mac_address'] = mac_addrs[name] # Handle both IPv4 and IPv6 values for pre in ('IPV4', 'IPV6'): # if no IPV4ADDR or IPV6ADDR, then go on. if pre + "ADDR" not in data: continue # PROTO for ipv4, IPV6PROTO for ipv6 cur_proto = data.get(pre + 'PROTO', proto) subnet = {'type': cur_proto, 'control': 'manual'} # only populate address for static types. While the rendered config # may have an address for dhcp, that is not really expected. if cur_proto == 'static': subnet['address'] = data[pre + 'ADDR'] # these fields go right on the subnet for key in ('NETMASK', 'BROADCAST', 'GATEWAY'): if pre + key in data: subnet[key.lower()] = data[pre + key] dns = [] # handle IPV4DNS0 or IPV6DNS0 for nskey in ('DNS0', 'DNS1'): ns = data.get(pre + nskey) # verify it has something other than 0.0.0.0 (or ipv6) if ns and len(ns.strip(":.0")): dns.append(data[pre + nskey]) if dns: subnet['dns_nameservers'] = dns # add search to both ipv4 and ipv6, as it has no namespace search = data.get('DOMAINSEARCH') if search: if ',' in search: subnet['dns_search'] = search.split(",") else: subnet['dns_search'] = search.split() iface['subnets'].append(subnet) return name, iface
def test_locale(self): """Test locale is set properly.""" data = util.load_shell_content(self.get_data_file('locale_default')) self.assertIn("LANG", data) self.assertEqual('en_GB.UTF-8', data['LANG'])