Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.hooks_unittest.py @ 72737a7f

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

200 a8083063 Iustin Pop
    Returns:
201 a8083063 Iustin Pop
      - list of False values with the same len as the node_list argument
202 a8083063 Iustin Pop

203 a8083063 Iustin Pop
    """
204 a8083063 Iustin Pop
    return [False for node_name in node_list]
205 a8083063 Iustin Pop
206 a8083063 Iustin Pop
  @staticmethod
207 a8083063 Iustin Pop
  def _call_script_fail(node_list, hpath, phase, env):
208 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
209 a8083063 Iustin Pop

210 a8083063 Iustin Pop
    Returns:
211 a8083063 Iustin Pop
      - list of False values with the same len as the node_list argument
212 a8083063 Iustin Pop

213 a8083063 Iustin Pop
    """
214 a8083063 Iustin Pop
    return dict([(node_name, [("unittest", constants.HKR_FAIL, "error")])
215 a8083063 Iustin Pop
                 for node_name in node_list])
216 a8083063 Iustin Pop
217 a8083063 Iustin Pop
  @staticmethod
218 a8083063 Iustin Pop
  def _call_script_succeed(node_list, hpath, phase, env):
219 a8083063 Iustin Pop
    """Fake call_hooks_runner function.
220 a8083063 Iustin Pop

221 a8083063 Iustin Pop
    Returns:
222 a8083063 Iustin Pop
      - list of False values with the same len as the node_list argument
223 a8083063 Iustin Pop

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