summaryrefslogtreecommitdiffstats
path: root/plugins/mdadm_conf.py
blob: 38c5aa1dc3f9d916c4a461f31630282d53d4e4f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# First Aid Kit - diagnostic and repair tool for Linux
# Copyright (C) 2008 Joel Andres Granados <jgranado@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

from pyfirstaidkit.plugins import Plugin,Flow
from pyfirstaidkit.returns import *
from pyfirstaidkit.utils import *
from pyfirstaidkit.reporting import PLUGIN
from pyfirstaidkit.issue import SimpleIssue
from pyfirstaidkit import Config
from pyfirstaidkit.errors import *

import os.path

class MdadmConfig(Plugin):
    """ Addresses the validity and presence of /etc/mdadm.conf """
    flows = Flow.init(Plugin)
    name = "mdadm configuration"
    version = "0.0.1"
    author = "Joel Andres Granados"
    description = "Assess the validity and existence of the mdadm.conf file"

    @classmethod
    def getDeps(cls):
        return set(["root", "filesystem"])

    def __init__(self, *args, **kwargs):
        Plugin.__init__(self, *args, **kwargs)
        self.currentFileDict = {} #what we read from /etc/mdadm.conf
        self.scannedFileDict = {} #what `mdadm --misc --detail --scan`
        self.scannedFile = None # what `mdadm --misc --detail --scan` returns
        self.configFile = os.path.join(Config.system.root,"/etc/mdadm.conf")
        self.backupSpace = self._backups.getBackup(str(self))
        self._issue = SimpleIssue(self.name, "mdadm.con misconfigured")

    def prepare(self):
        # We read the configuration file if it exists
        if os.path.exists(self.configFile):
            self._reporting.info("Gathering information from %s."%
                    self.configFile, level = PLUGIN, origin = self)
            fd = open(self.configFile, "r")
            for line in fd.readlines():
                splitline = line.strip("\n").split(" ")
                if "ARRAY" in splitline:
                    self.currentFileDict[splitline[1]] = splitline
            fd.close()

        else:
            self._reporting.info("File %s was not found."%
                    self.configFile, level = PLUGIN, origin = self)

        # We execute the mdadm command
        self._reporting.info("Scanning for software raid with mdadm.",
                level = PLUGIN, origin = self)
        mdadmargs = ["--misc", "--detail", "--scan"]
        proc = spawnvch(executable = "mdadm", args = mdadmargs,
                chroot = Config.system.root)
        (out, err) = proc.communicate()

        if err == '':
            # means that the command ran with no errors.
            for line in out.__str__().split("\n"):
                splitline = line.strip("\n").split(" ")
                if "ARRAY" in splitline:
                    self.scannedFileDict[splitline[1]] = splitline
            self.scannedFile = out
        else:
            # This should make the flow go to clean.  If there is an error we
            # should not trust what mdadm tells us.
            self._reporting.info("The mdadm command had the following " \
                    "error:%s. The plugin will silently exit."%err,
                    level = PLUGIN, origin = self)
            self._result = None
            return
        self._result = ReturnSuccess
        self._issue.set(reporting = self._reporting, level = PLUGIN,
                origin = self)

    def diagnose(self):
        # If nothing was returned by the mdadm command.  we dont have software
        # raid.
        if len(self.scannedFileDict) == 0:
            self._reporting.info("There was no sofware raid found by the " \
                    "mdadm command.... Nothing to do.", level = PLUGIN,
                    origin = self)
            self._result = ReturnSuccess
            self._issue.set(checked=True, happened=False,
                    reporting=self._reporting, level=PLUGIN, origin=self)
            return

        # If nothing is detected the result is successfull.
        self._result = ReturnSuccess

        # If there is one difference between the configs, regarding the
        # ARRAYS.  We replace the config file. Lets check for missing arrays
        # in the curren config file.
        for key, value in self.scannedFileDict.iteritems():
            if not self.currentFileDict.has_key(key):
                self._reporting.info("Found that the current mdadm.conf is " \
                        "missing: %s."%value, level = PLUGIN, origin = self)
                self._result = ReturnFailure

        # Lets check for additional ARRAYS that should not be there.
        for key, value in self.currentFileDict.iteritems():
            if not self.scannedFileDict.has_key(key):
                self._reporting.info("The followint entry: %s, is in the " \
                        "config file but was not detected by mdadm."%value,
                        level = PLUGIN, origin = self)
                self._result = ReturnFailure

        if self._result == ReturnSuccess:
            self._reporting.info("There was no problem found with the " \
                    "current mdadm.conf file.", level = PLUGIN, origin = self)

        self._issue.set(checked = True,
                happened = (self._result == ReturnFailure),
                reporting = self._reporting, level = PLUGIN, origin = self)

    def backup(self):
        if os.path.isfile(self.configFile):
            self._reporting.info("Making a backup of %s."%
                    self.configFile, level = PLUGIN, origin = self)
            self.backupSpace.backupPath(self.configFile)

        else:
            self._reporting.info("It appears that the file %s does not "\
                    "exist.  No backup attempt will be made."%self.configFile,
                    level = PLUGIN, origin = self)

        self._result = ReturnSuccess

    def fix(self):
        try:
            self._reporting.info("Going to write configuration to %s."%
                    self.configFile, level = PLUGIN, origin = self)
            fd = open(self.configFile, "w")
            fd.write("# File created by Firstaidkit.\n")
            fd.write("# DEVICE partitions\n")
            fd.write("# MAILADDR root\n")
            fd.write(self.scannedFile)
            fd.close()
            self._reporting.info("Configuration file writen.", level = PLUGIN,
                    origin = self)

            # The original mdadm.conf will be restore to
            # mdadm.conf.firstaidkit, just in case.
            self._reporting.info("Will put the old mdadm.conf in %s."%
                    os.path.join(Config.system.root,
                        self.configFile+".firstaidkit"), level=PLUGIN,
                    origin=self)
            self.backupSpace.restoreName(self.configFile,
                    path = self.configFile+".firstaidkit")
            self._result = ReturnSuccess

        except IOError:
            fd.close()
            self._reporting.info("Error occurred while writing %s."%
                    self.configFile, level = PLUGIN, origin = self)
            self._result = ReturnFailure
        self._issue.set(fixed = (self._result == ReturnSuccess),
                reporting = self._reporting, level = PLUGIN, origin = self)

    def restore(self):
        if not self.backupSpace.exists(self.configFile):
            # This is the case where there is no config file.
            self._reporting.info("The backedup file was not present. " \
                    "Assuming that %s was ont present to begin with."%
                    self.configFile, level = PLUGIN, original = self)
        else:
            self._reporting.info("Restoring original file.", level = PLUGIN ,
                    origin = self)
            self.backupSpace.restoreName(self.configFile)
        self._result = ReturnSuccess

    def clean(self):
        self._result = ReturnSuccess

def get_plugin():
    return MdadmConfig