Statistics
| Branch: | Tag: | Revision:

root / image_creator / os_type / linux.py @ 22a6d232

History | View | Annotate | Download (5.9 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from image_creator.os_type.unix import Unix
35
from image_creator.util import warn
36

    
37
from clint.textui import puts, indent
38

    
39
import re
40

    
41

    
42
class Linux(Unix):
43
    def __init__(self, rootdev, ghandler):
44
        super(Linux, self).__init__(rootdev, ghandler)
45
        self._uuid = dict()
46
        self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*')
47

    
48
    def is_persistent(self, dev):
49
        return not self._persistent.match(dev)
50

    
51
    def get_uuid(self, dev):
52
        if dev in self._uuid:
53
            return self._uuid[dev]
54

    
55
        for attr in self.g.blkid(dev):
56
            if attr[0] == 'UUID':
57
                self._uuid[dev] = attr[1]
58
                return attr[1]
59

    
60
    def sysprep_acpid(self):
61
        """Replace acpid powerdown action scripts to automatically shutdown
62
        the system without checking if a GUI is running.
63
        """
64

    
65
        puts('* Fixing acpid powerdown action')
66

    
67
        action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n shutdown -h now '
68
        '\"Power button pressed\"'
69

    
70
        if self.g.is_file('/etc/acpi/powerbtn.sh'):
71
            self.g.write('/etc/acpi/powerbtn.sh', action)
72
        elif self.g.is_file('/etc/acpi/actions/power.sh'):
73
            self.g.write('/etc/acpi/actions/power.sh', action)
74
        else:
75
            with indent(2):
76
                warn("No acpid action file found")
77

    
78
    def sysprep_persistent_net_rules(self):
79
        """Remove udev rules that will keep network interface names persistent
80
        after hardware changes and reboots. Those rules will be created again
81
        the next time the image runs.
82
        """
83

    
84
        puts('* Removing persistent network interface names')
85

    
86
        rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
87
        if self.g.is_file(rule_file):
88
            self.g.rm(rule_file)
89

    
90
    def sysprep_persistent_devs(self):
91
        """Scan fstab and grub configuration files and replace all
92
        non-persistent device appearences with UUIDs.
93
        """
94

    
95
        puts('* Replacing fstab & grub non-persistent device appearences')
96

    
97
        # convert all devices in fstab to persistent
98
        persistent_root = self._persistent_fstab()
99

    
100
        # convert all devices in grub1 to persistent
101
        self._persistent_grub1(persistent_root)
102

    
103
    def _persistent_grub1(self, new_root):
104
        if self.g.is_file('/boot/grub/menu.lst'):
105
            grub1 = '/boot/grub/menu.lst'
106
        elif self.g.is_file('/etc/grub.conf'):
107
            grub1 = '/etc/grub.conf'
108
        else:
109
            return
110

    
111
        self.g.aug_init('/', 0)
112
        try:
113
            roots = self.g.aug_match('/files%s/title[*]/kernel/root' % grub1)
114
            for root in roots:
115
                dev = self.g.aug_get(root)
116
                if not self.is_persistent(dev):
117
                    # This is not always correct. Grub may contain root entries
118
                    # for other systems, but we only support 1 OS per hard
119
                    # disk, so this shouldn't harm.
120
                    self.g.aug_set(root, new_root)
121
        finally:
122
            self.g.aug_save()
123
            self.g.aug_close()
124

    
125
    def _persistent_fstab(self):
126
        mpoints = self.g.mountpoints()
127
        if len(mpoints) == 0:
128
            pass  # TODO: error handling
129

    
130
        device_dict = dict([[mpoint, dev] for dev, mpoint in mpoints])
131

    
132
        root_dev = None
133
        new_fstab = ""
134
        fstab = self.g.cat('/etc/fstab')
135
        for line in fstab.splitlines():
136

    
137
            line, dev, mpoint = self._convert_fstab_line(line, device_dict)
138
            new_fstab += "%s\n" % line
139

    
140
            if mpoint == '/':
141
                root_dev = dev
142

    
143
        self.g.write('/etc/fstab', new_fstab)
144
        if root_dev is None:
145
            pass  # TODO: error handling
146

    
147
        return root_dev
148

    
149
    def _convert_fstab_line(self, line, devices):
150
        orig = line
151
        line = line.split('#')[0].strip()
152
        if len(line) == 0:
153
            return orig, "", ""
154

    
155
        entry = line.split()
156
        if len(entry) != 6:
157
            warn("Detected abnormal entry in fstab")
158
            return orig, "", ""
159

    
160
        dev = entry[0]
161
        mpoint = entry[1]
162

    
163
        if not self.is_persistent(dev):
164
            if mpoint in devices:
165
                dev = "UUID=%s" % self.get_uuid(devices[mpoint])
166
                entry[0] = dev
167
            else:
168
                # comment out the entry
169
                entry[0] = "#%s" % dev
170
            return " ".join(entry), dev, mpoint
171

    
172
        return orig, dev, mpoint
173

    
174
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :