summaryrefslogtreecommitdiffstats
path: root/plugins/plugin_mdadmconf.py
blob: 5c2b638a7850dce4c835fe00a018cd2ae11b374d (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
# 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"

    @classmethod
    def getDeps(cls):
        return set(["root", "experimental", "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(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 = "mdamd", 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.scannedFileDict = 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
            return

        # 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 mdamd.conf is missing %s."%value, level = PLUGIN, origin = self)
                self._result = ReturnFailure
                return
        # 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
                return

        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)
        self._result = ReturnSuccess

    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._reporting.info("%s does not exist."%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(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,"etc/mdamd.conf.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