Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.hooks_unittest.py @ 26d3fd2f

History | View | Annotate | Download (9.4 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 25231ec5 Michael Hanselmann
import testutils
43 25231ec5 Michael Hanselmann
44 25231ec5 Michael Hanselmann
45 a8083063 Iustin Pop
class FakeLU(cmdlib.LogicalUnit):
46 a8083063 Iustin Pop
  HPATH = "test"
47 a8083063 Iustin Pop
  def BuildHooksEnv(self):
48 a8083063 Iustin Pop
    return {}, ["localhost"], ["localhost"]
49 a8083063 Iustin Pop
50 25231ec5 Michael Hanselmann
51 a8083063 Iustin Pop
class TestHooksRunner(unittest.TestCase):
52 a8083063 Iustin Pop
  """Testing case for HooksRunner"""
53 a8083063 Iustin Pop
  def setUp(self):
54 a8083063 Iustin Pop
    self.torm = []
55 a8083063 Iustin Pop
    self.tmpdir = tempfile.mkdtemp()
56 a8083063 Iustin Pop
    self.torm.append((self.tmpdir, True))
57 a8083063 Iustin Pop
    self.logdir = tempfile.mkdtemp()
58 a8083063 Iustin Pop
    self.torm.append((self.logdir, True))
59 a8083063 Iustin Pop
    self.hpath = "fake"
60 a8083063 Iustin Pop
    self.ph_dirs = {}
61 a8083063 Iustin Pop
    for i in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
62 a8083063 Iustin Pop
      dname = "%s/%s-%s.d" % (self.tmpdir, self.hpath, i)
63 a8083063 Iustin Pop
      os.mkdir(dname)
64 a8083063 Iustin Pop
      self.torm.append((dname, True))
65 a8083063 Iustin Pop
      self.ph_dirs[i] = dname
66 a8083063 Iustin Pop
    self.hr = backend.HooksRunner(hooks_base_dir=self.tmpdir)
67 a8083063 Iustin Pop
68 a8083063 Iustin Pop
  def tearDown(self):
69 a8083063 Iustin Pop
    self.torm.reverse()
70 a8083063 Iustin Pop
    for path, kind in self.torm:
71 a8083063 Iustin Pop
      if kind:
72 a8083063 Iustin Pop
        os.rmdir(path)
73 a8083063 Iustin Pop
      else:
74 a8083063 Iustin Pop
        os.unlink(path)
75 a8083063 Iustin Pop
76 a8083063 Iustin Pop
  def _rname(self, fname):
77 a8083063 Iustin Pop
    return "/".join(fname.split("/")[-2:])
78 a8083063 Iustin Pop
79 a8083063 Iustin Pop
  def testEmpty(self):
80 a8083063 Iustin Pop
    """Test no hooks"""
81 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
82 d019f8bd Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), [])
83 a8083063 Iustin Pop
84 a8083063 Iustin Pop
  def testSkipNonExec(self):
85 a8083063 Iustin Pop
    """Test skip non-exec file"""
86 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
87 a8083063 Iustin Pop
      fname = "%s/test" % self.ph_dirs[phase]
88 a8083063 Iustin Pop
      f = open(fname, "w")
89 a8083063 Iustin Pop
      f.close()
90 a8083063 Iustin Pop
      self.torm.append((fname, False))
91 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
92 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
93 a8083063 Iustin Pop
94 a8083063 Iustin Pop
  def testSkipInvalidName(self):
95 a8083063 Iustin Pop
    """Test skip script with invalid name"""
96 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
97 a8083063 Iustin Pop
      fname = "%s/a.off" % self.ph_dirs[phase]
98 a8083063 Iustin Pop
      f = open(fname, "w")
99 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 0\n")
100 a8083063 Iustin Pop
      f.close()
101 a8083063 Iustin Pop
      os.chmod(fname, 0700)
102 a8083063 Iustin Pop
      self.torm.append((fname, False))
103 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
104 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
105 a8083063 Iustin Pop
106 a8083063 Iustin Pop
  def testSkipDir(self):
107 a8083063 Iustin Pop
    """Test skip directory"""
108 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
109 a8083063 Iustin Pop
      fname = "%s/testdir" % self.ph_dirs[phase]
110 a8083063 Iustin Pop
      os.mkdir(fname)
111 a8083063 Iustin Pop
      self.torm.append((fname, True))
