Statistics
| Branch: | Tag: | Revision:

root / image_creator / os_type / linux.py @ f953c647

History | View | Annotate | Download (12.8 kB)

1 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
2 121f3bc0 Nikos Skalkotos
#
3 ae48a082 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 ae48a082 Nikos Skalkotos
#
5 ae48a082 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 ae48a082 Nikos Skalkotos
# without modification, are permitted provided that the following
7 ae48a082 Nikos Skalkotos
# conditions are met:
8 ae48a082 Nikos Skalkotos
#
9 ae48a082 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 ae48a082 Nikos Skalkotos
#      disclaimer.
12 ae48a082 Nikos Skalkotos
#
13 ae48a082 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 ae48a082 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 ae48a082 Nikos Skalkotos
#      provided with the distribution.
17 ae48a082 Nikos Skalkotos
#
18 ae48a082 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 ae48a082 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ae48a082 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 ae48a082 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 ae48a082 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 ae48a082 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 ae48a082 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 ae48a082 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 ae48a082 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 ae48a082 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 ae48a082 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 ae48a082 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 ae48a082 Nikos Skalkotos
#
31 ae48a082 Nikos Skalkotos
# The views and conclusions contained in the software and
32 ae48a082 Nikos Skalkotos
# documentation are those of the authors and should not be
33 ae48a082 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 ae48a082 Nikos Skalkotos
# or implied, of GRNET S.A.
35 ae48a082 Nikos Skalkotos
36 121f3bc0 Nikos Skalkotos
"""This module hosts OS-specific code for Linux"""
37 121f3bc0 Nikos Skalkotos
38 f165adc0 Nikos Skalkotos
from image_creator.os_type.unix import Unix, sysprep
39 22a6d232 Nikos Skalkotos
40 a83f5185 Nikos Skalkotos
import re
41 3f70f242 Nikos Skalkotos
import time
42 aa2062ba Nikos Skalkotos
43 8c574358 Nikos Skalkotos
44 aa2062ba Nikos Skalkotos
class Linux(Unix):
45 88f83027 Nikos Skalkotos
    """OS class for Linux"""
46 0eac0256 Nikos Skalkotos
    def __init__(self, image, **kargs):
47 0eac0256 Nikos Skalkotos
        super(Linux, self).__init__(image, **kargs)
48 a83f5185 Nikos Skalkotos
        self._uuid = dict()
49 a83f5185 Nikos Skalkotos
        self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*')
50 a83f5185 Nikos Skalkotos
51 b8d4b14a Nikos Skalkotos
    @sysprep('Removing user accounts with id greater that 1000', enabled=False)
52 b8d4b14a Nikos Skalkotos
    def remove_user_accounts(self):
53 2dcd42b7 Nikos Skalkotos
        """Remove all user accounts with id greater than 1000"""
54 2dcd42b7 Nikos Skalkotos
55 2dcd42b7 Nikos Skalkotos
        if 'USERS' not in self.meta:
56 2dcd42b7 Nikos Skalkotos
            return
57 2dcd42b7 Nikos Skalkotos
58 2dcd42b7 Nikos Skalkotos
        # Remove users from /etc/passwd
59 2dcd42b7 Nikos Skalkotos
        passwd = []
60 2dcd42b7 Nikos Skalkotos
        removed_users = {}
61 2dcd42b7 Nikos Skalkotos
        metadata_users = self.meta['USERS'].split()
62 091c0335 Nikos Skalkotos
        for line in self.image.g.cat('/etc/passwd').splitlines():
63 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
64 2dcd42b7 Nikos Skalkotos
            if int(fields[2]) > 1000:
65 2dcd42b7 Nikos Skalkotos
                removed_users[fields[0]] = fields
66 2dcd42b7 Nikos Skalkotos
                # remove it from the USERS metadata too
67 2dcd42b7 Nikos Skalkotos
                if fields[0] in metadata_users:
68 2dcd42b7 Nikos Skalkotos
                    metadata_users.remove(fields[0])
69 2dcd42b7 Nikos Skalkotos
            else:
70 2dcd42b7 Nikos Skalkotos
                passwd.append(':'.join(fields))
71 2dcd42b7 Nikos Skalkotos
72 2dcd42b7 Nikos Skalkotos
        self.meta['USERS'] = " ".join(metadata_users)
73 2dcd42b7 Nikos Skalkotos
74 2dcd42b7 Nikos Skalkotos
        # Delete the USERS metadata if empty
