Setting static ip= for baremetal PXE boot.

This patch adds a new option "pxe_network_config" to baremetal PXE driver,
if set it tells the driver to append the network configuration to the
kernel cmdline. Initramfs built with network support could then benefit
from this option and avoid the injection of network configuration files
into the image.

DocImpact

Change-Id: I61dc946f42f8a86eaad0e73b033a0d8da4a74e40
This commit is contained in:
Lucas Alvares Gomes 2013-06-04 17:19:19 +01:00
parent ed6099d77e
commit 68e9b487bf
9 changed files with 89 additions and 66 deletions

View File

@ -116,6 +116,7 @@ class PXEClassMethodsTestCase(BareMetalPXETestCase):
'deployment_ari_path': 'eee',
'aki_path': 'fff',
'ari_path': 'ggg',
'network_info': self.test_network_info,
}
config = pxe.build_pxe_config(**args)
self.assertThat(config, matchers.StartsWith('default deploy'))
@ -140,6 +141,21 @@ class PXEClassMethodsTestCase(BareMetalPXETestCase):
matchers.Not(matchers.Contains('kernel ddd')),
))
def test_build_pxe_network_config(self):
self.flags(
pxe_network_config=True,
group='baremetal',
)
net = utils.get_test_network_info(1)
config = pxe.build_pxe_network_config(net)
self.assertIn('eth0:off', config)
self.assertNotIn('eth1', config)
net = utils.get_test_network_info(2)
config = pxe.build_pxe_network_config(net)
self.assertIn('eth0:off', config)
self.assertIn('eth1:off', config)
def test_build_network_config(self):
net = utils.get_test_network_info(1)
config = pxe.build_network_config(net)
@ -458,7 +474,8 @@ class PXEPublicMethodsTestCase(BareMetalPXETestCase):
bm_utils.random_alnum(32).AndReturn('alnum')
pxe.build_pxe_config(
self.node['id'], 'alnum', iqn,
'aaaa', 'bbbb', 'cccc', 'dddd').AndReturn(pxe_config)
'aaaa', 'bbbb', 'cccc', 'dddd',
self.test_network_info).AndReturn(pxe_config)
bm_utils.write_to_file(pxe_path, pxe_config)
for mac in macs:
bm_utils.create_link_without_raise(
@ -466,7 +483,8 @@ class PXEPublicMethodsTestCase(BareMetalPXETestCase):
self.mox.ReplayAll()
self.driver.activate_bootloader(self.context, self.node, self.instance)
self.driver.activate_bootloader(self.context, self.node, self.instance,
network_info=self.test_network_info)
self.mox.VerifyAll()
@ -515,8 +533,8 @@ class PXEPublicMethodsTestCase(BareMetalPXETestCase):
row = db.bm_node_get(self.context, 1)
self.assertTrue(row['deploy_key'] is None)
self.driver.activate_bootloader(self.context, self.node,
self.instance)
self.driver.activate_bootloader(self.context, self.node, self.instance,
network_info=self.test_network_info)
row = db.bm_node_get(self.context, 1)
self.assertTrue(row['deploy_key'] is not None)

View File

@ -317,7 +317,8 @@ class TileraPublicMethodsTestCase(BareMetalTileraTestCase):
self.mox.ReplayAll()
self.driver.activate_bootloader(self.context, self.node, self.instance)
self.driver.activate_bootloader(self.context, self.node, self.instance,
network_info=self.test_network_info)
self.mox.VerifyAll()
@ -334,8 +335,8 @@ class TileraPublicMethodsTestCase(BareMetalTileraTestCase):
row = db.bm_node_get(self.context, 1)
self.assertTrue(row['deploy_key'] is None)
self.driver.activate_bootloader(self.context, self.node,
self.instance)
self.driver.activate_bootloader(self.context, self.node, self.instance,
network_info=self.test_network_info)
row = db.bm_node_get(self.context, 1)
self.assertTrue(row['deploy_key'] is not None)

View File

@ -30,7 +30,7 @@ class NodeDriver(object):
def destroy_images(self, context, node, instance):
raise NotImplementedError()
def activate_bootloader(self, context, node, instance):
def activate_bootloader(self, context, node, instance, **kwargs):
raise NotImplementedError()
def deactivate_bootloader(self, context, node, instance):

View File

@ -248,7 +248,8 @@ class BareMetalDriver(driver.ComputeDriver):
injected_files=injected_files,
network_info=network_info,
)
self.driver.activate_bootloader(context, node, instance)
self.driver.activate_bootloader(context, node, instance,
network_info=network_info)
self.power_on(instance, node)
self.driver.activate_node(context, node, instance)
_update_state(context, node, instance, baremetal_states.ACTIVE)