112 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
113 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SKIP, "")])
114 a8083063 Iustin Pop
115 a8083063 Iustin Pop
  def testSuccess(self):
116 a8083063 Iustin Pop
    """Test success execution"""
117 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
118 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
119 a8083063 Iustin Pop
      f = open(fname, "w")
120 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 0\n")
121 a8083063 Iustin Pop
      f.close()
122 a8083063 Iustin Pop
      self.torm.append((fname, False))
123 a8083063 Iustin Pop
      os.chmod(fname, 0700)
124 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
125 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, "")])
126 a8083063 Iustin Pop
127 a8083063 Iustin Pop
  def testSymlink(self):
128 a8083063 Iustin Pop
    """Test running a symlink"""
129 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
130 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
131 a8083063 Iustin Pop
      os.symlink("/bin/true", fname)
132 a8083063 Iustin Pop
      self.torm.append((fname, False))
133 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
134 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, "")])
135 a8083063 Iustin Pop
136 a8083063 Iustin Pop
  def testFail(self):
137 a8083063 Iustin Pop
    """Test success execution"""
138 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
139 a8083063 Iustin Pop
      fname = "%s/success" % self.ph_dirs[phase]
140 a8083063 Iustin Pop
      f = open(fname, "w")
141 a8083063 Iustin Pop
      f.write("#!/bin/sh\nexit 1\n")
142 a8083063 Iustin Pop
      f.close()
143 a8083063 Iustin Pop
      self.torm.append((fname, False))
144 a8083063 Iustin Pop
      os.chmod(fname, 0700)
145 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
146 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_FAIL, "")])
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
  def testCombined(self):
149 a8083063 Iustin Pop
    """Test success, failure and skip all in one test"""
150 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
151 a8083063 Iustin Pop
      expect = []
152 a8083063 Iustin Pop
      for fbase, ecode, rs in [("00succ", 0, HKR_SUCCESS),
153 a8083063 Iustin Pop
                               ("10fail", 1, HKR_FAIL),
154 a8083063 Iustin Pop
                               ("20inv.", 0, HKR_SKIP),
155 a8083063 Iustin Pop
                               ]:
156 a8083063 Iustin Pop
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
157 a8083063 Iustin Pop
        f = open(fname, "w")
158 a8083063 Iustin Pop
        f.write("#!/bin/sh\nexit %d\n" % ecode)
159 a8083063 Iustin Pop
        f.close()
160 a8083063 Iustin Pop
        self.torm.append((fname, False))
161 a8083063 Iustin Pop
        os.chmod(fname, 0700)
162 a8083063 Iustin Pop
        expect.append((self._rname(fname), rs, ""))
163 d019f8bd Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
164 a8083063 Iustin Pop
165 a8083063 Iustin Pop
  def testOrdering(self):
166 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
167 a8083063 Iustin Pop
      expect = []
168 a8083063 Iustin Pop
      for fbase in ["10s1",
169 a8083063 Iustin Pop
                    "00s0",
170 a8083063 Iustin Pop
                    "10sa",
171 a8083063 Iustin Pop
                    "80sc",
172 a8083063 Iustin Pop
                    "60sd",
173 a8083063 Iustin Pop
                    ]:
174 a8083063 Iustin Pop
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
175 a8083063 Iustin Pop
        os.symlink("/bin/true", fname)
176 a8083063 Iustin Pop
        self.torm.append((fname, False))
177 a8083063 Iustin Pop
        expect.append((self._rname(fname), HKR_SUCCESS, ""))
178 a8083063 Iustin Pop
      expect.sort()
179 d019f8bd Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
  def testEnv(self):
182 a8083063 Iustin Pop
    """Test environment execution"""
183 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
184 a8083063 Iustin Pop
      fbase = "success"
185 a8083063 Iustin Pop
      fname = "%s/%s" % (self.ph_dirs[phase], fbase)
186 a8083063 Iustin Pop
      os.symlink("/usr/bin/env", fname)
187 a8083063 Iustin Pop
      self.torm.append((fname, False))
188 a8083063 Iustin Pop
      env_snt = {"PHASE": phase}
189 7b80424f Iustin Pop
      env_exp = "PHASE=%s" % phase
190 a8083063 Iustin Pop
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, env_snt),
191 d019f8bd Iustin Pop
                           [(self._rname(fname), HKR_SUCCESS, env_exp)])
