Statistics
| Branch: | Tag: | Revision:

root / image_creator / os_type / linux.py @ d144e954

History | View | Annotate | Download (7.4 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
import time
41

    
42

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

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

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

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

    
61
    def sysprep_acpid(self, print_header=True):
62
        """Replace acpid powerdown action scripts to immediately shutdown the
63
        system without checking if a GUI is running.
64
        """
65

    
66
        if print_header:
67
            print 'Fixing acpid powerdown action'
68

    
69
        powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \
70
                                'shutdown -h now \"Power button pressed\"'
71

    
72
        events_dir = '/etc/acpi/events'
73
        if not self.g.is_dir(events_dir):
74
            warn("No acpid event directory found")
75
            return
76

    
77
        event_exp = re.compile('event=(.+)', re.I)
78
        action_exp = re.compile('action=(.+)', re.I)
79
        for f in self.g.readdir(events_dir):
80
            if f['ftyp'] != 'r':
81
                continue
82

    
83
            fullpath = "%s/%s" % (events_dir, f['name'])
84
            event = ""
85
            action = ""
86
            for line in self.g.cat(fullpath).splitlines():
87
                m = event_exp.match(line)
88
                if m:
89
                    event = m.group(1)
90
                    continue
91
                m = action_exp.match(line)
92
                if m:
93
                    action = m.group(1)
94
                    continue
95

    
96
            if event.strip() == "button[ /]power":
97
                if action:
98
                    if not self.g.is_file(action):
99
                        warn("Acpid action file: %s does not exist" % action)
100
                        return
101
                    self.g.copy_file_to_file(action, \
102
                      "%s.orig.snf-image-creator-%d" % (action, time.time()))
103
                    self.g.write(action, powerbtn_action)
104
                    return
105
                else:
106
                    warn("Acpid event file %s does not contain and action")
107
                    return
108
            elif event.strip() == ".*":
109
                warn("Found action `.*'. Don't know how to handle this." \
110
                    " Please edit \%s' image file manually to make the " \
111
                    "system immediatelly shutdown when an power button acpi " \
112
                    "event occures" % action)
113
                return
114

    
115
    def sysprep_persistent_net_rules(self, print_header=True):
116
        """Remove udev rules that will keep network interface names persistent
117
        after hardware changes and reboots. Those rules will be created again
118
        the next time the image runs.
119
        """
120

    
121
        if print_header:
122
            puts('Removing persistent network interface names')
123

    
124
        rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
125
        if self.g.is_file(rule_file):
126
            self.g.rm(rule_file)
127

    
128
    def sysprep_persistent_devs(self, print_header=True):
129
        """Scan fstab and grub configuration files and replace all
130
        non-persistent device appearences with UUIDs.
131
        """
132

    
133
        if print_header:
134
            puts('Replacing fstab & grub non-persistent device appearences')
135

    
136
        # convert all devices in fstab to persistent
137
        persistent_root = self._persistent_fstab()
138

    
139
        # convert all devices in grub1 to persistent
140
        self._persistent_grub1(persistent_root)
141

    
142
    def _persistent_grub1(self, new_root):
143
        if self.g.is_file('/boot/grub/menu.lst'):
144
            grub1 = '/boot/grub/menu.lst'
145
        elif self.g.is_file('/etc/grub.conf'):
146
            grub1 = '/etc/grub.conf'
147
        else:
148
            return
149

    
150
        self.g.aug_init('/', 0)
151
        try:
152
            roots = self.g.aug_match('/files%s/title[*]/kernel/root' % grub1)
153
            for root in roots:
154
                dev = self.g.aug_get(root)
155
                if not self.is_persistent(dev):
156
                    # This is not always correct. Grub may contain root entries
157
                    # for other systems, but we only support 1 OS per hard
158
                    # disk, so this shouldn't harm.
159
                    self.g.aug_set(root, new_root)
160
        finally:
161
            self.g.aug_save()
162
            self.g.aug_close()
163

    
164
    def _persistent_fstab(self):
165
        mpoints = self.g.mountpoints()
166
        if len(mpoints) == 0:
167
            pass  # TODO: error handling
168

    
169
        device_dict = dict([[mpoint, dev] for dev, mpoint in mpoints])
170

    
171
        root_dev = None
172
        new_fstab = ""
173
        fstab = self.g.cat('/etc/fstab')
174
        for line in fstab.splitlines():
175

    
176
            line, dev, mpoint = self._convert_fstab_line(line, device_dict)
177
            new_fstab += "%s\n" % line
178

    
179
            if mpoint == '/':
180
                root_dev = dev
181

    
182
        self.g.write('/etc/fstab', new_fstab)
183
        if root_dev is None:
184
            pass  # TODO: error handling
185

    
186
        return root_dev
187

    
188
    def _convert_fstab_line(self, line, devices):
189
        orig = line
190
        line = line.split('#')[0].strip()
191
        if len(line) == 0:
192
            return orig, "", ""
193

    
194
        entry = line.split()
195
        if len(entry) != 6:
196
            warn("Detected abnormal entry in fstab")
197
            return orig, "", ""
198

    
199
        dev = entry[0]
200
        mpoint = entry[1]
201

    
202
        if not self.is_persistent(dev):
203
            if mpoint in devices:
204
                dev = "UUID=%s" % self.get_uuid(devices[mpoint])
205
                entry[0] = dev
206
            else:
207
                # comment out the entry
208
                entry[0] = "#%s" % dev
209
            return " ".join(entry), dev, mpoint
210

    
211
        return orig, dev, mpoint
212

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