diff --git a/.gitignore b/.gitignore index af68b39..79b1e54 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ .ropeproject .tox .venv +.testrepository AUTHORS Authors build-stamp diff --git a/cloudbaseinit/metadata/factory.py b/cloudbaseinit/metadata/factory.py index 1de2b9d..b97e246 100644 --- a/cloudbaseinit/metadata/factory.py +++ b/cloudbaseinit/metadata/factory.py @@ -22,8 +22,8 @@ cfg.ListOpt( 'metadata_services', default=[ + 'cloudbaseinit.metadata.services.configdrive.ConfigDriveService', 'cloudbaseinit.metadata.services.httpservice.HttpService', - #'cloudbaseinit.metadata.services.configdrive.ConfigDriveService', #'cloudbaseinit.metadata.services.ec2service.EC2Service', #'cloudbaseinit.metadata.services.maasservice.MaaSHttpService', #'cloudbaseinit.metadata.services.cloudstack.CloudStack', diff --git a/cloudbaseinit/metadata/services/osconfigdrive/factory.py b/cloudbaseinit/metadata/services/osconfigdrive/factory.py index cea0986..90ac516 100644 --- a/cloudbaseinit/metadata/services/osconfigdrive/factory.py +++ b/cloudbaseinit/metadata/services/osconfigdrive/factory.py @@ -19,8 +19,14 @@ def get_config_drive_manager(): class_paths = { - 'win32': 'cloudbaseinit.metadata.services.osconfigdrive.windows.' - 'WindowsConfigDriveManager', + 'freebsd10': ( + 'cloudbaseinit.metadata.services.osconfigdrive.freebsd.' + 'FreeBSDConfigDriveManager' + ), + 'win32': ( + 'cloudbaseinit.metadata.services.osconfigdrive.windows.' + 'WindowsConfigDriveManager' + ), } class_path = class_paths.get(sys.platform) diff --git a/cloudbaseinit/metadata/services/osconfigdrive/freebsd.py b/cloudbaseinit/metadata/services/osconfigdrive/freebsd.py new file mode 100644 index 0000000..fa21112 --- /dev/null +++ b/cloudbaseinit/metadata/services/osconfigdrive/freebsd.py @@ -0,0 +1,136 @@ +from cloudbaseinit.metadata.services.osconfigdrive import base +from cloudbaseinit.openstack.common import log as logging +from oslo.config import cfg +import os +import contextlib +import shutil +import subprocess +import tempfile +import re + +LOG = logging.getLogger(__name__) + +class FreeBSDConfigDriveManager(base.BaseConfigDriveManager): + + def get_config_drive_files(self, target_path, check_raw_hhd=True, + check_cdrom=True, check_vfat=True): + config_drive_found = False + + if check_vfat: + LOG.debug('Looking for Config Drive in VFAT filesystems') + config_drive_found = self._get_conf_drive_from_vfat(target_path) + + if not config_drive_found and check_raw_hhd: + LOG.debug('Looking for Config Drive in raw HDDs') + config_drive_found = self._get_conf_drive_from_raw_hdd(target_path) + + if not config_drive_found and check_cdrom: + LOG.debug('Looking for Config Drive in cdrom drives') + config_drive_found = self._get_conf_drive_from_cdrom_drive(target_path) + + return config_drive_found + + def _get_conf_drive_from_vfat(self, target_path): + return False + + def _get_conf_drive_from_raw_hdd(self, target_path): + return False + + def _get_conf_drive_from_cdrom_drive(self, target_path): + cdrom = self._get_cdrom_device() + if not cdrom: + return False + + with tempdir() as tmp: + umount = False + cdrom_mount_point = self._get_existing_cdrom_mount(cdrom) + if not cdrom_mount_point: + try: + mountcmd = ['mount', '-o', 'ro', '-t', 'cd9660', cdrom, tmp] + subprocess.check_call(mountcmd) + umount = tmp + cdrom_mount_point = tmp + except subprocess.CalledProcessError as exc: + LOG.debug('Failed mount of %s as %s: %s', cdrom, tmp, exc) + return False + + with unmounter(umount): + shutil.copytree(cdrom_mount_point, target_path) + return True + + return False + + def _get_cdrom_device(self): + devices = self._get_devices() + cdrom_drives = ['/dev/%s' % d for d in devices if self._is_cdrom(d)] + if len(cdrom_drives): + return cdrom_drives[0] + return None + + def _get_devices(self): + devices = [] + cmd = 'sysctl -n kern.disks' + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) + devices = output.split() + except subprocess.CalledProcessError: + pass + + return devices + + def _is_cdrom(self, device): + cmd = 'glabel status -s %s' % device + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) + return output.startswith('iso9660/config-2') + except subprocess.CalledProcessError: + return False + + def _get_existing_cdrom_mount(self, device): + existing_mounts = self._get_mounts() + mount = None + if device in existing_mounts: + mount = existing_mounts[os.path.realpath(device)]['mountpoint'] + return mount + + def _get_mounts(self): + mounts = {} + mountre = r'^(/dev/[\S]+) on (/.*) \((.+), .+, (.+)\)$' + cmd_output = subprocess.check_output('mount', stderr=subprocess.STDOUT, shell=True) + mount_info = cmd_output.split('\n') + for mount in mount_info: + try: + m = re.search(mountre, mount) + dev = m.group(1) + mp = m.group(2) + fstype = m.group(3) + opts = m.group(4) + except: + continue + + mounts[dev] = { + 'fstype': fstype, + 'mountpoint': mp, + 'opts': opts + } + + return mounts + + +@contextlib.contextmanager +def tempdir(**kwargs): + tdir = tempfile.mkdtemp(**kwargs) + try: + yield tdir + finally: + shutil.rmtree(tdir) + + +@contextlib.contextmanager +def unmounter(umount): + try: + yield umount + finally: + if umount: + umount_cmd = ["umount", umount] + subprocess.check_call(umount_cmd) diff --git a/cloudbaseinit/osutils/freebsd.py b/cloudbaseinit/osutils/freebsd.py index 3ac10e1..8d9ed2b 100644 --- a/cloudbaseinit/osutils/freebsd.py +++ b/cloudbaseinit/osutils/freebsd.py @@ -63,7 +63,7 @@ def get_network_adapters(self): """ if_list = subprocess.check_output(['ifconfig', '-l']).split(' ') # Filter out non-network interfaces - if_list = filter(lambda x: x.startswith(('pflog', 'lo', 'plip')), if_list) + if_list = filter(lambda x: not x.startswith(('pflog', 'lo', 'plip')), if_list) return if_list def set_static_network_config(self, adapter_name, address, netmask, @@ -78,14 +78,19 @@ def set_static_network_config(self, adapter_name, address, netmask, if_cmd = 'ifconfig ' + adapter_name + ' inet ' + address + ' netmask ' + netmask + ' broadcast ' + broadcast route_cmd = 'route add default ' + gateway - resolv_conf = ['domain ' + dnsdomain] - resolv_conf_file = os.popen('resolvconf -a vtnet0', 'w', 1) + resolv_conf = [] + if dnsdomain: + resolv_conf.append('domain ' + dnsdomain) + + resolvconf_cmd = 'resolvconf -a %s' % adapter_name + resolv_conf_file = subprocess.Popen( + resolvconf_cmd, shell=True, bufsize=1, stdin=subprocess.PIPE).stdin for i in dnsnameservers: resolv_conf.append('nameserver ' + i) subprocess.check_call(if_cmd, shell=True) subprocess.check_call(route_cmd, shell=True) - self._add_comment(resolv_conf_file); + self._add_comment(resolv_conf_file) for line in resolv_conf: resolv_conf_file.write(line + '\n') self._add_rc_conf({'ifconfig_' + adapter_name: 'inet ' + address + ' netmask ' + netmask + ' broadcast ' + broadcast, diff --git a/cloudbaseinit/plugins/common/execcmd.py b/cloudbaseinit/plugins/common/execcmd.py index e0f0c56..eb6cb03 100644 --- a/cloudbaseinit/plugins/common/execcmd.py +++ b/cloudbaseinit/plugins/common/execcmd.py @@ -182,7 +182,7 @@ class Python(BaseCommand): class Bash(BaseCommand): extension = '.sh' - command = 'bash' + command = 'sh' class PowershellSysnative(BaseCommand): diff --git a/cloudbaseinit/plugins/common/factory.py b/cloudbaseinit/plugins/common/factory.py index 604c4d6..b1ee5b0 100644 --- a/cloudbaseinit/plugins/common/factory.py +++ b/cloudbaseinit/plugins/common/factory.py @@ -20,6 +20,7 @@ cfg.ListOpt( 'plugins', default=[ + 'cloudbaseinit.plugins.freebsd.networkconfig.NetworkConfigPlugin', 'cloudbaseinit.plugins.freebsd.sethostname.SetHostNamePlugin', 'cloudbaseinit.plugins.freebsd.scramblerootpassword.ScrambleRootPassword', 'cloudbaseinit.plugins.freebsd.createuser.CreateUserPlugin', @@ -28,7 +29,7 @@ 'cloudbaseinit.plugins.freebsd.sshpublickeys.' 'SetUserSSHPublicKeysPlugin', #'cloudbaseinit.plugins.freebsd.extendvolumes.ExtendVolumesPlugin', - #'cloudbaseinit.plugins.freebsd.userdata.UserDataPlugin', + 'cloudbaseinit.plugins.common.userdata.UserDataPlugin', ], help='List of enabled plugin classes, ' 'to executed in the provided order'), diff --git a/cloudbaseinit/plugins/freebsd/networkconfig.py b/cloudbaseinit/plugins/freebsd/networkconfig.py index 878266b..c67c0f7 100644 --- a/cloudbaseinit/plugins/freebsd/networkconfig.py +++ b/cloudbaseinit/plugins/freebsd/networkconfig.py @@ -42,32 +42,12 @@ def execute(self, service, shared_data): if not network_details: return (plugin_base.PLUGIN_EXECUTION_DONE, False) - if 'content_path' not in network_details: - return (base.PLUGIN_EXECUTION_DONE, False) - - content_path = network_details['content_path'] - content_name = content_path.rsplit('/', 1)[-1] - debian_network_conf = service.get_content(content_name) - - LOG.debug('network config content:\n%s' % debian_network_conf) - - # TODO(alexpilotti): implement a proper grammar - m = re.search(r'iface eth0 inet static\s+' - r'address\s+(?P
[^\s]+)\s+' - r'netmask\s+(?P