summaryrefslogtreecommitdiffstats
path: root/compass-tasks/actions/health_check/check_dhcp.py
blob: e3bae1ee245d463c54477252b141f66aab931743 (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
# Copyright 2014 Huawei Technologies Co. Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Health Check module for DHCP service."""
import commands
import os
import re
import socket
import xmlrpclib

from compass.actions.health_check import base


class DhcpCheck(base.BaseCheck):
    """dhcp health check class."""

    NAME = "DHCP Check"

    def run(self):
        """do health check."""
        method_name = "self.check_" + self.os_installer['name'] + "_dhcp()"
        return eval(method_name)

    def check_cobbler_dhcp(self):
        """Checks if Cobbler has taken over DHCP service."""

        try:
            remote = xmlrpclib.Server(
                self.os_installer['cobbler_url'],
                allow_none=True)
            credentials = self.os_installer['credentials']
            remote.login(
                credentials['username'], credentials['password'])
        except Exception:
            self._set_status(
                0,
                "[%s]Error: Cannot login to Cobbler with "
                "the tokens provided in the config file" % self.NAME)
            return (self.code, self.messages)

        cobbler_settings = remote.get_settings()
        if cobbler_settings['manage_dhcp'] == 0:
            self.messages.append(
                "[%s]Info: DHCP service is "
                "not managed by Compass" % self.NAME)
            self.code = 0
            return (self.code, self.messages)

        self.check_cobbler_dhcp_template()
        print "[Done]"
        self.check_dhcp_service()
        self.check_dhcp_netmask()
        print "[Done]"
        if self.code == 1:
            self.messages.append(
                "[%s]Info: DHCP health check has completed. "
                "No problems found, all systems go." % self.NAME)

        return (self.code, self.messages)

    def check_cobbler_dhcp_template(self):
        """Validates Cobbler's DHCP template file."""
        print "Checking DHCP template......",
        if os.path.exists("/etc/cobbler/dhcp.template"):
            var_map = {
                "match_next_server": False,
                "match_subnet": False,
                "match_filename": False,
                "match_range": False,
            }

            ip_regex = re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')

            dhcp_template = open("/etc/cobbler/dhcp.template")
            for line in dhcp_template.readlines():
                if line.find("next_server") != -1:
                    elmlist = line.split(" ")
                    for elm in elmlist:
                        if ";" in elm:
                            elm = elm[:-2]

                        if "$next_server" in elm or ip_regex.match(elm):
                            var_map["match_next_server"] = True

                elif line.find("subnet") != -1 and line.find("{") != -1:
                    elmlist = line.split(" ")
                    for elm in elmlist:
                        if ip_regex.match(elm):
                            if elm[-1] == "0" and "255" not in elm:
                                var_map["match_subnet"] = True
                            elif elm[-1] != "0":
                                self.messages.append(
                                    "[%s]Error: Subnet should be set "
                                    "in the form of 192.168.0.0 in"
                                    "/etc/cobbler/dhcp.template" % self.NAME)

                elif line.find("filename") != -1:
                    var_map["match_filename"] = True
                elif line.find("range dynamic-bootp") != -1:
                    elmlist = line.split(" ")
                    ip_count = 0
                    for elm in elmlist:
                        if ";" in elm and "\n" in elm:
                            elm = elm[:-2]

                        if ip_regex.match(elm):
                            ip_count += 1

                    if ip_count != 2:
                        self.messages.append(
                            "[%s]Error: DHCP range should be set "
                            "between two IP addresses in "
                            "/etc/cobbler/dhcp.template" % self.NAME)
                    else:
                        var_map["match_range"] = True

            dhcp_template.close()
            fails = []
            for var in var_map.keys():
                if var_map[var] is False:
                    fails.append(var)

            if len(fails) != 0:
                self._set_status(
                    0,
                    "[%s]Info: DHCP template file "
                    "failed components: %s" % (
                        self.NAME, ' '.join(failed for failed in fails)))

        else:
            self._set_status(
                0,
                "[%s]Error: DHCP template file doesn't exist, "
                "health check failed." % self.NAME)

        return True

    def check_dhcp_netmask(self):
        with open('/etc/dhcp/dhcpd.conf') as conf_reader:
            lines = conf_reader.readlines()
            for line in lines:
                if re.search('^subnet', line):
                    elm_list = line.split(' ')
                    break
            subnet_ip = elm_list[1]
            netmask = elm_list[-2]
            subnet_ip_elm = subnet_ip.split('.')
            netmask_elm = netmask.split('.')
            for index, digit in enumerate(subnet_ip_elm):
                if int(digit) & int(netmask_elm[index]) != int(digit):
                    self._set_status(
                        0,
                        "[%s]Info: DHCP subnet IP and "
                        "netmask do not match" % self.NAME)
                    break
        return True

    def check_dhcp_service(self):
        """Checks if DHCP is running on port 67."""
        print "Checking DHCP service......",
        if not commands.getoutput('pgrep dhcp'):
            self._set_status(
                0,
                "[%s]Error: dhcp service does not "
                "seem to be running" % self.NAME)

        if socket.getservbyport(67) != 'bootps':
            self._set_status(
                0,
                "[%s]Error: bootps is not listening "
                "on port 67" % self.NAME)

        return True