1
# Copyright 2014 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""PowerNV Boot Method"""
6
from __future__ import (
21
from provisioningserver.boot import (
27
from provisioningserver.boot.pxe import (
31
from provisioningserver.kernel_opts import compose_kernel_command_line
32
from tftp.backend import FilesystemReader
34
# The pxelinux.cfg path is prefixed with the architecture for the
35
# PowerNV nodes. This prefix is set by the path-prefix dhcpd option.
36
# We assume that the ARP HTYPE (hardware type) that PXELINUX sends is
39
# Optional leading slash(es).
41
ppc64el # PowerNV pxe prefix, set by dhcpd
43
pxelinux[.]cfg # PXELINUX expects this.
46
{htype:02x} # ARP HTYPE.
48
(?P<mac>{re_mac_address.pattern}) # Capture MAC.
55
re_config_file = re_config_file.format(
56
htype=ARP_HTYPE.ETHERNET, re_mac_address=re_mac_address)
57
re_config_file = re.compile(re_config_file, re.VERBOSE)
60
def format_bootif(mac):
61
"""Formats a mac address into the BOOTIF format, expected by
63
mac = mac.replace(':', '-')
65
return '%02x-%s' % (ARP_HTYPE.ETHERNET, mac)
68
class PowerNVBootMethod(BootMethod):
71
template_subdir = "pxe"
72
bootloader_path = "pxelinux.0"
74
path_prefix = "ppc64el/"
76
def get_params(self, backend, path):
77
"""Gets the matching parameters from the requested path."""
78
match = re_config_file.match(path)
80
return get_parameters(match)
81
if path.lstrip('/').startswith(self.path_prefix):
85
def match_path(self, backend, path):
86
"""Checks path for the configuration file that needs to be
89
:param backend: requesting backend
90
:param path: requested path
91
:returns: dict of match params from path, None if no match
93
params = self.get_params(backend, path)
96
params['arch'] = "ppc64el"
97
if 'mac' not in params:
98
mac = get_remote_mac()
103
def get_reader(self, backend, kernel_params, **extra):
104
"""Render a configuration file as a unicode string.
106
:param backend: requesting backend
107
:param kernel_params: An instance of `KernelParameters`.
108
:param extra: Allow for other arguments. This is a safety valve;
109
parameters generated in another component (for example, see
110
`TFTPBackend.get_config_reader`) won't cause this to break.
112
# Due to the path prefix, all requested files from the client will
113
# contain that prefix. Removing the prefix from the path will return
114
# the correct path in the tftp root.
117
path = path.replace(self.path_prefix, '', 1)
118
target_path = backend.base.descendant(path.split('/'))
119
return FilesystemReader(target_path)
121
# Return empty config for PowerNV local. PowerNV fails to
122
# support the LOCALBOOT flag. Empty config will allow it
123
# to select the first device.
124
if kernel_params.purpose == 'local':
125
return BytesReader("".encode("utf-8"))
127
template = self.get_template(
128
kernel_params.purpose, kernel_params.arch,
129
kernel_params.subarch)
130
namespace = self.compose_template_namespace(kernel_params)
132
# Modify the kernel_command to inject the BOOTIF. PowerNV fails to
133
# support the IPAPPEND pxelinux flag.
134
def kernel_command(params):
135
cmd_line = compose_kernel_command_line(params)
138
mac = format_bootif(mac)
139
return '%s BOOTIF=%s' % (cmd_line, mac)
142
namespace['kernel_command'] = kernel_command
143
return BytesReader(template.substitute(namespace).encode("utf-8"))
145
def install_bootloader(self, destination):
146
"""Does nothing. No extra boot files are required. All of the boot
147
files from PXEBootMethod will suffice."""