Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.hooks_unittest.py @ 2a52a064

History | View | Annotate | Download (9.3 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Script for unittesting the hooks module"""
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
import unittest
26 a8083063 Iustin Pop
import os
27 a8083063 Iustin Pop
import time
28 a8083063 Iustin Pop
import tempfile
29 a8083063 Iustin Pop
import os.path
30 a8083063 Iustin Pop
31 a8083063 Iustin Pop
from ganeti import errors
32 a8083063 Iustin Pop
from ganeti import opcodes
33 a8083063 Iustin Pop
from ganeti import mcpu
34 a8083063 Iustin Pop
from ganeti import backend
35 a8083063 Iustin Pop
from ganeti import constants
36 a8083063 Iustin Pop
from ganeti import cmdlib
37 7ccb3074 Guido Trotter
from ganeti import rpc
38 a8083063 Iustin Pop
from ganeti.constants import HKR_SUCCESS, HKR_FAIL, HKR_SKIP
39 a8083063 Iustin Pop
40 c259ce64 Michael Hanselmann
from mocks import FakeConfig, FakeProc, FakeContext
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
class FakeLU(cmdlib.LogicalUnit):
43 a8083063 Iustin Pop
  HPATH = "test"
44 a8083063 Iustin Pop
  def BuildHooksEnv(self):
45 a8083063 Iustin Pop
    return {}, ["localhost"], ["localhost"]
46 a8083063 Iustin Pop
47 a8083063 Iustin Pop
class TestHooksRunner(unittest.TestCase):
48 a8083063 Iustin Pop
  """Testing case for HooksRunner"""
49 a8083063 Iustin Pop
  def setUp(self):
50 a8083063 Iustin Pop
    self.torm = []
51 a8083063 Iustin Pop
    self.tmpdir = tempfile.mkdtemp()
52 a8083063 Iustin Pop
    self.torm.append((self.tmpdir, True))
53 a8083063 Iustin Pop
    self.logdir = tempfile.mkdtemp()
54 a8083063 Iustin Pop
    self.torm.append((self.logdir, True))
55 a8083063 Iustin Pop
    self.hpath = "fake"
56 a8083063 Iustin Pop
    self.ph_dirs = {}
57 a8083063 Iustin Pop
    for i in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
58 a8083063 Iustin Pop
      dname = "%s/%s-%s.d" % (self.tmpdir, self.hpath, i)
59 a8083063 Iustin Pop
      os.mkdir(dname)
60 a8083063 Iustin Pop
      self.torm.append((dname, True))
61 a8083063 Iustin Pop
      self.ph_dirs[i] = dname
62 a8083063 Iustin Pop
    self.hr = backend.HooksRunner(hooks_base_dir=self.tmpdir)
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
  def tearDown(self):
65 a8083063 Iustin Pop
    self.torm.reverse()
66 a8083063 Iustin Pop
    for path, kind in self.torm:
67 a8083063 Iustin Pop
      if kind:
68 a8083063 Iustin Pop
        os.rmdir(path)
69 a8083063 Iustin Pop
      else:
70 a8083063 Iustin Pop
        os.unlink(path)
71 a8083063 Iustin Pop
72 a8083063 Iustin Pop
  def _rname(self, fname):
73 a8083063 Iustin Pop
    return "/".join(fname.split("/")[-2:])
74 a8083063 Iustin Pop
75 a8083063 Iustin Pop
  def testEmpty(self):
76 a8083063 Iustin Pop
    """Test no hooks"""
77 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
78 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), [])
79 a8083063 Iustin Pop
80 a8083063 Iustin Pop
  def testSkipNonExec(self):
81 a8083063 Iustin Pop
    """Test skip non-exec file"""
82 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
83 a8083063 Iustin Pop
      fname = "%s/test" % self.ph_dirs[phase]
84 a8083063 Iustin Pop
      f = open(fname, "w")
85 a8083063 Iustin Pop
      f.close()
86 a8083063 Iustin Pop
      self.torm.append((fname, False))
87 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
88 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
89 a8083063 Iustin Pop
90 a8083063 Iustin Pop
  def testSkipInvalidName(self):
91 a8083063 Iustin Pop
    """Test skip script with invalid name"""
92 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
93 a8083063 Iustin Pop
      fname = "%s/a.off" % self.ph_dirs[phase]
94 a8083063 Iustin Pop
      f = open(fname, "w")
95 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 0\n")
96 a8083063 Iustin Pop
      f.close()
97 a8083063 Iustin Pop
      os.chmod(fname, 0700)
98 a8083063 Iustin Pop
      self.torm.append((fname, False))
99 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
100 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
101 a8083063 Iustin Pop
102 a8083063 Iustin Pop
  def testSkipDir(self):
103 a8083063 Iustin Pop
    """Test skip directory"""
104 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
105 a8083063 Iustin Pop
      fname = "%s/testdir" % self.ph_dirs[phase]
106 a8083063 Iustin Pop
      os.mkdir(fname)
107 a8083063 Iustin Pop
      self.torm.append((fname, True))
108 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
109 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
110 a8083063 Iustin Pop
111 a8083063 Iustin Pop
  def testSuccess(self):
112 a8083063 Iustin Pop
    """Test success execution"""
113 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
114 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
115 a8083063 Iustin Pop
      f = open(fname, "w")
116 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 0\n")
117 a8083063 Iustin Pop
      f.close()
118 a8083063 Iustin Pop
      self.torm.append((fname, False))
119 a8083063 Iustin Pop
      os.chmod(fname, 0700)
120 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
121 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, "")])
122 a8083063 Iustin Pop
123 a8083063 Iustin Pop
  def testSymlink(self):
124 a8083063 Iustin Pop
    """Test running a symlink"""
125 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
126 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
127 a8083063 Iustin Pop
      os.symlink("/bin/true", fname)
128 a8083063 Iustin Pop
      self.torm.append((fname, False))
129 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
130 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, "")])
131 a8083063 Iustin Pop
132 a8083063 Iustin Pop
  def testFail(self):
133 a8083063 Iustin Pop
    """Test success execution"""
134 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
135 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
136 a8083063 Iustin Pop
      f = open(fname, "w")
137 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 1\n")
138 a8083063 Iustin Pop
      f.close()
139 a8083063 Iustin Pop
      self.torm.append((fname, False))
140 a8083063 Iustin Pop
      os.chmod(fname, 0700)
141 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
142 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_FAIL, "")])
143 a8083063 Iustin Pop
144 a8083063 Iustin Pop
  def testCombined(self):
145 a8083063 Iustin Pop
    """Test success, failure and skip all in one test"""
146 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
147 a8083063 Iustin Pop
      expect = []
148 a8083063 Iustin Pop
      for fbase, ecode, rs in [("00succ", 0, HKR_SUCCESS),
149 a8083063 Iustin Pop
                               ("10fail", 1, HKR_FAIL),
150 a8083063 Iustin Pop
                               ("20inv.", 0, HKR_SKIP),
151 a8083063 Iustin Pop
                               ]:
152 a8083063 Iustin Pop
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
153 a8083063 Iustin Pop
        f = open(fname, "w")
154 a8083063 Iustin Pop
        f.write("#!/bin/sh\nexit %d\n" % ecode)
155 a8083063 Iustin Pop
        f.close()
156 a8083063 Iustin Pop
        self.torm.append((fname, False))
157 a8083063 Iustin Pop
        os.chmod(fname, 0700)
158 a8083063 Iustin Pop
        expect.append((self._rname(fname), rs, ""))
159 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
160 a8083063 Iustin Pop
161 a8083063 Iustin Pop
  def testOrdering(self):
162 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
163 a8083063 Iustin Pop
      expect = []
164 a8083063 Iustin Pop
      for fbase in ["10s1",
165 a8083063 Iustin Pop
                    "00s0",
166 a8083063 Iustin Pop
                    "10sa",
167 a8083063 Iustin Pop
                    "80sc",
168 a8083063 Iustin Pop
                    "60sd",
169 a8083063 Iustin Pop
                    ]:
170 a8083063 Iustin Pop
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
171 a8083063 Iustin Pop
        os.symlink("/bin/true", fname)
172 a8083063 Iustin Pop
        self.torm.append((fname, False))
173 a8083063 Iustin Pop
        expect.append((self._rname(fname), HKR_SUCCESS, ""))
174 a8083063 Iustin Pop
      expect.sort()
175 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
176 a8083063 Iustin Pop
177 a8083063 Iustin Pop
  def testEnv(self):
178 a8083063 Iustin Pop
    """Test environment execution"""
179 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
180 a8083063 Iustin Pop
      fbase = "success"
181 a8083063 Iustin Pop
      fname = "%s/%s" % (self.ph_dirs[phase], fbase)
182 a8083063 Iustin Pop
      os.symlink("/usr/bin/env", fname)
183 a8083063 Iustin Pop
      self.torm.append((fname, False))
184 a8083063 Iustin Pop
      env_snt = {"PHASE": phase}
185 7b80424f Iustin Pop
      env_exp = "PHASE=%s" % phase
186 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, env_snt),
187 a8083063 Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, env_exp)])
188 a8083063 Iustin Pop
189 a8083063 Iustin Pop
190 a8083063 Iustin Pop
class TestHooksMaster(unittest.TestCase):
191 a8083063 Iustin Pop
  """Testing case for HooksMaster"""
192 a8083063 Iustin Pop
193 a8083063 Iustin Pop
  def _call_false(*args):
194 a8083063 Iustin Pop
    """Fake call_hooks_runner function which returns False."""
195 a8083063 Iustin Pop
    return False
196 a8083063 Iustin Pop
197 a8083063 Iustin Pop
  @staticmethod
198 a8083063 Iustin Pop
  def _call_nodes_false(node_list, hpath, phase, env):
199 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
200 a8083063 Iustin Pop

201 7ccb3074 Guido Trotter
    @rtype: dict of node -> L{rpc.RpcResult} with an rpc error
202 7ccb3074 Guido Trotter
    @return: rpc failure from all nodes
203 a8083063 Iustin Pop

204 a8083063 Iustin Pop
    """
205 7ccb3074 Guido Trotter
    return dict([(node, rpc.RpcResult('error', failed=True,
206 7ccb3074 Guido Trotter
                  node=node, call='FakeError')) for node in node_list])
207 a8083063 Iustin Pop
208 a8083063 Iustin Pop
  @staticmethod
209 a8083063 Iustin Pop
  def _call_script_fail(node_list, hpath, phase, env):
210 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
211 a8083063 Iustin Pop

212 7ccb3074 Guido Trotter
    @rtype: dict of node -> L{rpc.RpcResult} with a failed script result
213 7ccb3074 Guido Trotter
    @return: script execution failure from all nodes
214 a8083063 Iustin Pop

215 a8083063 Iustin Pop
    """
216 7ccb3074 Guido Trotter
    return dict([(node, rpc.RpcResult([("utest", constants.HKR_FAIL, "err")],
217 7ccb3074 Guido Trotter
                  node=node, call='FakeScriptFail')) for node in node_list])
218 a8083063 Iustin Pop
219 a8083063 Iustin Pop
  @staticmethod
220 a8083063 Iustin Pop
  def _call_script_succeed(node_list, hpath, phase, env):
221 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
222 a8083063 Iustin Pop

223 7ccb3074 Guido Trotter
    @rtype: dict of node -> L{rpc.RpcResult} with a successful script result
224 7ccb3074 Guido Trotter
    @return: script execution from all nodes
225 a8083063 Iustin Pop

226 a8083063 Iustin Pop
    """
227 7ccb3074 Guido Trotter
    return dict([(node, rpc.RpcResult([("utest", constants.HKR_SUCCESS, "ok")],
228 7ccb3074 Guido Trotter
                  node=node, call='FakeScriptOk')) for node in node_list])
229 a8083063 Iustin Pop
230 d2525573 Guido Trotter
  def setUp(self):
231 d2525573 Guido Trotter
    self.op = opcodes.OpCode()
232 77b657a3 Guido Trotter
    self.context = FakeContext()
233 72737a7f Iustin Pop
    # WARNING: here we pass None as RpcRunner instance since we know
234 72737a7f Iustin Pop
    # our usage via HooksMaster will not use lu.rpc
235 86d9d3bb Iustin Pop
    self.lu = FakeLU(FakeProc(), self.op, self.context, None)
236 d2525573 Guido Trotter
237 a8083063 Iustin Pop
  def testTotalFalse(self):
238 a8083063 Iustin Pop
    """Test complete rpc failure"""
239 d2525573 Guido Trotter
    hm = mcpu.HooksMaster(self._call_false, FakeProc(), self.lu)
240 a8083063 Iustin Pop
    self.failUnlessRaises(errors.HooksFailure,
241 a8083063 Iustin Pop
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
242 a8083063 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_POST)
243 a8083063 Iustin Pop
244 a8083063 Iustin Pop
  def testIndividualFalse(self):
245 2395c322 Iustin Pop
    """Test individual node failure"""
246 d2525573 Guido Trotter
    hm = mcpu.HooksMaster(self._call_nodes_false, FakeProc(), self.lu)
247 2395c322 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
248 2395c322 Iustin Pop
    #self.failUnlessRaises(errors.HooksFailure,
249 2395c322 Iustin Pop
    #                      hm.RunPhase, constants.HOOKS_PHASE_PRE)
250 a8083063 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_POST)
251 a8083063 Iustin Pop
252 a8083063 Iustin Pop
  def testScriptFalse(self):
253 a8083063 Iustin Pop
    """Test individual rpc failure"""
254 d2525573 Guido Trotter
    hm = mcpu.HooksMaster(self._call_script_fail, FakeProc(), self.lu)
255 a8083063 Iustin Pop
    self.failUnlessRaises(errors.HooksAbort,
256 a8083063 Iustin Pop
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
257 a8083063 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_POST)
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
  def testScriptSucceed(self):
260 a8083063 Iustin Pop
    """Test individual rpc failure"""
261 d2525573 Guido Trotter
    hm = mcpu.HooksMaster(self._call_script_succeed, FakeProc(), self.lu)
262 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
263 a8083063 Iustin Pop
      hm.RunPhase(phase)
264 a8083063 Iustin Pop
265 a8083063 Iustin Pop
if __name__ == '__main__':
266 a8083063 Iustin Pop
  unittest.main()