~ubuntu-branches/ubuntu/raring/maas/raring-proposed

« back to all changes in this revision

Viewing changes to src/maasserver/management/commands/install_pxe_bootloader.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2012-07-17 08:28:36 UTC
  • mfrom: (1.1.16)
  • Revision ID: package-import@ubuntu.com-20120717082836-ucb2vou8tqg353eq
Tags: 0.1+bzr777+dfsg-0ubuntu1
* New upstream release
* Only run 'maas' command as root. (LP: #974046)
  - debian/extras/maas: Check id.
  - debian/maas.install: Install in 'sbin'.
* debian/maas.postinst:
  - restart apache2 after everything gets processed.
  - Update version to handle upgrades.
* debian/extras/maas-provision: Add wrapper to access 'maasprovisiong'
  command line.
* debian/patches/99_temporary_fix_path.patch: Dropped. No longer needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2012 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
 
4
 
"""Install a PXE pre-boot loader for TFTP download."""
5
 
 
6
 
from __future__ import (
7
 
    absolute_import,
8
 
    print_function,
9
 
    unicode_literals,
10
 
    )
11
 
 
12
 
__metaclass__ = type
13
 
__all__ = [
14
 
    'Command',
15
 
    ]
16
 
 
17
 
import filecmp
18
 
from optparse import make_option
19
 
import os.path
20
 
from shutil import copyfile
21
 
 
22
 
from celeryconfig import TFTPROOT
23
 
from django.core.management.base import BaseCommand
24
 
from provisioningserver.pxe.tftppath import (
25
 
    compose_bootloader_path,
26
 
    locate_tftp_path,
27
 
    )
28
 
 
29
 
 
30
 
def make_destination(tftproot, arch, subarch):
31
 
    """Locate a loader's destination.  Create containing directory if needed.
32
 
 
33
 
    :param tftproot: The root directory served up by the TFTP server,
34
 
        e.g. /var/lib/tftpboot/.
35
 
    :param arch: Main architecture to locate the destination for.
36
 
    :param subarch: Sub-architecture of the main architecture.
37
 
    :return: Full path describing the filename that the installed loader
38
 
        should end up having.  For example, the loader for i386 (with
39
 
        sub-architecture "generic") should install at
40
 
        /maas/i386/generic/pxelinux.0.
41
 
    """
42
 
    path = locate_tftp_path(
43
 
        compose_bootloader_path(arch, subarch),
44
 
        tftproot=tftproot)
45
 
    directory = os.path.dirname(path)
46
 
    if not os.path.isdir(directory):
47
 
        os.makedirs(directory)
48
 
    return path
49
 
 
50
 
 
51
 
def are_identical_files(old, new):
52
 
    """Are `old` and `new` identical?
53
 
 
54
 
    If `old` does not exist, the two are considered different (`new` is
55
 
    assumed to exist).
56
 
    """
57
 
    if os.path.isfile(old):
58
 
        return filecmp.cmp(old, new, shallow=False)
59
 
    else:
60
 
        return False
61
 
 
62
 
 
63
 
def install_bootloader(loader, destination):
64
 
    """Install bootloader file at path `loader` as `destination`.
65
 
 
66
 
    Installation will be atomic.  If an identical loader is already
67
 
    installed, it will be left untouched.
68
 
 
69
 
    However it is still conceivable, depending on the TFTP implementation,
70
 
    that a download that is already in progress may suddenly start receiving
71
 
    data from the new file instead of the one it originally started
72
 
    downloading.
73
 
 
74
 
    :param loader: Name of loader to install.
75
 
    :param destination: Loader's intended filename, including full path,
76
 
        where it will become available over TFTP.
77
 
    """
78
 
    if are_identical_files(destination, loader):
79
 
        return
80
 
 
81
 
    # Copy new loader next to the old one, to ensure that it is on the
82
 
    # same filesystem.  Once it is, we can replace the old one with an
83
 
    # atomic rename operation.
84
 
    temp_file = '%s.new' % destination
85
 
    if os.path.exists(temp_file):
86
 
        os.remove(temp_file)
87
 
    copyfile(loader, temp_file)
88
 
    os.rename(temp_file, destination)
89
 
 
90
 
 
91
 
class Command(BaseCommand):
92
 
    """Install a PXE pre-boot loader into the TFTP directory structure.
93
 
 
94
 
    This won't overwrite an existing loader if its contents are unchanged.
95
 
    However the new loader you give it will be deleted regardless.
96
 
    """
97
 
 
98
 
    option_list = BaseCommand.option_list + (
99
 
        make_option(
100
 
            '--arch', dest='arch', default=None,
101
 
            help="Main system architecture that the bootloader is for."),
102
 
        make_option(
103
 
            '--subarch', dest='subarch', default='generic',
104
 
            help="Sub-architecture of the main architecture."),
105
 
        make_option(
106
 
            '--loader', dest='loader', default=None,
107
 
            help="PXE pre-boot loader to install."),
108
 
        make_option(
109
 
            '--tftproot', dest='tftproot', default=TFTPROOT,
110
 
            help="Store to this TFTP directory tree instead of the default."),
111
 
        )
112
 
 
113
 
    def handle(self, arch=None, subarch=None, loader=None, tftproot=None,
114
 
               **kwargs):
115
 
        if tftproot is None:
116
 
            tftproot = TFTPROOT
117
 
 
118
 
        install_bootloader(loader, make_destination(tftproot, arch, subarch))
119
 
 
120
 
        if os.path.exists(loader):
121
 
            os.remove(loader)