75 2dcd42b7 Nikos Skalkotos
        if not len(self.meta['USERS']):
76 2dcd42b7 Nikos Skalkotos
            del self.meta['USERS']
77 2dcd42b7 Nikos Skalkotos
78 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/passwd', '\n'.join(passwd) + '\n')
79 2dcd42b7 Nikos Skalkotos
80 2dcd42b7 Nikos Skalkotos
        # Remove the corresponding /etc/shadow entries
81 2dcd42b7 Nikos Skalkotos
        shadow = []
82 091c0335 Nikos Skalkotos
        for line in self.image.g.cat('/etc/shadow').splitlines():
83 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
84 2dcd42b7 Nikos Skalkotos
            if fields[0] not in removed_users:
85 2dcd42b7 Nikos Skalkotos
                shadow.append(':'.join(fields))
86 2dcd42b7 Nikos Skalkotos
87 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/shadow', "\n".join(shadow) + '\n')
88 2dcd42b7 Nikos Skalkotos
89 2dcd42b7 Nikos Skalkotos
        # Remove the corresponding /etc/group entries
90 2dcd42b7 Nikos Skalkotos
        group = []
91 091c0335 Nikos Skalkotos
        for line in self.image.g.cat('/etc/group').splitlines():
92 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
93 2dcd42b7 Nikos Skalkotos
            # Remove groups tha have the same name as the removed users
94 2dcd42b7 Nikos Skalkotos
            if fields[0] not in removed_users:
95 2dcd42b7 Nikos Skalkotos
                group.append(':'.join(fields))
96 2dcd42b7 Nikos Skalkotos
97 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/group', '\n'.join(group) + '\n')
98 2dcd42b7 Nikos Skalkotos
99 2dcd42b7 Nikos Skalkotos
        # Remove home directories
100 2dcd42b7 Nikos Skalkotos
        for home in [field[5] for field in removed_users.values()]:
101 091c0335 Nikos Skalkotos
            if self.image.g.is_dir(home) and home.startswith('/home/'):
102 091c0335 Nikos Skalkotos
                self.image.g.rm_rf(home)
103 2dcd42b7 Nikos Skalkotos
104 b8d4b14a Nikos Skalkotos
    @sysprep('Cleaning up password & locking all user accounts')
105 b8d4b14a Nikos Skalkotos
    def cleanup_passwords(self):
106 2dcd42b7 Nikos Skalkotos
        """Remove all passwords and lock all user accounts"""
107 2dcd42b7 Nikos Skalkotos
108 2dcd42b7 Nikos Skalkotos
        shadow = []
109 2dcd42b7 Nikos Skalkotos
110 091c0335 Nikos Skalkotos
        for line in self.image.g.cat('/etc/shadow').splitlines():
111 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
112 2dcd42b7 Nikos Skalkotos
            if fields[1] not in ('*', '!'):
113 2dcd42b7 Nikos Skalkotos
                fields[1] = '!'
114 2dcd42b7 Nikos Skalkotos
115 2dcd42b7 Nikos Skalkotos
            shadow.append(":".join(fields))
116 2dcd42b7 Nikos Skalkotos
117 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/shadow', "\n".join(shadow) + '\n')
118 2dcd42b7 Nikos Skalkotos
119 7b626c6b Nikos Skalkotos
        # Remove backup file for /etc/shadow
120 7b626c6b Nikos Skalkotos
        self.image.g.rm_rf('/etc/shadow-')
121 7b626c6b Nikos Skalkotos
122 b8d4b14a Nikos Skalkotos
    @sysprep('Fixing acpid powerdown action')
123 b8d4b14a Nikos Skalkotos
    def fix_acpid(self):
124 d144e954 Nikos Skalkotos
        """Replace acpid powerdown action scripts to immediately shutdown the
125 d144e954 Nikos Skalkotos
        system without checking if a GUI is running.
126 9cbb5794 Nikos Skalkotos
        """
127 22a6d232 Nikos Skalkotos
128 3f70f242 Nikos Skalkotos
        powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \
129 f99fe99d Nikos Skalkotos
                          'shutdown -h now "Power button pressed"\n'
130 3f70f242 Nikos Skalkotos
131 3f70f242 Nikos Skalkotos
        events_dir = '/etc/acpi/events'
132 091c0335 Nikos Skalkotos
        if not self.image.g.is_dir(events_dir):
133 e77e66a9 Nikos Skalkotos
            self.out.warn("No acpid event directory found")
