# 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 logging import os import subprocess import sys log = logging.getLogger("glean-install") def _find_gleansh_path(): # the "glean.sh" file is installed in /usr/bin/ on Fedora, and # /usr/local/bin on Ubuntu/Debian thanks to differences in pip and # where it likes to put scripts. if os.path.exists("/usr/local/bin/glean.sh"): return "/usr/local/bin" if os.path.exists("/usr/bin/glean.sh"): return "/usr/bin" log.error("Unable to find glean.sh!") sys.exit(1) def install(source_file, target_file, mode='0755', replacements=dict()): """Install given SOURCE_FILE to TARGET_FILE with given MODE REPLACEMENTS is a dictionary where each KEY will result in the template "%%KEY%%" being replaced with its VALUE in TARGET_FILE (this is just a sed -i wrapper) :param source_file: file to be installed :param target_file: location file is being installed to :param mode: mode of file being installed :param replacements: dict of key/value replacements to the file """ log.info("Installing %s -> %s" % (source_file, target_file)) script_dir = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'init') cmd = ('install -D -g root -o root' ' -m {mode} {source_file} {target_file}').format( source_file=os.path.join(script_dir, source_file), target_file=target_file, mode=mode) log.info(cmd) ret = os.system(cmd) if ret != 0: log.error("Failed to install %s!" % source_file) sys.exit(ret) for k, v in replacements.items(): log.info("Replacing %s -> %s in %s" % (k, v, target_file)) cmd = 'sed -i "s|%%{k}%%|{v}|g" {target_file}'.format( k=k, v=v, target_file=target_file) log.info(cmd) ret = os.system(cmd) if ret != 0: log.error("Failed to substitute in %s" % target_file) sys.exit(ret) def main(): parser = argparse.ArgumentParser( description='Install glean init components') parser.add_argument("-n", "--use-nm", help="Use NetworkManager", action="store_true") parser.add_argument("-q", "--quiet", help="Be very quiet", action="store_true") args = parser.parse_args() p = _find_gleansh_path() if args.quiet: logging.basicConfig(level=logging.ERROR) else: logging.basicConfig(level=logging.INFO) # needs to go first because gentoo can have systemd along side openrc if os.path.exists('/etc/gentoo-release'): log.info('installing openrc services') install('glean.openrc', '/etc/init.d/glean', replacements={'GLEANSH_PATH': p}) # Needs to check for the presence of systemd and systemctl # as apparently some packages may stage systemd init files # when systemd is not present. # We also cannot check the path for the init pid as the pid # may be wrong as install is generally executed in a chroot # with diskimage-builder. if (os.path.exists('/usr/lib/systemd/system') and (os.path.exists('/usr/bin/systemctl') or os.path.exists('/bin/systemctl'))): log.info("Installing systemd services") log.info("glean.sh in %s" % p) if os.path.exists('/etc/gentoo-release'): install( 'glean-networkd.service', '/lib/systemd/system/glean.service', mode='0644', replacements={'GLEANSH_PATH': p}) subprocess.call(['systemctl', 'enable', 'glean.service']) else: log.info("Installing %s NetworkManager support" % "with" if args.use_nm else "without") if args.use_nm: service_file = 'glean-nm@.service' else: service_file = 'glean@.service' install( service_file, '/usr/lib/systemd/system/glean@.service', mode='0644', replacements={'GLEANSH_PATH': p}) install( 'glean-udev.rules', '/etc/udev/rules.d/99-glean.rules', mode='0644') if args.use_nm: # glean handles resolv.conf, so this turns off nm touching # it install('nm-no-resolv-handling.conf', '/etc/NetworkManager/conf.d/nm-no-resolv-handling.conf', mode='0644') # NetworkManager has a "after" network-pre, and # glean@ services have a "before". However, if # udev has not yet triggered and started the glean # service, which it seems can be quite common in a slow # environment like a binary-translated nested-vm, systemd # may think it is fine to start NetworkManager because # network-pre has been reached with no blockers. Thus we # override NetworkManager to wait for udev-settle, which # should ensure the glean service has started; which will # block network-pre until it finishes writing out the # configs. install( 'nm-udev-settle.override', '/etc/systemd/system/NetworkManager.service.d/override.conf', mode='0644') elif os.path.exists('/etc/init'): log.info("Installing upstart services") install('glean.conf', '/etc/init/glean.conf') elif os.path.exists('/sbin/rc-update'): subprocess.call(['rc-update', 'add', 'glean', 'boot']) else: log.info("Installing sysv services") install('glean.init', '/etc/init.d/glean') os.system('update-rc.d glean defaults') if __name__ == '__main__': main()