1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Module doing node maintenance for Ganeti watcher.
23
24 """
25
26 import logging
27
28 from ganeti import bdev
29 from ganeti import constants
30 from ganeti import errors
31 from ganeti import hypervisor
32 from ganeti import netutils
33 from ganeti import ssconf
34 from ganeti import utils
35 from ganeti import confd
36
37 import ganeti.confd.client
38
39
40 -class NodeMaintenance(object):
41 """Talks to confd daemons and possible shutdown instances/drbd devices.
42
43 """
45 self.store_cb = confd.client.StoreResultCallback()
46 self.filter_cb = confd.client.ConfdFilterCallback(self.store_cb)
47 self.confd_client = confd.client.GetConfdClient(self.filter_cb)
48
49 @staticmethod
51 """Checks whether node maintenance should run.
52
53 """
54 try:
55 return ssconf.SimpleStore().GetMaintainNodeHealth()
56 except errors.ConfigurationError, err:
57 logging.error("Configuration error, not activating node maintenance: %s",
58 err)
59 return False
60
61 @staticmethod
63 """Compute list of hypervisor/running instances.
64
65 """
66 hyp_list = ssconf.SimpleStore().GetHypervisorList()
67 results = []
68 for hv_name in hyp_list:
69 try:
70 hv = hypervisor.GetHypervisor(hv_name)
71 ilist = hv.ListInstances()
72 results.extend([(iname, hv_name) for iname in ilist])
73 except:
74 logging.error("Error while listing instances for hypervisor %s",
75 hv_name, exc_info=True)
76 return results
77
78 @staticmethod
80 """Get list of used DRBD minors.
81
82 """
83 return bdev.DRBD8.GetUsedDevs().keys()
84
85 @classmethod
86 - def DoMaintenance(cls, role):
87 """Maintain the instance list.
88
89 """
90 if role == constants.CONFD_NODE_ROLE_OFFLINE:
91 inst_running = cls.GetRunningInstances()
92 cls.ShutdownInstances(inst_running)
93 drbd_running = cls.GetUsedDRBDs()
94 cls.ShutdownDRBD(drbd_running)
95 else:
96 logging.debug("Not doing anything for role %s", role)
97
98 @staticmethod
99 - def ShutdownInstances(inst_running):
100 """Shutdown running instances.
101
102 """
103 names_running = set([i[0] for i in inst_running])
104 if names_running:
105 logging.info("Following instances should not be running,"
106 " shutting them down: %s", utils.CommaJoin(names_running))
107
108
109 i2h = dict(inst_running)
110 for name in names_running:
111 hv_name = i2h[name]
112 hv = hypervisor.GetHypervisor(hv_name)
113 hv.StopInstance(None, force=True, name=name)
114
115 @staticmethod
116 - def ShutdownDRBD(drbd_running):
117 """Shutdown active DRBD devices.
118
119 """
120 if drbd_running:
121 logging.info("Following DRBD minors should not be active,"
122 " shutting them down: %s", utils.CommaJoin(drbd_running))
123 for minor in drbd_running:
124
125
126
127 bdev.DRBD8._ShutdownAll(minor)
128
130 """Check node status versus cluster desired state.
131
132 """
133 if not constants.ENABLE_CONFD:
134 logging.warning("Confd use not enabled, cannot do maintenance")
135 return
136
137 my_name = netutils.Hostname.GetSysName()
138 req = \
139 confd.client.ConfdClientRequest(type=constants.CONFD_REQ_NODE_ROLE_BYNAME,
140 query=my_name)
141 self.confd_client.SendRequest(req, async=False, coverage=-1)
142 timed_out, _, _ = self.confd_client.WaitForReply(req.rsalt)
143 if not timed_out:
144
145 status, result = self.store_cb.GetResponse(req.rsalt)
146 assert status, "Missing result but received replies"
147 if not self.filter_cb.consistent[req.rsalt]:
148 logging.warning("Inconsistent replies, not doing anything")
149 return
150 self.DoMaintenance(result.server_reply.answer)
151 else:
152 logging.warning("Confd query timed out, cannot do maintenance actions")
153