134 3f70f242 Nikos Skalkotos
            return
135 3f70f242 Nikos Skalkotos
136 3f70f242 Nikos Skalkotos
        event_exp = re.compile('event=(.+)', re.I)
137 3f70f242 Nikos Skalkotos
        action_exp = re.compile('action=(.+)', re.I)
138 091c0335 Nikos Skalkotos
        for events_file in self.image.g.readdir(events_dir):
139 121f3bc0 Nikos Skalkotos
            if events_file['ftyp'] != 'r':
140 3f70f242 Nikos Skalkotos
                continue
141 3f70f242 Nikos Skalkotos
142 121f3bc0 Nikos Skalkotos
            fullpath = "%s/%s" % (events_dir, events_file['name'])
143 3f70f242 Nikos Skalkotos
            event = ""
144 3f70f242 Nikos Skalkotos
            action = ""
145 091c0335 Nikos Skalkotos
            for line in self.image.g.cat(fullpath).splitlines():
146 121f3bc0 Nikos Skalkotos
                match = event_exp.match(line)
147 121f3bc0 Nikos Skalkotos
                if match:
148 121f3bc0 Nikos Skalkotos
                    event = match.group(1)
149 3f70f242 Nikos Skalkotos
                    continue
150 121f3bc0 Nikos Skalkotos
                match = action_exp.match(line)
151 121f3bc0 Nikos Skalkotos
                if match:
152 121f3bc0 Nikos Skalkotos
                    action = match.group(1)
153 3f70f242 Nikos Skalkotos
                    continue
154 3f70f242 Nikos Skalkotos
155 c0f3abdc Nikos Skalkotos
            if event.strip() in ("button[ /]power", "button/power.*"):
156 3f70f242 Nikos Skalkotos
                if action:
157 091c0335 Nikos Skalkotos
                    if not self.image.g.is_file(action):
158 e77e66a9 Nikos Skalkotos
                        self.out.warn("Acpid action file: %s does not exist" %
159 f99fe99d Nikos Skalkotos
                                      action)
160 3f70f242 Nikos Skalkotos
                        return
161 ec8b2a79 Nikos Skalkotos
                    self.image.g.copy_file_to_file(
162 ec8b2a79 Nikos Skalkotos
                        action, "%s.orig.snf-image-creator-%d" %
163 ec8b2a79 Nikos Skalkotos
                        (action, time.time()))
164 091c0335 Nikos Skalkotos
                    self.image.g.write(action, powerbtn_action)
165 3f70f242 Nikos Skalkotos
                    return
166 3f70f242 Nikos Skalkotos
                else:
167 f99fe99d Nikos Skalkotos
                    self.out.warn("Acpid event file %s does not contain and "
168 f99fe99d Nikos Skalkotos
                                  "action")
169 3f70f242 Nikos Skalkotos
                    return
170 3f70f242 Nikos Skalkotos
            elif event.strip() == ".*":
171 f99fe99d Nikos Skalkotos
                self.out.warn("Found action `.*'. Don't know how to handle "
172 f99fe99d Nikos Skalkotos
                              "this. Please edit `%s' image file manually to "
173 f99fe99d Nikos Skalkotos
                              "make the system immediatelly shutdown when an "
174 f99fe99d Nikos Skalkotos
                              "power button acpi event occures." %
175 f99fe99d Nikos Skalkotos
                              action.strip().split()[0])
176 3f70f242 Nikos Skalkotos
                return
177 3f70f242 Nikos Skalkotos
178 c0f3abdc Nikos Skalkotos
        self.out.warn("No acpi power button event found!")
179 c0f3abdc Nikos Skalkotos
180 b8d4b14a Nikos Skalkotos
    @sysprep('Removing persistent network interface names')
181 b8d4b14a Nikos Skalkotos
    def remove_persistent_net_rules(self):
182 9cbb5794 Nikos Skalkotos
        """Remove udev rules that will keep network interface names persistent
183 9cbb5794 Nikos Skalkotos
        after hardware changes and reboots. Those rules will be created again
184 9cbb5794 Nikos Skalkotos
        the next time the image runs.
185 9cbb5794 Nikos Skalkotos
        """
186 22a6d232 Nikos Skalkotos
187 9cbb5794 Nikos Skalkotos
        rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
188 091c0335 Nikos Skalkotos
        if self.image.g.is_file(rule_file):
189 091c0335 Nikos Skalkotos
            self.image.g.rm(rule_file)
