daisy_workflows/image_import/freebsd/translate.py (89 lines of code) (raw):

#!/usr/bin/env python3 # Copyright 2017 Google Inc. All Rights Reserved. # # 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. """Translate the FreeBSD image on a GCE VM. Parameters (retrieved from instance metadata): install_gce_packages: True if GCE agent and SDK should be installed """ import glob import logging import os import subprocess import utils rc_conf = ''' ifconfig_re0="DHCP" sshd_enable="YES" ifconfig_DEFAULT="SYNCDHCP mtu 1460" ntpd_sync_on_start="YES" ''' ntp_conf = ''' server metadata.google.internal iburst ''' console_settings = ''' console="comconsole,vidconsole" comconsole_speed="38400" autoboot_delay="-1" loader_logo="none" ''' google_services = ''' google_startup_enable=YES google_accounts_daemon_enable=YES google_clock_skew_daemon_enable=YES google_instance_setup_enable=YES google_ip_forwarding_daemon_enable=YES google_network_setup_enable=YES ''' def DistroSpecific(c): install_gce = utils.GetMetadataAttribute('install_gce_packages') def UpdateConfigs(config, filename): """ Parses @config and removes left side of '=' char from @filename and then add the full @config to @filename """ # Removing, if it exists if os.path.isfile(filename): for t in config.split('\n'): if t: to_be_removed = t.split('=')[0] c.sh('sed -i -e "/%(pattern)s/d" %(filename)s' % { 'pattern': to_be_removed, 'filename': filename, }) else: # Indicate that a new one is being created throught a comment with open('/etc/resolv.conf', 'w') as f: f.write("# Created by daisy's image import\n") # Adding c.write_append(config, filename) UpdateConfigs(rc_conf, '/etc/rc.conf') if install_gce == 'true': c.sh('ASSUME_ALWAYS_YES=yes pkg update') logging.info('Installing GCE packages.') c.sh('pkg install --yes py27-google-compute-engine google-cloud-sdk') # Activate google services UpdateConfigs(google_services, '/etc/rc.conf') # Update console configuration on boot UpdateConfigs(console_settings, '/boot/loader.conf') # Update device names on fstab c.sh('sed -i -e "s#/dev/ada#/dev/da#" /etc/fstab') # Remove any hard coded DNS settings in resolvconf. logging.info('Resetting resolvconf base.') with open('/etc/resolv.conf', 'w') as f: f.write('\n') class Chroot(object): """ Simple alternative to guestfs lib, as it doesn't exist in FreeBSD """ def __init__(self, device): self.mount_point = '/translate' os.mkdir(self.mount_point) def FindAndMountRootPartition(): """ Try to mount partitions of @device onto @self.mount_point. The root partition should have a 'bin' folder. Return false if not found. """ for part in glob.glob(device + 'p*'): try: self.sh('mount %s %s' % (part, self.mount_point)) # check if a bin folder exists if os.path.isdir(os.path.join(self.mount_point, 'bin')): # Great! Found a desired partition with rootfs return True # No bin folder? Try the next partition self.sh('umount %s' % self.mount_point) except Exception as e: logging.info('Failed to mount %s. Reason: %s. Continuing...' % ( part, e)) # Too bad. Didn't find one return False if not FindAndMountRootPartition(): raise Exception("No root partition found on disk %s" % device) # copy resolv.conf for using internet connection before chroot self.sh('cp /etc/resolv.conf %s/etc/resolv.conf' % self.mount_point) # chroot to that environment os.chroot(self.mount_point) def sh(self, cmd): p = subprocess.Popen(cmd, shell=True) p.communicate() returncode = p.returncode if returncode != 0: raise subprocess.CalledProcessError(returncode, cmd) def write_append(self, content, filename): with open(filename, 'a') as dst: dst.write(content) def main(): # Class will mount appropriate partition on da1 disk c = Chroot('/dev/da1') DistroSpecific(c) # Remove SSH host keys. logging.info('Removing SSH host keys.') c.sh("rm -f /etc/ssh/ssh_host_*") if __name__ == '__main__': utils.RunTranslate(main)