192 a8083063 Iustin Pop
193 a8083063 Iustin Pop
194 a8083063 Iustin Pop
class TestHooksMaster(unittest.TestCase):
195 a8083063 Iustin Pop
  """Testing case for HooksMaster"""
196 a8083063 Iustin Pop
197 a8083063 Iustin Pop
  def _call_false(*args):
198 a8083063 Iustin Pop
    """Fake call_hooks_runner function which returns False."""
199 a8083063 Iustin Pop
    return False
200 a8083063 Iustin Pop
201 a8083063 Iustin Pop
  @staticmethod
202 a8083063 Iustin Pop
  def _call_nodes_false(node_list, hpath, phase, env):
203 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
204 a8083063 Iustin Pop

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

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

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

219 a8083063 Iustin Pop
    """
220 3fb4f740 Iustin Pop
    rr = rpc.RpcResult
221 3fb4f740 Iustin Pop
    return dict([(node, rr((True, [("utest", constants.HKR_FAIL, "err")]),
222 3fb4f740 Iustin Pop
                           node=node, call='FakeScriptFail'))
223 3fb4f740 Iustin Pop
                  for node in node_list])
224 a8083063 Iustin Pop
225 a8083063 Iustin Pop
  @staticmethod
226 a8083063 Iustin Pop
  def _call_script_succeed(node_list, hpath, phase, env):
227 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
228 a8083063 Iustin Pop

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

232 a8083063 Iustin Pop
    """
233 3fb4f740 Iustin Pop
    rr = rpc.RpcResult
234 3fb4f740 Iustin Pop
    return dict([(node, rr(True, [("utest", constants.HKR_SUCCESS, "ok")],
235 3fb4f740 Iustin Pop
                           node=node, call='FakeScriptOk'))
236 3fb4f740 Iustin Pop
                 for node in node_list])
237 a8083063 Iustin Pop
238 d2525573 Guido Trotter
  def setUp(self):
239 d2525573 Guido Trotter
    self.op = opcodes.OpCode()
240 77b657a3 Guido Trotter
    self.context = FakeContext()
241 72737a7f Iustin Pop
    # WARNING: here we pass None as RpcRunner instance since we know
242 72737a7f Iustin Pop
    # our usage via HooksMaster will not use lu.rpc
243 86d9d3bb Iustin Pop
    self.lu = FakeLU(FakeProc(), self.op, self.context, None)
244 d2525573 Guido Trotter
245 a8083063 Iustin Pop
  def testTotalFalse(self):
246 a8083063 Iustin Pop
    """Test complete rpc failure"""
247 4b5e8271 Iustin Pop
    hm = mcpu.HooksMaster(self._call_false, self.lu)
248 a8083063 Iustin Pop
    self.failUnlessRaises(errors.HooksFailure,
249 a8083063 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 testIndividualFalse(self):
253 2395c322 Iustin Pop
    """Test individual node failure"""
254 4b5e8271 Iustin Pop
    hm = mcpu.HooksMaster(self._call_nodes_false, self.lu)
255 2395c322 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
256 2395c322 Iustin Pop
    #self.failUnlessRaises(errors.HooksFailure,
257 2395c322 Iustin Pop
    #                      hm.RunPhase, constants.HOOKS_PHASE_PRE)
258 a8083063 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_POST)
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
  def testScriptFalse(self):
261 a8083063 Iustin Pop
    """Test individual rpc failure"""
262 4b5e8271 Iustin Pop
    hm = mcpu.HooksMaster(self._call_script_fail, self.lu)
263 a8083063 Iustin Pop
    self.failUnlessRaises(errors.HooksAbort,
264 a8083063 Iustin Pop
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
265 a8083063 Iustin Pop
    hm.RunPhase(constants.HOOKS_PHASE_POST)
266 a8083063 Iustin Pop
267 a8083063 Iustin Pop
  def testScriptSucceed(self):
268 a8083063 Iustin Pop
    """Test individual rpc failure"""
269 4b5e8271 Iustin Pop
    hm = mcpu.HooksMaster(self._call_script_succeed, self.lu)
270 a8083063 Iustin Pop
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
271 a8083063 Iustin Pop
      hm.RunPhase(phase)
272 a8083063 Iustin Pop
273 25231ec5 Michael Hanselmann
274 a8083063 Iustin Pop
if __name__ == '__main__':
275 25231ec5 Michael Hanselmann
  testutils.GanetiTestProgram()