190 9cbb5794 Nikos Skalkotos
191 b8d4b14a Nikos Skalkotos
    @sysprep('Removing swap entry from fstab')
192 b8d4b14a Nikos Skalkotos
    def remove_swap_entry(self):
193 4a2fd05c Nikos Skalkotos
        """Remove swap entry from /etc/fstab. If swap is the last partition
194 4a2fd05c Nikos Skalkotos
        then the partition will be removed when shrinking is performed. If the
195 4a2fd05c Nikos Skalkotos
        swap partition is not the last partition in the disk or if you are not
196 4a2fd05c Nikos Skalkotos
        going to shrink the image you should probably disable this.
197 4a2fd05c Nikos Skalkotos
        """
198 4a2fd05c Nikos Skalkotos
199 4a2fd05c Nikos Skalkotos
        new_fstab = ""
200 091c0335 Nikos Skalkotos
        fstab = self.image.g.cat('/etc/fstab')
201 4a2fd05c Nikos Skalkotos
        for line in fstab.splitlines():
202 4a2fd05c Nikos Skalkotos
203 4a2fd05c Nikos Skalkotos
            entry = line.split('#')[0].strip().split()
204 4a2fd05c Nikos Skalkotos
            if len(entry) == 6 and entry[2] == 'swap':
205 4a2fd05c Nikos Skalkotos
                continue
206 4a2fd05c Nikos Skalkotos
207 4a2fd05c Nikos Skalkotos
            new_fstab += "%s\n" % line
208 4a2fd05c Nikos Skalkotos
209 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/fstab', new_fstab)
210 4a2fd05c Nikos Skalkotos
211 b8d4b14a Nikos Skalkotos
    @sysprep('Replacing fstab & grub non-persistent device references')
212 b8d4b14a Nikos Skalkotos
    def use_persistent_block_device_names(self):
213 f165adc0 Nikos Skalkotos
        """Scan fstab & grub configuration files and replace all non-persistent
214 dcf9274b Vangelis Koukis
        device references with UUIDs.
215 9cbb5794 Nikos Skalkotos
        """
216 22a6d232 Nikos Skalkotos
217 a83f5185 Nikos Skalkotos
        # convert all devices in fstab to persistent
218 a83f5185 Nikos Skalkotos
        persistent_root = self._persistent_fstab()
219 a83f5185 Nikos Skalkotos
220 a83f5185 Nikos Skalkotos
        # convert all devices in grub1 to persistent
221 a83f5185 Nikos Skalkotos
        self._persistent_grub1(persistent_root)
222 a83f5185 Nikos Skalkotos
223 9cbb5794 Nikos Skalkotos
    def _persistent_grub1(self, new_root):
224 121f3bc0 Nikos Skalkotos
        """Replaces non-persistent device name occurencies with persistent
225 121f3bc0 Nikos Skalkotos
        ones in GRUB1 configuration files.
226 121f3bc0 Nikos Skalkotos
        """
227 091c0335 Nikos Skalkotos
        if self.image.g.is_file('/boot/grub/menu.lst'):
228 a83f5185 Nikos Skalkotos
            grub1 = '/boot/grub/menu.lst'
229 091c0335 Nikos Skalkotos
        elif self.image.g.is_file('/etc/grub.conf'):
230 a83f5185 Nikos Skalkotos
            grub1 = '/etc/grub.conf'
231 a83f5185 Nikos Skalkotos
        else:
232 a83f5185 Nikos Skalkotos
            return
233 a83f5185 Nikos Skalkotos
234 091c0335 Nikos Skalkotos
        self.image.g.aug_init('/', 0)
235 a83f5185 Nikos Skalkotos
        try:
236 091c0335 Nikos Skalkotos
            roots = self.image.g.aug_match(
237 091c0335 Nikos Skalkotos
                '/files%s/title[*]/kernel/root' % grub1)
238 a83f5185 Nikos Skalkotos
            for root in roots:
239 091c0335 Nikos Skalkotos
                dev = self.image.g.aug_get(root)
240 121f3bc0 Nikos Skalkotos
                if not self._is_persistent(dev):
241 a83f5185 Nikos Skalkotos
                    # This is not always correct. Grub may contain root entries
242 a83f5185 Nikos Skalkotos
                    # for other systems, but we only support 1 OS per hard
243 a83f5185 Nikos Skalkotos
                    # disk, so this shouldn't harm.
244 091c0335 Nikos Skalkotos
                    self.image.g.aug_set(root, new_root)