View File

@ -28,7 +28,7 @@ class FakeDriver(base.NodeDriver):
def destroy_images(self, context, node, instance):
pass
def activate_bootloader(self, context, node, instance):
def activate_bootloader(self, context, node, instance, **kwargs):
pass
def deactivate_bootloader(self, context, node, instance):

View File

@ -54,6 +54,10 @@ pxe_opts = [
cfg.IntOpt('pxe_deploy_timeout',
help='Timeout for PXE deployments. Default: 0 (unlimited)',
default=0),
cfg.BoolOpt('pxe_network_config',
help='If set, pass the network configuration details to the '
'initramfs via cmdline.',
default=False),
]
LOG = logging.getLogger(__name__)
@ -77,9 +81,22 @@ def _get_cheetah():
return CHEETAH
def build_pxe_network_config(network_info):
interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6)
template = None
if not CONF.use_ipv6:
template = "ip=%(address)s::%(gateway)s:%(netmask)s::%(name)s:off"
else:
template = ("ip=[%(address_v6)s]::[%(gateway_v6)s]:"
"[%(netmask_v6)s]::%(name)s:off")
net_config = [template % iface for iface in interfaces]
return ' '.join(net_config)
def build_pxe_config(deployment_id, deployment_key, deployment_iscsi_iqn,
deployment_aki_path, deployment_ari_path,
aki_path, ari_path):
aki_path, ari_path, network_info):
"""Build the PXE config file for a node
This method builds the PXE boot configuration file for a node,
@ -90,6 +107,11 @@ def build_pxe_config(deployment_id, deployment_key, deployment_iscsi_iqn,
"""
LOG.debug(_("Building PXE config for deployment %s.") % deployment_id)
network_config = None
if network_info and CONF.baremetal.pxe_network_config:
network_config = build_pxe_network_config(network_info)
pxe_options = {
'deployment_id': deployment_id,
'deployment_key': deployment_key,
@ -99,6 +121,7 @@ def build_pxe_config(deployment_id, deployment_key, deployment_iscsi_iqn,
'aki_path': aki_path,
'ari_path': ari_path,
'pxe_append_params': CONF.baremetal.pxe_append_params,
'pxe_network_config': network_config,
}
cheetah = _get_cheetah()
pxe_config = str(cheetah(
@ -110,33 +133,7 @@ def build_pxe_config(deployment_id, deployment_key, deployment_iscsi_iqn,
def build_network_config(network_info):
# TODO(deva): fix assumption that device names begin with "eth"
# and fix assumption about ordering
try:
assert isinstance(network_info, list)
except AssertionError:
network_info = [network_info]
interfaces = []
for id, (network, mapping) in enumerate(network_info):
address_v6 = None
gateway_v6 = None
netmask_v6 = None
if CONF.use_ipv6:
address_v6 = mapping['ip6s'][0]['ip']
netmask_v6 = mapping['ip6s'][0]['netmask']
gateway_v6 = mapping['gateway_v6']
interface = {
'name': 'eth%d' % id,
'address': mapping['ips'][0]['ip'],
'gateway': mapping['gateway'],
'netmask': mapping['ips'][0]['netmask'],
'dns': ' '.join(mapping['dns']),
'address_v6': address_v6,
'gateway_v6': gateway_v6,
'netmask_v6': netmask_v6,
}
interfaces.append(interface)
interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6)
cheetah = _get_cheetah()
network_config = str(cheetah(
open(CONF.baremetal.net_config_template).read(),
@ -354,7 +351,7 @@ class PXE(base.NodeDriver):
bm_utils.unlink_without_raise(get_image_file_path(instance))
bm_utils.rmtree_without_raise(get_image_dir_path(instance))
def activate_bootloader(self, context, node, instance):
def activate_bootloader(self, context, node, instance, network_info):
"""Configure PXE boot loader for an instance
Kernel and ramdisk images are downloaded by cache_tftp_images,
@ -398,6 +395,7 @@ class PXE(base.NodeDriver):
image_info['deploy_ramdisk'][1],
image_info['kernel'][1],
image_info['ramdisk'][1],
network_info,
)
bm_utils.write_to_file(pxe_config_file_path, pxe_config)

View File

@ -8,4 +8,4 @@ ipappend 3
label boot
kernel ${pxe_options.aki_path}
append initrd=${pxe_options.ari_path} root=${ROOT} ro ${pxe_options.pxe_append_params}
append initrd=${pxe_options.ari_path} root=${ROOT} ro ${pxe_options.pxe_append_params} ${pxe_options.pxe_network_config}

View File

@ -64,31 +64,7 @@ def _get_cheetah():
def build_network_config(network_info):
try:
assert isinstance(network_info, list)
except AssertionError:
network_info = [network_info]
interfaces = []
for id, (network, mapping) in enumerate(network_info):
address_v6 = None
gateway_v6 = None
netmask_v6 = None
if CONF.use_ipv6:
address_v6 = mapping['ip6s'][0]['ip']
netmask_v6 = mapping['ip6s'][0]['netmask']
gateway_v6 = mapping['gateway_v6']
interface = {
'name': 'eth%d' % id,
'address': mapping['ips'][0]['ip'],
'gateway': mapping['gateway'],
'netmask': mapping['ips'][0]['netmask'],
'dns': ' '.join(mapping['dns']),
'address_v6': address_v6,
'gateway_v6': gateway_v6,
'netmask_v6': netmask_v6,
}
interfaces.append(interface)
interfaces = bm_utils.map_network_interfaces(network_info, CONF.use_ipv6)
cheetah = _get_cheetah()
network_config = str(cheetah(
open(CONF.baremetal.net_config_template).read(),
@ -271,7 +247,7 @@ class Tilera(base.NodeDriver):
bm_utils.unlink_without_raise(get_image_file_path(instance))
bm_utils.rmtree_without_raise(get_image_dir_path(instance))
def activate_bootloader(self, context, node, instance):
def activate_bootloader(self, context, node, instance, network_info):
"""Configure Tilera boot loader for an instance
Kernel and ramdisk images are downloaded by cache_tftp_images,

View File

@ -81,3 +81,32 @@ def random_alnum(count):
import string
chars = string.ascii_uppercase + string.digits
return "".join(random.choice(chars) for _ in range(count))
def map_network_interfaces(network_info, use_ipv6=False):
# TODO(deva): fix assumption that device names begin with "eth"
# and fix assumption about ordering
if not isinstance(network_info, list):
network_info = [network_info]
interfaces = []
for id, (network, mapping) in enumerate(network_info):
address_v6 = None
gateway_v6 = None
netmask_v6 = None
if use_ipv6:
address_v6 = mapping['ip6s'][0]['ip']
netmask_v6 = mapping['ip6s'][0]['netmask']
gateway_v6 = mapping['gateway_v6']
interface = {
'name': 'eth%d' % id,
'address': mapping['ips'][0]['ip'],
'gateway': mapping['gateway'],
'netmask': mapping['ips'][0]['netmask'],
'dns': ' '.join(mapping['dns']),
'address_v6': address_v6,
'gateway_v6': gateway_v6,
'netmask_v6': netmask_v6,
}
interfaces.append(interface)
return interfaces