Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
.ropeproject
.tox
.venv
.testrepository
AUTHORS
Authors
build-stamp
Expand Down
2 changes: 1 addition & 1 deletion cloudbaseinit/metadata/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
10 changes: 8 additions & 2 deletions cloudbaseinit/metadata/services/osconfigdrive/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
136 changes: 136 additions & 0 deletions cloudbaseinit/metadata/services/osconfigdrive/freebsd.py
Original file line number Diff line number Diff line change
@@ -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)
13 changes: 9 additions & 4 deletions cloudbaseinit/osutils/freebsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion cloudbaseinit/plugins/common/execcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class Python(BaseCommand):

class Bash(BaseCommand):
extension = '.sh'
command = 'bash'
command = 'sh'


class PowershellSysnative(BaseCommand):
Expand Down
3 changes: 2 additions & 1 deletion cloudbaseinit/plugins/common/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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'),
Expand Down
35 changes: 8 additions & 27 deletions cloudbaseinit/plugins/freebsd/networkconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,39 +42,20 @@ 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<address>[^\s]+)\s+'
r'netmask\s+(?P<netmask>[^\s]+)\s+'
r'broadcast\s+(?P<broadcast>[^\s]+)\s+'
r'gateway\s+(?P<gateway>[^\s]+)\s+'
r'dns\-nameservers\s+(?P<dnsnameservers>[^\r\n]+)\s+',
debian_network_conf)
if not m:
raise exception.CloudbaseInitException(
"network_details format not recognized")

address = m.group('address')
netmask = m.group('netmask')
broadcast = m.group('broadcast')
gateway = m.group('gateway')
dnsnameservers = m.group('dnsnameservers').strip().split(' ')
address = network_details[0].address
netmask = network_details[0].netmask
broadcast = network_details[0].broadcast
gateway = network_details[0].gateway
dnsdomain = None
dnsnameservers = network_details[0].dnsnameservers

osutils = osutils_factory.get_os_utils()

network_adapter_name = CONF.network_adapter
if not network_adapter_name:
# Get the first available one
available_adapters = osutils.get_network_adapters()
LOG.debug('available adapters: %s', available_adapters)
if not len(available_adapters):
raise exception.CloudbaseInitException(
"No network adapter available")
Expand All @@ -84,6 +65,6 @@ def execute(self, service, shared_data):

reboot_required = osutils.set_static_network_config(
network_adapter_name, address, netmask, broadcast,
gateway, dnsnameservers)
gateway, dnsdomain, dnsnameservers)

return (base.PLUGIN_EXECUTION_DONE, reboot_required)
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,29 @@ def tearDown(self):
def _test_get_config_drive_manager(self, mock_load_class, platform):
sys.platform = platform

if platform is not "win32":
self.assertRaises(NotImplementedError,
factory.get_config_drive_manager)

else:
caught_notimplemented = False
try:
response = factory.get_config_drive_manager()
self.assertIsNotNone(response)
except NotImplementedError:
caught_notimplemented = True

if platform == 'win32':
mock_load_class.assert_called_once_with(
'cloudbaseinit.metadata.services.osconfigdrive.'
'windows.WindowsConfigDriveManager')

self.assertIsNotNone(response)
elif platform == 'freebsd10':
mock_load_class.assert_called_once_with(
'cloudbaseinit.metadata.services.osconfigdrive.'
'freebsd.FreeBSDConfigDriveManager')
else:
self.assertTrue(caught_notimplemented, 'NotImplementedError expected')

def test_get_config_drive_manager(self):
self._test_get_config_drive_manager(platform="win32")

def test_get_config_drive_manager_exception(self):
self._test_get_config_drive_manager(platform="other")

def test_get_config_drive_manager(self):
self._test_get_config_drive_manager(platform="freebsd10")
Loading