245 a83f5185 Nikos Skalkotos
        finally:
246 091c0335 Nikos Skalkotos
            self.image.g.aug_save()
247 091c0335 Nikos Skalkotos
            self.image.g.aug_close()
248 a83f5185 Nikos Skalkotos
249 a83f5185 Nikos Skalkotos
    def _persistent_fstab(self):
250 121f3bc0 Nikos Skalkotos
        """Replaces non-persistent device name occurencies in /etc/fstab with
251 121f3bc0 Nikos Skalkotos
        persistent ones.
252 121f3bc0 Nikos Skalkotos
        """
253 091c0335 Nikos Skalkotos
        mpoints = self.image.g.mountpoints()
254 a83f5185 Nikos Skalkotos
        if len(mpoints) == 0:
255 a83f5185 Nikos Skalkotos
            pass  # TODO: error handling
256 a83f5185 Nikos Skalkotos
257 a83f5185 Nikos Skalkotos
        device_dict = dict([[mpoint, dev] for dev, mpoint in mpoints])
258 a83f5185 Nikos Skalkotos
259 a83f5185 Nikos Skalkotos
        root_dev = None
260 a83f5185 Nikos Skalkotos
        new_fstab = ""
261 091c0335 Nikos Skalkotos
        fstab = self.image.g.cat('/etc/fstab')
262 a83f5185 Nikos Skalkotos
        for line in fstab.splitlines():
263 a83f5185 Nikos Skalkotos
264 a83f5185 Nikos Skalkotos
            line, dev, mpoint = self._convert_fstab_line(line, device_dict)
265 a83f5185 Nikos Skalkotos
            new_fstab += "%s\n" % line
266 a83f5185 Nikos Skalkotos
267 a83f5185 Nikos Skalkotos
            if mpoint == '/':
268 a83f5185 Nikos Skalkotos
                root_dev = dev
269 a83f5185 Nikos Skalkotos
270 091c0335 Nikos Skalkotos
        self.image.g.write('/etc/fstab', new_fstab)
271 a83f5185 Nikos Skalkotos
        if root_dev is None:
272 a83f5185 Nikos Skalkotos
            pass  # TODO: error handling
273 a83f5185 Nikos Skalkotos
274 a83f5185 Nikos Skalkotos
        return root_dev
275 a83f5185 Nikos Skalkotos
276 a83f5185 Nikos Skalkotos
    def _convert_fstab_line(self, line, devices):
277 121f3bc0 Nikos Skalkotos
        """Replace non-persistent device names in an fstab line to their UUID
278 121f3bc0 Nikos Skalkotos
        equivalent
279 121f3bc0 Nikos Skalkotos
        """
280 a83f5185 Nikos Skalkotos
        orig = line
281 a83f5185 Nikos Skalkotos
        line = line.split('#')[0].strip()
282 a83f5185 Nikos Skalkotos
        if len(line) == 0:
283 a83f5185 Nikos Skalkotos
            return orig, "", ""
284 a83f5185 Nikos Skalkotos
285 a83f5185 Nikos Skalkotos
        entry = line.split()
286 a83f5185 Nikos Skalkotos
        if len(entry) != 6:
287 e77e66a9 Nikos Skalkotos
            self.out.warn("Detected abnormal entry in fstab")
288 a83f5185 Nikos Skalkotos
            return orig, "", ""
289 a83f5185 Nikos Skalkotos
290 a83f5185 Nikos Skalkotos
        dev = entry[0]
291 a83f5185 Nikos Skalkotos
        mpoint = entry[1]
292 a83f5185 Nikos Skalkotos
293 121f3bc0 Nikos Skalkotos
        if not self._is_persistent(dev):
294 a83f5185 Nikos Skalkotos
            if mpoint in devices:
295 121f3bc0 Nikos Skalkotos
                dev = "UUID=%s" % self._get_uuid(devices[mpoint])
296 a83f5185 Nikos Skalkotos
                entry[0] = dev
297 a83f5185 Nikos Skalkotos
            else:
298 a83f5185 Nikos Skalkotos
                # comment out the entry
299 a83f5185 Nikos Skalkotos
                entry[0] = "#%s" % dev
300 a83f5185 Nikos Skalkotos
            return " ".join(entry), dev, mpoint
301 a83f5185 Nikos Skalkotos
302 a83f5185 Nikos Skalkotos
        return orig, dev, mpoint
303 aa2062ba Nikos Skalkotos
304 5a33a51f Nikos Skalkotos
    def _do_inspect(self):
