1
# Copyright 2012-2013 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Generating PXE configuration files.
6
For more about the format of these files:
8
http://www.syslinux.org/wiki/index.php/SYSLINUX#How_do_I_Configure_SYSLINUX.3F
11
from __future__ import (
25
from errno import ENOENT
28
from provisioningserver.kernel_opts import compose_kernel_command_line
29
from provisioningserver.pxe.tftppath import compose_image_path
30
from provisioningserver.utils import locate_config
33
# Location of PXE templates, relative to the configuration directory.
34
TEMPLATES_DIR = 'templates/pxe'
37
def gen_pxe_template_filenames(purpose, arch, subarch):
38
"""List possible PXE template filenames.
40
:param purpose: The boot purpose, e.g. "local".
41
:param arch: Main machine architecture.
42
:param subarch: Sub-architecture, or "generic" if there is none.
43
:param release: The Ubuntu release to be used.
45
Returns a list of possible PXE template filenames using the following
48
config.{purpose}.{arch}.{subarch}.template
49
config.{purpose}.{arch}.template
50
config.{purpose}.template
54
elements = [purpose, arch, subarch]
55
while len(elements) >= 1:
56
yield "config.%s.template" % ".".join(elements)
58
yield "config.template"
61
def get_pxe_template(purpose, arch, subarch):
62
pxe_templates_dir = locate_config(TEMPLATES_DIR)
63
# Templates are loaded each time here so that they can be changed on
64
# the fly without restarting the provisioning server.
65
for filename in gen_pxe_template_filenames(purpose, arch, subarch):
66
template_name = path.join(pxe_templates_dir, filename)
68
return tempita.Template.from_filename(
69
template_name, encoding="UTF-8")
70
except IOError as error:
71
if error.errno != ENOENT:
75
"No PXE template found in %r for:\n"
76
" Purpose: %r, Arch: %r, Subarch: %r\n"
77
"This can happen if you manually power up a node when its "
78
"state is not one that allows it. Is the node in the 'Declared' "
79
"or 'Ready' states? It needs to be Enlisting, Commissioning or "
81
pxe_templates_dir, purpose, arch, subarch))
83
raise AssertionError(error)
86
def render_pxe_config(kernel_params, **extra):
87
"""Render a PXE configuration file as a unicode string.
89
:param kernel_params: An instance of `KernelParameters`.
90
:param extra: Allow for other arguments. This is a safety valve;
91
parameters generated in another component (for example, see
92
`TFTPBackend.get_config_reader`) won't cause this to break.
94
template = get_pxe_template(
95
kernel_params.purpose, kernel_params.arch,
96
kernel_params.subarch)
98
# The locations of the kernel image and the initrd are defined by
99
# update_install_files(), in scripts/maas-import-pxe-files.
101
def image_dir(params):
102
return compose_image_path(
103
params.arch, params.subarch,
104
params.release, params.purpose)
106
def initrd_path(params):
107
return "%s/initrd.gz" % image_dir(params)
109
def kernel_path(params):
110
return "%s/linux" % image_dir(params)
112
def kernel_command(params):
113
return compose_kernel_command_line(params)
116
"initrd_path": initrd_path,
117
"kernel_command": kernel_command,
118
"kernel_params": kernel_params,
119
"kernel_path": kernel_path,
121
return template.substitute(namespace)