~martin-nowack/ubuntu/utopic/maas/bug-1425837

« back to all changes in this revision

Viewing changes to src/provisioningserver/boot/powernv.py

  • Committer: Package Import Robot
  • Author(s): Julian Edwards, Julian Edwards, Andres Rodriguez
  • Date: 2014-08-21 18:38:27 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20140821183827-9xyb5u2o4l8g3zxj
Tags: 1.6.1+bzr2550-0ubuntu1
* New upstream bugfix release:
  - Auto-link node MACs to Networks (LP: #1341619)

[ Julian Edwards ]
* debian/maas-region-controller.postinst: Don't restart RabbitMQ on
  upgrades, just ensure it's running.  Should prevent a race with the
  cluster celery restarting.
* debian/rules: Pull upstream branch from the right place.

[ Andres Rodriguez ]
* debian/maas-region-controller.postinst: Ensure cluster celery is
  started if it also runs on the region.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2014 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""PowerNV Boot Method"""
 
5
 
 
6
from __future__ import (
 
7
    absolute_import,
 
8
    print_function,
 
9
    unicode_literals,
 
10
    )
 
11
 
 
12
str = None
 
13
 
 
14
__metaclass__ = type
 
15
__all__ = [
 
16
    'PowerNVBootMethod',
 
17
    ]
 
18
 
 
19
import re
 
20
 
 
21
from provisioningserver.boot import (
 
22
    BootMethod,
 
23
    BytesReader,
 
24
    get_parameters,
 
25
    get_remote_mac,
 
26
    )
 
27
from provisioningserver.boot.pxe import (
 
28
    ARP_HTYPE,
 
29
    re_mac_address,
 
30
    )
 
31
from provisioningserver.kernel_opts import compose_kernel_command_line
 
32
from tftp.backend import FilesystemReader
 
33
 
 
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
 
37
# always Ethernet.
 
38
re_config_file = r'''
 
39
    # Optional leading slash(es).
 
40
    ^/*
 
41
    ppc64el           # PowerNV pxe prefix, set by dhcpd
 
42
    /
 
43
    pxelinux[.]cfg    # PXELINUX expects this.
 
44
    /
 
45
    (?: # either a MAC
 
46
        {htype:02x}    # ARP HTYPE.
 
47
        -
 
48
        (?P<mac>{re_mac_address.pattern})    # Capture MAC.
 
49
    | # or "default"
 
50
        default
 
51
    )
 
52
    $
 
53
'''
 
54
 
 
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)
 
58
 
 
59
 
 
60
def format_bootif(mac):
 
61
    """Formats a mac address into the BOOTIF format, expected by
 
62
    the linux kernel."""
 
63
    mac = mac.replace(':', '-')
 
64
    mac = mac.lower()
 
65
    return '%02x-%s' % (ARP_HTYPE.ETHERNET, mac)
 
66
 
 
67
 
 
68
class PowerNVBootMethod(BootMethod):
 
69
 
 
70
    name = "powernv"
 
71
    template_subdir = "pxe"
 
72
    bootloader_path = "pxelinux.0"
 
73
    arch_octet = "00:0E"
 
74
    path_prefix = "ppc64el/"
 
75
 
 
76
    def get_params(self, backend, path):
 
77
        """Gets the matching parameters from the requested path."""
 
78
        match = re_config_file.match(path)
 
79
        if match is not None:
 
80
            return get_parameters(match)
 
81
        if path.lstrip('/').startswith(self.path_prefix):
 
82
            return {'path': path}
 
83
        return None
 
84
 
 
85
    def match_path(self, backend, path):
 
86
        """Checks path for the configuration file that needs to be
 
87
        generated.
 
88
 
 
89
        :param backend: requesting backend
 
90
        :param path: requested path
 
91
        :returns: dict of match params from path, None if no match
 
92
        """
 
93
        params = self.get_params(backend, path)
 
94
        if params is None:
 
95
            return None
 
96
        params['arch'] = "ppc64el"
 
97
        if 'mac' not in params:
 
98
            mac = get_remote_mac()
 
99
            if mac is not None:
 
100
                params['mac'] = mac
 
101
        return params
 
102
 
 
103
    def get_reader(self, backend, kernel_params, **extra):
 
104
        """Render a configuration file as a unicode string.
 
105
 
 
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.
 
111
        """
 
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.
 
115
        if 'path' in extra:
 
116
            path = extra['path']
 
117
            path = path.replace(self.path_prefix, '', 1)
 
118
            target_path = backend.base.descendant(path.split('/'))
 
119
            return FilesystemReader(target_path)
 
120
 
 
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"))
 
126
 
 
127
        template = self.get_template(
 
128
            kernel_params.purpose, kernel_params.arch,
 
129
            kernel_params.subarch)
 
130
        namespace = self.compose_template_namespace(kernel_params)
 
131
 
 
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)
 
136
            if 'mac' in extra:
 
137
                mac = extra['mac']
 
138
                mac = format_bootif(mac)
 
139
                return '%s BOOTIF=%s' % (cmd_line, mac)
 
140
            return cmd_line
 
141
 
 
142
        namespace['kernel_command'] = kernel_command
 
143
        return BytesReader(template.substitute(namespace).encode("utf-8"))
 
144
 
 
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."""