glean/glean/cmd.py

913 lines
33 KiB
Python

#!/usr/bin/python
# Copyright (c) 2015 Monty Taylor
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import errno
import json
import logging
import os
import platform
import re
import subprocess
import sys
import time
from glean import systemlock
log = logging.getLogger("glean")
post_up = " post-up route add -net {net} netmask {mask} gw {gw} || true\n"
pre_down = " pre-down route del -net {net} netmask {mask} gw {gw} || true\n"
def _exists_rh_interface(name):
file_to_check = '/etc/sysconfig/network-scripts/ifcfg-{name}'.format(
name=name
)
return os.path.exists(file_to_check)
def _write_rh_interface(name, interface):
files_to_write = dict()
results = """# Automatically generated, do not edit
DEVICE={name}
BOOTPROTO=static
HWADDR={hwaddr}
IPADDR={ip_address}
NETMASK={netmask}
ONBOOT=yes
NM_CONTROLLED=no
""".format(
name=name,
hwaddr=interface['mac_address'],
ip_address=interface['ip_address'],
netmask=interface['netmask'],
)
if 'vlan_id' in interface:
results += "VLAN=yes\n"
routes = []
for route in interface['routes']:
if route['network'] == '0.0.0.0' and route['netmask'] == '0.0.0.0':
results += "DEFROUTE=yes\n"
results += "GATEWAY={gw}\n".format(gw=route['gateway'])
else:
routes.append(dict(
net=route['network'], mask=route['netmask'],
gw=route['gateway']))
if routes:
route_content = ""
for x in range(0, len(routes)):
route_content += "ADDRESS{x}={net}\n".format(x=x, **routes[x])
route_content += "NETMASK{x}={mask}\n".format(x=x, **routes[x])
route_content += "GATEWAY{x}={gw}\n".format(x=x, **routes[x])
files_to_write['/etc/sysconfig/network-scripts/route-{name}'.format(
name=name)] = route_content
files_to_write['/etc/sysconfig/network-scripts/ifcfg-{name}'.format(
name=name)] = results
return files_to_write
def _write_rh_dhcp(name, interface):
filename = '/etc/sysconfig/network-scripts/ifcfg-{name}'.format(name=name)
results = """# Automatically generated, do not edit
DEVICE={name}
BOOTPROTO=dhcp
HWADDR={hwaddr}
ONBOOT=yes
NM_CONTROLLED=no
TYPE=Ethernet
""".format(name=name, hwaddr=interface['mac_address'])
if 'vlan_id' in interface:
results += "VLAN=yes\n"
return {filename: results}
def _write_rh_manual(name, interface):
filename = '/etc/sysconfig/network-scripts/ifcfg-{name}'.format(name=name)
results = """# Automatically generated, do not edit
DEVICE={name}
BOOTPROTO=none
HWADDR={hwaddr}
ONBOOT=yes
NM_CONTROLLED=no
TYPE=Ethernet
""".format(name=name, hwaddr=interface['mac_address'])
if 'vlan_id' in interface:
results += "VLAN=yes\n"
if 'bond_master' in interface:
results += "SLAVE=yes\n"
results += "MASTER={0}\n".format(interface['bond_master'])
return {filename: results}
def write_redhat_interfaces(interfaces, sys_interfaces):
files_to_write = dict()
# Sort the interfaces by id so that we'll have consistent output order
for iname, interface in sorted(
interfaces.items(), key=lambda x: x[1]['id']):
if interface['type'] == 'ipv6':
continue
raw_macs = interface.get('raw_macs', [interface['mac_address']])
for mac in raw_macs:
if mac not in sys_interfaces:
continue
if 'vlan_id' in interface:
if len(raw_macs) == 1:
vlan_raw_device = sys_interfaces.get(raw_macs[0])
else:
vlan_raw_device = interface['vlan_link']
interface_name = "{0}.{1}".format(
vlan_raw_device, interface['vlan_id'])
elif 'bond_mode' in interface:
interface_name = iname
else:
interface_name = sys_interfaces[interface['mac_address']]
if interface['type'] == 'ipv4':
files_to_write.update(
_write_rh_interface(interface_name, interface))
if interface['type'] == 'ipv4_dhcp':
files_to_write.update(
_write_rh_dhcp(interface_name, interface))
if interface['type'] == 'manual':
files_to_write.update(
_write_rh_manual(interface_name, interface))
for mac, iname in sorted(
sys_interfaces.items(), key=lambda x: x[1]):
if _exists_rh_interface(iname):
# This interface already has a config file, move on
log.debug("%s already has config file, skipping" % iname)
continue
inter_macs = [intf['mac_address'] for intf in interfaces.values()]
link_macs = [intf.get('link_mac') for intf in interfaces.values()
if 'vlan_id' in interface]
if mac in inter_macs or mac in link_macs:
# We have a config drive config, move on
log.debug("%s configured via config-drive" % mac)
continue
files_to_write.update(_write_rh_dhcp(iname, {'mac_address': mac}))
return files_to_write
def _exists_gentoo_interface(name):
file_to_check = '/etc/conf.d/net.{name}'.format(name=name)
return os.path.exists(file_to_check)
def _enable_gentoo_interface(name):
log.debug('rc-update add {name} default'.format(name=name))
subprocess.call(['rc-update', 'add',
'net.{name}'.format(name=name), 'default'])
def _write_gentoo_interface(name, interfaces):
files_to_write = dict()
results = ""
vlans = []
for interface in interfaces:
iname = name
if 'vlan_id' in interface:
vlans.append(interface['vlan_id'])
iname = "%s_%s" % (iname, interface['vlan_id'])
if interface['type'] == 'ipv4':
results += """config_{name}="{ip_address} netmask {netmask}"
mac_{name}="{hwaddr}\"\n""".format(
name=iname,
ip_address=interface['ip_address'],
netmask=interface['netmask'],
hwaddr=interface['mac_address']
)
routes = list()
for route in interface['routes']:
if (route['network'] == '0.0.0.0' and
route['netmask'] == '0.0.0.0'):
# add default route if it exists
routes.append('default via {gw}'.format(
name=name,
gw=route['gateway']
))
else:
# add remaining static routes
routes.append('{net} netmask {mask} via {gw}'.format(
net=route['network'],
mask=route['netmask'],
gw=route['gateway']
))
if routes:
routes_string = '\n'.join(route for route in routes)
results += 'routes_{name}="{routes}"'.format(
name=name,
routes=routes_string
# routes='\n'.join(str(route) for route in routes)
)
results += '\n'
elif interface['type'] == 'manual':
results += """config_{name}="null"
mac_{name}="{hwaddr}"
""".format(name=iname, hwaddr=interface['mac_address'])
_enable_gentoo_interface(iname)
else:
results += """config_{name}="dhcp"
mac_{name}="{hwaddr}"
""".format(name=iname, hwaddr=interface['mac_address'])
_enable_gentoo_interface(iname)
if 'bond_mode' in interface:
slaves = ' '.join(interface['slaves'])
results += """slaves_{name}="{slaves}"
mode_{name}="{mode}"
""".format(name=iname, slaves=slaves, mode=interface['bond_mode'])
full_results = "# Automatically generated, do not edit\n"
if vlans:
full_results += 'vlans_{name}="{vlans}"\n'.format(
name=name,
vlans=' '.join(str(vlan) for vlan in vlans))
full_results += results
files_to_write['/etc/conf.d/net.{name}'.format(name=name)] = full_results
return files_to_write
def _setup_gentoo_network_init(sys_interface, interfaces):
for interface in interfaces:
interface_name = '{name}'.format(name=sys_interface)
if 'vlan_id' in interface:
interface_name += ".{vlan}".format(
vlan=interface['vlan_id'])
log.debug('vlan {vlan} found, interface named {name}'.
format(vlan=interface['vlan_id'], name=interface_name))
if 'bond_master' in interface:
continue
_create_gentoo_net_symlink_and_enable(interface_name)
if not interfaces:
_create_gentoo_net_symlink_and_enable(sys_interface)
def _create_gentoo_net_symlink_and_enable(interface_name):
file_path = '/etc/init.d/net.{name}'.format(name=interface_name)
if not os.path.islink(file_path):
log.debug('ln -s /etc/init.d/net.lo {file_path}'.
format(file_path=file_path))
os.symlink('/etc/init.d/net.lo',
'{file_path}'.format(file_path=file_path))
_enable_gentoo_interface(interface_name)
def write_gentoo_interfaces(interfaces, sys_interfaces):
files_to_write = dict()
gen_intfs = {}
# Sort the interfaces by id so that we'll have consistent output order
for iname, interface in sorted(
interfaces.items(), key=lambda x: x[1]['id']):
if interface['type'] == 'ipv6':
continue
raw_macs = interface.get('raw_macs', [interface['mac_address']])
for mac in raw_macs:
if mac not in sys_interfaces:
continue
if 'bond_mode' in interface:
interface['slaves'] = [
sys_interfaces[mac] for mac in interface['raw_macs']]
if 'raw_macs' in interface:
key = tuple(interface['raw_macs'])
if key not in gen_intfs:
gen_intfs[key] = []
gen_intfs[key].append(interface)
else:
key = (interface['mac_address'],)
if key not in gen_intfs:
gen_intfs[key] = []
gen_intfs[key].append(interface)
for raw_macs, interfs in gen_intfs.items():
if len(raw_macs) == 1:
interface_name = sys_interfaces[raw_macs[0]]
else:
interface_name = next(
intf['id'] for intf in interfs if 'bond_mode' in intf)
files_to_write.update(
_write_gentoo_interface(interface_name, interfs))
_setup_gentoo_network_init(interface_name, interfs)
for mac, iname in sorted(
sys_interfaces.items(), key=lambda x: x[1]):
if _exists_gentoo_interface(iname):
# This interface already has a config file, move on
log.debug("%s already has config file, skipping" % iname)
continue
if (mac,) in gen_intfs:
# We have a config drive config, move on
log.debug("%s configured via config-drive" % mac)
continue
interface = {'type': 'ipv4_dhcp', 'mac_address': mac}
files_to_write.update(_write_gentoo_interface(iname, [interface]))
_setup_gentoo_network_init(iname, [])
return files_to_write
def systemd_enable(service, args):
log.debug("Enabling %s via systemctl" % service)
if args.noop:
return
rc = os.system('systemctl enable %s' % service)
if rc != 0:
log.error("Error enabling %s" % service)
sys.exit(rc)
def _exists_debian_interface(name):
file_to_check = '/etc/network/interfaces.d/{name}.cfg'.format(name=name)
return os.path.exists(file_to_check)
def write_debian_interfaces(interfaces, sys_interfaces):
eni_path = '/etc/network/interfaces'
eni_d_path = eni_path + '.d'
files_to_write = dict()
files_to_write[eni_path] = "auto lo\niface lo inet loopback\n"
files_to_write[eni_path] += "source /etc/network/interfaces.d/*.cfg\n"
# Sort the interfaces by id so that we'll have consistent output order
for iname, interface in interfaces.items():
raw_macs = interface.get('raw_macs', [interface['mac_address']])
for mac in raw_macs:
if mac not in sys_interfaces:
continue
vlan_raw_device = None
if 'vlan_id' in interface:
if len(raw_macs) == 1:
vlan_raw_device = sys_interfaces.get(raw_macs[0])
else:
vlan_raw_device = interface['vlan_link']
interface_name = "{0}.{1}".format(vlan_raw_device,
interface['vlan_id'])
elif 'bond_mode' in interface:
interface_name = iname
else:
interface_name = sys_interfaces[interface['mac_address']]
if _exists_debian_interface(interface_name):
continue
iface_path = os.path.join(eni_d_path, '%s.cfg' % interface_name)
if interface['type'] == 'ipv4_dhcp':
result = "auto {0}\n".format(interface_name)
result += "iface {0} inet dhcp\n".format(interface_name)
if vlan_raw_device is not None:
result += " vlan-raw-device {0}\n".format(vlan_raw_device)
result += " hw-mac-address {0}\n".format(
interface['mac_address'])
if 'bond_mode' in interface:
if interface['mac_address']:
result += " hwaddress {0}\n".format(
interface['mac_address'])
result += " bond-mode {0}\n".format(interface['bond_mode'])
result += " bond-miimon {0}\n".format(
interface.get('bond_miimon', 0))
result += " bond-lacp-rate {0}\n".format(
interface.get('bond_lacp_rate', 'slow'))
result += " bond-xmit_hash_policy {0}\n".format(
interface.get('bond_xmit_hash_policy', 'layer2'))
slave_devices = [sys_interfaces[mac]
for mac in interface['raw_macs']]
slaves = ' '.join(slave_devices)
result += " bond-slaves {0}\n".format(slaves)
files_to_write[iface_path] = result
continue
if interface['type'] == 'manual':
result = "auto {0}\n".format(interface_name)
result += "iface {0} inet manual\n".format(interface_name)
if 'bond_master' in interface:
result += " bond-master {0}\n".format(
interface['bond_master'])
if 'bond_mode' in interface:
if interface['mac_address']:
result += " hwaddress {0}\n".format(
interface['mac_address'])
result += " bond-mode {0}\n".format(interface['bond_mode'])
result += " bond-miimon {0}\n".format(
interface.get('bond_miimon', 0))
result += " bond-lacp-rate {0}\n".format(
interface.get('bond_lacp_rate', 'slow'))
result += " bond-xmit_hash_policy {0}\n".format(
interface.get('bond_xmit_hash_policy', 'layer2'))
slave_devices = [sys_interfaces[mac]
for mac in interface['raw_macs']]
slaves = ' '.join(slave_devices)
result += " bond-slaves {0}\n".format(slaves)
files_to_write[iface_path] = result
continue
if interface['type'] == 'ipv6':
link_type = "inet6"
elif interface['type'] == 'ipv4':
link_type = "inet"
# We do not know this type of entry
if not link_type:
continue
result = "auto {0}\n".format(interface_name)
result += "iface {name} {link_type} static\n".format(
name=interface_name, link_type=link_type)
if vlan_raw_device:
result += " vlan-raw-device {0}\n".format(vlan_raw_device)
if 'bond_master' in interface:
result += " bond-master {0}\n".format(
interface['bond_master'])
if 'bond_mode' in interface:
if interface['mac_address']:
result += " hwaddress {0}\n".format(
interface['mac_address'])
result += " bond-mode {0}\n".format(interface['bond_mode'])
result += " bond-miimon {0}\n".format(
interface.get('bond_miimon', 0))
result += " bond-lacp-rate {0}\n".format(
interface.get('bond_lacp_rate', 'slow'))
result += " bond-xmit_hash_policy {0}\n".format(
interface.get('bond_xmit_hash_policy', 'layer2'))
slave_devices = [sys_interfaces[mac]
for mac in interface['raw_macs']]
slaves = ' '.join(slave_devices)
result += " bond-slaves {0}\n".format(slaves)
result += " address {0}\n".format(interface['ip_address'])
result += " netmask {0}\n".format(interface['netmask'])
for route in interface['routes']:
if route['network'] == '0.0.0.0' and route['netmask'] == '0.0.0.0':
result += " gateway {0}\n".format(route['gateway'])
else:
result += post_up.format(
net=route['network'], mask=route['netmask'],
gw=route['gateway'])
result += pre_down.format(
net=route['network'], mask=route['netmask'],
gw=route['gateway'])
files_to_write[iface_path] = result
for mac, iname in sorted(
sys_interfaces.items(), key=lambda x: x[1]):
if _exists_debian_interface(iname):
# This interface already has a config file, move on
continue
inter_macs = [intf['mac_address'] for intf in interfaces.values()]
link_macs = [intf.get('link_mac') for intf in interfaces.values()
if 'vlan_id' in interface]
if mac in inter_macs or mac in link_macs:
# We have a config drive config, move on
continue
result = "auto {0}\n".format(iname)
result += "iface {0} inet dhcp\n".format(iname)
files_to_write[os.path.join(eni_d_path, "%s.cfg" % iname)] = result
return files_to_write
def write_dns_info(dns_servers):
results = ""
for server in dns_servers:
results += "nameserver {0}\n".format(server)
return {'/etc/resolv.conf': results}
def get_config_drive_interfaces(net):
interfaces = {}
if 'networks' not in net or 'links' not in net:
log.debug("No config-drive interfaces defined")
return interfaces
networks = {}
for network in net['networks']:
networks[network['link']] = network
vlans = {}
phys = {}
bonds = {}
for link in net['links']:
if link['type'] == 'vlan':
vlans[link['id']] = link
elif link['type'] == 'bond':
bonds[link['id']] = link
else:
phys[link['id']] = link
for link in vlans.values():
if link['vlan_link'] in phys:
vlan_link = phys[link['vlan_link']]
link['raw_macs'] = [vlan_link['ethernet_mac_address'].lower()]
elif link['vlan_link'] in bonds:
vlan_link = bonds[link['vlan_link']]
link['raw_macs'] = []
for phy in vlan_link['bond_links']:
link['raw_macs'].append(
phys[phy]['ethernet_mac_address'].lower())
link['mac_address'] = link.pop(
'vlan_mac_address', vlan_link['ethernet_mac_address']).lower()
for link in bonds.values():
phy_macs = []
for phy in link.pop('bond_links'):
phy_link = phys[phy]
phy_link['bond_master'] = link['id']
if phy in phys:
phy_macs.append(phy_link['ethernet_mac_address'].lower())
link['raw_macs'] = phy_macs
link['mac_address'] = link.pop('ethernet_mac_address').lower()
if link['id'] not in networks:
link['type'] = 'manual'
interfaces[link['id']] = link
for link in phys.values():
link['mac_address'] = link.pop('ethernet_mac_address').lower()
if link['id'] not in networks:
link['type'] = 'manual'
interfaces[link['id']] = link
for i, network in networks.items():
link = vlans.get(i, phys.get(i, bonds.get(i)))
if not link:
continue
link.update(network)
link['id'] = i
interfaces[i] = link
return interfaces
def get_dns_from_config_drive(net):
if 'services' not in net:
log.debug("No DNS info available from config-drive")
return []
return [
f['address'] for f in net['services'] if f['type'] == 'dns'
]
def write_static_network_info(
interfaces, sys_interfaces, files_to_write, args):
if args.distro in ('debian', 'ubuntu'):
files_to_write.update(
write_debian_interfaces(interfaces, sys_interfaces))
elif args.distro in ('redhat', 'centos', 'fedora', 'suse', 'opensuse'):
files_to_write.update(
write_redhat_interfaces(interfaces, sys_interfaces))
# glean configures interfaces via
# /etc/sysconfig/network-scripts, so we have to ensure that
# the LSB init script /etc/init.d/network gets started!
systemd_enable('network.service', args)
elif args.distro in 'gentoo':
files_to_write.update(
write_gentoo_interfaces(interfaces, sys_interfaces)
)
else:
return False
finish_files(files_to_write, args)
def finish_files(files_to_write, args):
files = sorted(files_to_write.keys())
log.debug("Writing output files")
for k in files:
if not files_to_write[k]:
# Don't write empty files
log.debug("%s is blank, skipped" % k)
continue
if args.noop:
sys.stdout.write("### Write {0}\n{1}".format(k, files_to_write[k]))
continue
retries = 0
while True:
try:
log.debug("Writing output file : %s" % k)
with open(k, 'w') as outfile:
outfile.write(files_to_write[k])
log.debug(" ... done")
break
except IOError as e:
# if we got ELOOP the file was a dangling or bad
# symlink. We're taking ownership of this, so
# overwrite it.
if e.errno == errno.ELOOP and retries < 1:
log.debug("Dangling symlink <%s>; "
"unlinking and trying again" % k)
os.unlink(k)
retries = 1
continue
elif e.errno == errno.EACCESS:
log.debug(" ... is read only, skipped")
break
else:
raise
def is_interface_live(interface, sys_root):
try:
if open('{root}/{iface}/carrier'.format(
root=sys_root, iface=interface)).read().strip() == '1':
return True
except IOError as e:
# We get this error if the link is not up
if e.errno != 22:
raise
return False
def interface_live(iface, sys_root, args):
if is_interface_live(iface, sys_root):
return True
if args.noop:
return False
subprocess.check_call(['ip', 'link', 'set', 'dev', iface, 'up'])
# Poll the interface since it may not come up instantly
for x in range(0, 50):
if is_interface_live(iface, sys_root):
return True
time.sleep(.1)
return False
def is_interface_vlan(iface):
file_name = '/etc/network/interfaces.d/%s.cfg' % iface
if os.path.exists(file_name):
return 'vlan-raw-device' in open(file_name).read()
return False
def get_sys_interfaces(interface, args):
log.debug("Probing system interfaces")
sys_root = os.path.join(args.root, 'sys/class/net')
ignored_interfaces = ('sit', 'tunl', 'bonding_master', 'teql',
'ip6_vti', 'ip6tnl', 'bond', 'lo')
sys_interfaces = {}
if interface is not None:
log.debug("Only considering interface %s from arguments" % interface)
interfaces = [interface]
else:
interfaces = [f for f in os.listdir(sys_root)
if not f.startswith(ignored_interfaces)]
for iface in interfaces:
# if interface is for an already configured vlan, skip it
if is_interface_vlan(iface):
log.debug("Skipping vlan %s" % iface)
continue
mac_addr_type = open(
'%s/%s/addr_assign_type' % (sys_root, iface), 'r').read().strip()
if mac_addr_type != '0':
continue
mac = open('%s/%s/address' % (sys_root, iface), 'r').read().strip()
if interface_live(iface, sys_root, args):
sys_interfaces[mac] = iface
log.debug("Adding system interface %s (%s)" % (iface, mac))
return sys_interfaces
def get_network_info(args):
"""Retrieves network info from config-drive.
If there is no meta_data.json in config-drive, it means that there
is no config drive mounted- which means we know nothing.
"""
config_drive = os.path.join(args.root, 'mnt/config')
network_info_file = '%s/openstack/latest/network_info.json' % config_drive
network_data_file = '%s/openstack/latest/network_data.json' % config_drive
vendor_data_file = '%s/openstack/latest/vendor_data.json' % config_drive
network_info = {}
if os.path.exists(network_info_file):
log.debug("Found network_info file %s" % network_info_file)
network_info = json.load(open(network_info_file))
if os.path.exists(network_data_file):
log.debug("Found network_info file %s" % network_data_file)
network_info = json.load(open(network_data_file))
elif os.path.exists(vendor_data_file):
log.debug("Found vendor_data_file file %s" % vendor_data_file)
vendor_data = json.load(open(vendor_data_file))
if 'network_info' in vendor_data:
log.debug("Found network_info in vendor_data_file")
network_info = vendor_data['network_info']
else:
log.debug("Did not find vendor_data or network_info in config-drive")
if not network_info:
log.debug("Found no network_info in config-drive! "
"Asusming DHCP interfaces")
return network_info
def write_network_info_from_config_drive(args):
"""Write network info from config-drive.
If there is no meta_data.json in config-drive, it means that there
is no config drive mounted- which means we know nothing.
Returns False on any issue, which will cause the writing of
DHCP network files.
"""
network_info = get_network_info(args)
dns = write_dns_info(get_dns_from_config_drive(network_info))
interfaces = get_config_drive_interfaces(network_info)
sys_interfaces = get_sys_interfaces(args.interface, args)
write_static_network_info(interfaces, sys_interfaces, dns, args)
def write_ssh_keys(args):
"""Write ssh-keys from config-drive.
If there is no meta_data.json in config-drive, it means that there
is no config drive mounted- which means we do nothing.
"""
config_drive = os.path.join(args.root, 'mnt/config')
ssh_path = os.path.join(args.root, 'root/.ssh')
meta_data_path = '%s/openstack/latest/meta_data.json' % config_drive
if not os.path.exists(meta_data_path):
return 0
meta_data = json.load(open(meta_data_path))
if 'public_keys' not in meta_data:
return 0
keys_to_write = []
# if we have keys already there, we want to preserve them
if os.path.exists('/root/.ssh/authorized_keys'):
with open('/root/.ssh/authorized_keys', 'r') as fk:
for line in fk:
keys_to_write.append(line.strip())
for (name, key) in meta_data['public_keys'].items():
key_title = "# Injected key {name} by keypair extension".format(
name=name)
if key_title not in keys_to_write:
keys_to_write.append(key_title)
if key not in keys_to_write:
keys_to_write.append(key)
files_to_write = {
'/root/.ssh/authorized_keys': '\n'.join(keys_to_write) + '\n',
}
try:
os.mkdir(ssh_path, 0o700)
except OSError as e:
if e.errno != 17: # not File Exists
raise
finish_files(files_to_write, args)
def set_hostname_from_config_drive(args):
if args.noop:
return
config_drive = os.path.join(args.root, 'mnt/config')
meta_data_path = '%s/openstack/latest/meta_data.json' % config_drive
if not os.path.exists(meta_data_path):
return
meta_data = json.load(open(meta_data_path))
if 'name' not in meta_data:
return
hostname = meta_data['name']
log.debug("Got hostname from meta_data.json : %s" % hostname)
# underscore is not a valid hostname, but it's easy to name your
# host with that on the command-line. be helpful...
if '_' in hostname:
hostname = hostname.replace('_', '-')
log.debug("Fixed up hostname to %s" % hostname)
ret = subprocess.call(['hostname', hostname])
if ret != 0:
raise RuntimeError('Error setting hostname')
else:
# gentoo's hostname file is in a different location
if args.distro is 'gentoo':
with open('/etc/conf.d/hostname', 'w') as fh:
fh.write("hostname=\"{host}\"\n".format(host=hostname))
else:
with open('/etc/hostname', 'w') as fh:
fh.write(hostname)
fh.write('\n')
# generate the lists of hosts and ips
hosts_to_add = {'localhost': '127.0.0.1'}
# get information on the network
hostname_ip = '127.0.1.1'
network_info = get_network_info(args)
if network_info:
interfaces = get_config_drive_interfaces(network_info)
keys = sorted(interfaces.keys())
for key in keys:
interface = interfaces[key]
if interface and 'ip_address' in interface:
hostname_ip = interface['ip_address']
break
# check short hostname and generate list for hosts
hosts_to_add[hostname] = hostname_ip
short_hostname = hostname.split('.')[0]
if short_hostname != hostname:
hosts_to_add[short_hostname] = hostname_ip
for host in hosts_to_add:
host_value = hosts_to_add[host]
# See if we already have a hosts entry for hostname
prog = re.compile('^%s .*%s\n' % (host_value, host))
match = None
if os.path.isfile('/etc/hosts'):
with open('/etc/hosts') as fh:
match = prog.match(fh.read())
# Write out a hosts entry for hostname
if match is None:
with open('/etc/hosts', 'a+') as fh:
fh.write(u'%s %s\n' % (host_value, host))
def main():
parser = argparse.ArgumentParser(description="Static network config")
parser.add_argument(
'-n', '--noop', action='store_true', help='Do not write files')
parser.add_argument(
'--distro', dest='distro',
default=platform.dist()[0].lower(),
help='Override distro (detected "%s")' % platform.dist()[0].lower())
parser.add_argument(
'--root', dest='root', default='/',
help='Mounted root for config drive info, defaults to /')
parser.add_argument(
'-i', '--interface', dest='interface',
default=None, help="Interface to process")
parser.add_argument(
'--ssh', dest='ssh', action='store_true', help="Write ssh key")
parser.add_argument(
'--hostname', dest='hostname', action='store_true',
help="Set the hostname if name is available in config drive.")
parser.add_argument(
'--skip-network', dest='skip', action='store_true',
help="Do not write network info")
parser.add_argument(
'--debug', dest='debug', action='store_true',
help="Enable debugging output")
args = parser.parse_args()
if args.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
log.debug("Starting glean")
log.debug("Detected distro : %s" % args.distro)
with systemlock.Lock('/tmp/glean.lock'):
if args.ssh:
write_ssh_keys(args)
if args.hostname:
set_hostname_from_config_drive(args)
if args.interface != 'lo' and not args.skip:
write_network_info_from_config_drive(args)
log.debug("Done!")
return 0
if __name__ == '__main__':
sys.exit(main())