305 d0daafa2 Nikos Skalkotos
        """Run various diagnostics to check if media is supported"""
306 d0daafa2 Nikos Skalkotos
307 d0daafa2 Nikos Skalkotos
        self.out.output(
308 d0daafa2 Nikos Skalkotos
            'Checking if the media contains logical volumes (LVM)...', False)
309 d0daafa2 Nikos Skalkotos
310 d0daafa2 Nikos Skalkotos
        has_lvm = True if len(self.image.g.lvs()) else False
311 d0daafa2 Nikos Skalkotos
312 d0daafa2 Nikos Skalkotos
        if has_lvm:
313 d0daafa2 Nikos Skalkotos
            self.out.output()
314 d0daafa2 Nikos Skalkotos
            self.image.set_unsupported('The media contains logical volumes')
315 d0daafa2 Nikos Skalkotos
        else:
316 d0daafa2 Nikos Skalkotos
            self.out.success('no')
317 d0daafa2 Nikos Skalkotos
318 121f3bc0 Nikos Skalkotos
    def _do_collect_metadata(self):
319 121f3bc0 Nikos Skalkotos
        """Collect metadata about the OS"""
320 121f3bc0 Nikos Skalkotos
        super(Linux, self)._do_collect_metadata()
321 121f3bc0 Nikos Skalkotos
        self.meta["USERS"] = " ".join(self._get_passworded_users())
322 121f3bc0 Nikos Skalkotos
323 121f3bc0 Nikos Skalkotos
        # Delete the USERS metadata if empty
324 121f3bc0 Nikos Skalkotos
        if not len(self.meta['USERS']):
325 121f3bc0 Nikos Skalkotos
            self.out.warn("No passworded users found!")
326 121f3bc0 Nikos Skalkotos
            del self.meta['USERS']
327 121f3bc0 Nikos Skalkotos
328 121f3bc0 Nikos Skalkotos
    def _get_passworded_users(self):
329 121f3bc0 Nikos Skalkotos
        """Returns a list of non-locked user accounts"""
330 121f3bc0 Nikos Skalkotos
        users = []
331 47505e53 Nikos Skalkotos
        regexp = re.compile(r'(\S+):((?:!\S+)|(?:[^!*]\S+)|):(?:\S*:){6}')
332 121f3bc0 Nikos Skalkotos
333 091c0335 Nikos Skalkotos
        for line in self.image.g.cat('/etc/shadow').splitlines():
334 121f3bc0 Nikos Skalkotos
            match = regexp.match(line)
335 121f3bc0 Nikos Skalkotos
            if not match:
336 121f3bc0 Nikos Skalkotos
                continue
337 121f3bc0 Nikos Skalkotos
338 121f3bc0 Nikos Skalkotos
            user, passwd = match.groups()
339 121f3bc0 Nikos Skalkotos
            if len(passwd) > 0 and passwd[0] == '!':
340 121f3bc0 Nikos Skalkotos
                self.out.warn("Ignoring locked %s account." % user)
341 121f3bc0 Nikos Skalkotos
            else:
342 121f3bc0 Nikos Skalkotos
                users.append(user)
343 121f3bc0 Nikos Skalkotos
344 121f3bc0 Nikos Skalkotos
        return users
345 121f3bc0 Nikos Skalkotos
346 121f3bc0 Nikos Skalkotos
    def _is_persistent(self, dev):
347 121f3bc0 Nikos Skalkotos
        """Checks if a device name is persistent."""
348 121f3bc0 Nikos Skalkotos
        return not self._persistent.match(dev)
349 121f3bc0 Nikos Skalkotos
350 121f3bc0 Nikos Skalkotos
    def _get_uuid(self, dev):
351 121f3bc0 Nikos Skalkotos
        """Returns the UUID corresponding to a device"""
352 121f3bc0 Nikos Skalkotos
        if dev in self._uuid:
353 121f3bc0 Nikos Skalkotos
            return self._uuid[dev]
354 121f3bc0 Nikos Skalkotos
355 091c0335 Nikos Skalkotos
        uuid = self.image.g.vfs_uuid(dev)
356 121f3bc0 Nikos Skalkotos
        assert len(uuid)
357 121f3bc0 Nikos Skalkotos
        self._uuid[dev] = uuid
358 121f3bc0 Nikos Skalkotos
        return uuid
359 121f3bc0 Nikos Skalkotos
360 aa2062ba Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :