Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.backend_unittest.py @ 99e222b1

History | View | Annotate | Download (18.1 kB)

1 f942a838 Michael Hanselmann
#!/usr/bin/python
2 f942a838 Michael Hanselmann
#
3 f942a838 Michael Hanselmann
4 f942a838 Michael Hanselmann
# Copyright (C) 2010 Google Inc.
5 f942a838 Michael Hanselmann
#
6 f942a838 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 f942a838 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 f942a838 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 f942a838 Michael Hanselmann
# (at your option) any later version.
10 f942a838 Michael Hanselmann
#
11 f942a838 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 f942a838 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 f942a838 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 f942a838 Michael Hanselmann
# General Public License for more details.
15 f942a838 Michael Hanselmann
#
16 f942a838 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 f942a838 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 f942a838 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 f942a838 Michael Hanselmann
# 02110-1301, USA.
20 f942a838 Michael Hanselmann
21 f942a838 Michael Hanselmann
22 f942a838 Michael Hanselmann
"""Script for testing ganeti.backend"""
23 f942a838 Michael Hanselmann
24 f942a838 Michael Hanselmann
import os
25 f942a838 Michael Hanselmann
import sys
26 f942a838 Michael Hanselmann
import shutil
27 f942a838 Michael Hanselmann
import tempfile
28 f942a838 Michael Hanselmann
import unittest
29 f942a838 Michael Hanselmann
30 f942a838 Michael Hanselmann
from ganeti import utils
31 31ff0247 Michael Hanselmann
from ganeti import constants
32 f942a838 Michael Hanselmann
from ganeti import backend
33 a744b676 Manuel Franceschini
from ganeti import netutils
34 1a2eb2dc Michael Hanselmann
from ganeti import errors
35 f942a838 Michael Hanselmann
36 f942a838 Michael Hanselmann
import testutils
37 1a2eb2dc Michael Hanselmann
import mocks
38 f942a838 Michael Hanselmann
39 f942a838 Michael Hanselmann
40 f942a838 Michael Hanselmann
class TestX509Certificates(unittest.TestCase):
41 f942a838 Michael Hanselmann
  def setUp(self):
42 f942a838 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
43 f942a838 Michael Hanselmann
44 f942a838 Michael Hanselmann
  def tearDown(self):
45 f942a838 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
46 f942a838 Michael Hanselmann
47 f942a838 Michael Hanselmann
  def test(self):
48 f942a838 Michael Hanselmann
    (name, cert_pem) = backend.CreateX509Certificate(300, cryptodir=self.tmpdir)
49 f942a838 Michael Hanselmann
50 f942a838 Michael Hanselmann
    self.assertEqual(utils.ReadFile(os.path.join(self.tmpdir, name,
51 f942a838 Michael Hanselmann
                                                 backend._X509_CERT_FILE)),
52 f942a838 Michael Hanselmann
                     cert_pem)
53 f942a838 Michael Hanselmann
    self.assert_(0 < os.path.getsize(os.path.join(self.tmpdir, name,
54 f942a838 Michael Hanselmann
                                                  backend._X509_KEY_FILE)))
55 f942a838 Michael Hanselmann
56 f942a838 Michael Hanselmann
    (name2, cert_pem2) = \
57 f942a838 Michael Hanselmann
      backend.CreateX509Certificate(300, cryptodir=self.tmpdir)
58 f942a838 Michael Hanselmann
59 f942a838 Michael Hanselmann
    backend.RemoveX509Certificate(name, cryptodir=self.tmpdir)
60 f942a838 Michael Hanselmann
    backend.RemoveX509Certificate(name2, cryptodir=self.tmpdir)
61 f942a838 Michael Hanselmann
62 f942a838 Michael Hanselmann
    self.assertEqual(utils.ListVisibleFiles(self.tmpdir), [])
63 f942a838 Michael Hanselmann
64 f942a838 Michael Hanselmann
  def testNonEmpty(self):
65 f942a838 Michael Hanselmann
    (name, _) = backend.CreateX509Certificate(300, cryptodir=self.tmpdir)
66 f942a838 Michael Hanselmann
67 f942a838 Michael Hanselmann
    utils.WriteFile(utils.PathJoin(self.tmpdir, name, "hello-world"),
68 f942a838 Michael Hanselmann
                    data="Hello World")
69 f942a838 Michael Hanselmann
70 f942a838 Michael Hanselmann
    self.assertRaises(backend.RPCFail, backend.RemoveX509Certificate,
71 f942a838 Michael Hanselmann
                      name, cryptodir=self.tmpdir)
72 f942a838 Michael Hanselmann
73 f942a838 Michael Hanselmann
    self.assertEqual(utils.ListVisibleFiles(self.tmpdir), [name])
74 f942a838 Michael Hanselmann
75 f942a838 Michael Hanselmann
76 a3a5f850 Iustin Pop
class TestNodeVerify(testutils.GanetiTestCase):
77 a3a5f850 Iustin Pop
  def testMasterIPLocalhost(self):
78 a3a5f850 Iustin Pop
    # this a real functional test, but requires localhost to be reachable
79 b705c7a6 Manuel Franceschini
    local_data = (netutils.Hostname.GetSysName(),
80 b705c7a6 Manuel Franceschini
                  constants.IP4_ADDRESS_LOCALHOST)
81 a3a5f850 Iustin Pop
    result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None)
82 a3a5f850 Iustin Pop
    self.failUnless(constants.NV_MASTERIP in result,
83 a3a5f850 Iustin Pop
                    "Master IP data not returned")
84 a3a5f850 Iustin Pop
    self.failUnless(result[constants.NV_MASTERIP], "Cannot reach localhost")
85 a3a5f850 Iustin Pop
86 a3a5f850 Iustin Pop
  def testMasterIPUnreachable(self):
87 a3a5f850 Iustin Pop
    # Network 192.0.2.0/24 is reserved for test/documentation as per
88 926feaf1 Manuel Franceschini
    # RFC 5737
89 a3a5f850 Iustin Pop
    bad_data =  ("master.example.com", "192.0.2.1")
90 a3a5f850 Iustin Pop
    # we just test that whatever TcpPing returns, VerifyNode returns too
91 a744b676 Manuel Franceschini
    netutils.TcpPing = lambda a, b, source=None: False
92 a3a5f850 Iustin Pop
    result = backend.VerifyNode({constants.NV_MASTERIP: bad_data}, None)
93 a3a5f850 Iustin Pop
    self.failUnless(constants.NV_MASTERIP in result,
94 a3a5f850 Iustin Pop
                    "Master IP data not returned")
95 a3a5f850 Iustin Pop
    self.failIf(result[constants.NV_MASTERIP],
96 a744b676 Manuel Franceschini
                "Result from netutils.TcpPing corrupted")
97 a3a5f850 Iustin Pop
98 a3a5f850 Iustin Pop
99 405bffe2 Michael Hanselmann
def _DefRestrictedCmdOwner():
100 1a2eb2dc Michael Hanselmann
  return (os.getuid(), os.getgid())
101 1a2eb2dc Michael Hanselmann
102 1a2eb2dc Michael Hanselmann
103 405bffe2 Michael Hanselmann
class TestVerifyRestrictedCmdName(unittest.TestCase):
104 1a2eb2dc Michael Hanselmann
  def testAcceptableName(self):
105 1a2eb2dc Michael Hanselmann
    for i in ["foo", "bar", "z1", "000first", "hello-world"]:
106 1a2eb2dc Michael Hanselmann
      for fn in [lambda s: s, lambda s: s.upper(), lambda s: s.title()]:
107 405bffe2 Michael Hanselmann
        (status, msg) = backend._VerifyRestrictedCmdName(fn(i))
108 1a2eb2dc Michael Hanselmann
        self.assertTrue(status)
109 1a2eb2dc Michael Hanselmann
        self.assertTrue(msg is None)
110 1a2eb2dc Michael Hanselmann
111 1a2eb2dc Michael Hanselmann
  def testEmptyAndSpace(self):
112 1a2eb2dc Michael Hanselmann
    for i in ["", " ", "\t", "\n"]:
113 405bffe2 Michael Hanselmann
      (status, msg) = backend._VerifyRestrictedCmdName(i)
114 1a2eb2dc Michael Hanselmann
      self.assertFalse(status)
115 1a2eb2dc Michael Hanselmann
      self.assertEqual(msg, "Missing command name")
116 1a2eb2dc Michael Hanselmann
117 1a2eb2dc Michael Hanselmann
  def testNameWithSlashes(self):
118 1a2eb2dc Michael Hanselmann
    for i in ["/", "./foo", "../moo", "some/name"]:
119 405bffe2 Michael Hanselmann
      (status, msg) = backend._VerifyRestrictedCmdName(i)
120 1a2eb2dc Michael Hanselmann
      self.assertFalse(status)
121 1a2eb2dc Michael Hanselmann
      self.assertEqual(msg, "Invalid command name")
122 1a2eb2dc Michael Hanselmann
123 1a2eb2dc Michael Hanselmann
  def testForbiddenCharacters(self):
124 1a2eb2dc Michael Hanselmann
    for i in ["#", ".", "..", "bash -c ls", "'"]:
125 405bffe2 Michael Hanselmann
      (status, msg) = backend._VerifyRestrictedCmdName(i)
126 1a2eb2dc Michael Hanselmann
      self.assertFalse(status)
127 1a2eb2dc Michael Hanselmann
      self.assertEqual(msg, "Command name contains forbidden characters")
128 1a2eb2dc Michael Hanselmann
129 1a2eb2dc Michael Hanselmann
130 405bffe2 Michael Hanselmann
class TestVerifyRestrictedCmdDirectory(unittest.TestCase):
131 1a2eb2dc Michael Hanselmann
  def setUp(self):
132 1a2eb2dc Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
133 1a2eb2dc Michael Hanselmann
134 1a2eb2dc Michael Hanselmann
  def tearDown(self):
135 1a2eb2dc Michael Hanselmann
    shutil.rmtree(self.tmpdir)
136 1a2eb2dc Michael Hanselmann
137 1a2eb2dc Michael Hanselmann
  def testCanNotStat(self):
138 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "foobar")
139 1a2eb2dc Michael Hanselmann
    self.assertFalse(os.path.exists(tmpname))
140 1a2eb2dc Michael Hanselmann
    (status, msg) = \
141 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmdDirectory(tmpname, _owner=NotImplemented)
142 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
143 1a2eb2dc Michael Hanselmann
    self.assertTrue(msg.startswith("Can't stat(2) '"))
144 1a2eb2dc Michael Hanselmann
145 1a2eb2dc Michael Hanselmann
  def testTooPermissive(self):
146 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "foobar")
147 1a2eb2dc Michael Hanselmann
    os.mkdir(tmpname)
148 1a2eb2dc Michael Hanselmann
149 1a2eb2dc Michael Hanselmann
    for mode in [0777, 0706, 0760, 0722]:
150 1a2eb2dc Michael Hanselmann
      os.chmod(tmpname, mode)
151 1a2eb2dc Michael Hanselmann
      self.assertTrue(os.path.isdir(tmpname))
152 1a2eb2dc Michael Hanselmann
      (status, msg) = \
153 405bffe2 Michael Hanselmann
        backend._VerifyRestrictedCmdDirectory(tmpname, _owner=NotImplemented)
154 1a2eb2dc Michael Hanselmann
      self.assertFalse(status)
155 1a2eb2dc Michael Hanselmann
      self.assertTrue(msg.startswith("Permissions on '"))
156 1a2eb2dc Michael Hanselmann
157 1a2eb2dc Michael Hanselmann
  def testNoDirectory(self):
158 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "foobar")
159 1a2eb2dc Michael Hanselmann
    utils.WriteFile(tmpname, data="empty\n")
160 1a2eb2dc Michael Hanselmann
    self.assertTrue(os.path.isfile(tmpname))
161 1a2eb2dc Michael Hanselmann
    (status, msg) = \
162 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmdDirectory(tmpname,
163 405bffe2 Michael Hanselmann
                                            _owner=_DefRestrictedCmdOwner())
164 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
165 1a2eb2dc Michael Hanselmann
    self.assertTrue(msg.endswith("is not a directory"))
166 1a2eb2dc Michael Hanselmann
167 1a2eb2dc Michael Hanselmann
  def testNormal(self):
168 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "foobar")
169 1a2eb2dc Michael Hanselmann
    os.mkdir(tmpname)
170 1a2eb2dc Michael Hanselmann
    self.assertTrue(os.path.isdir(tmpname))
171 1a2eb2dc Michael Hanselmann
    (status, msg) = \
172 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmdDirectory(tmpname,
173 405bffe2 Michael Hanselmann
                                            _owner=_DefRestrictedCmdOwner())
174 1a2eb2dc Michael Hanselmann
    self.assertTrue(status)
175 1a2eb2dc Michael Hanselmann
    self.assertTrue(msg is None)
176 1a2eb2dc Michael Hanselmann
177 1a2eb2dc Michael Hanselmann
178 405bffe2 Michael Hanselmann
class TestVerifyRestrictedCmd(unittest.TestCase):
179 1a2eb2dc Michael Hanselmann
  def setUp(self):
180 1a2eb2dc Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
181 1a2eb2dc Michael Hanselmann
182 1a2eb2dc Michael Hanselmann
  def tearDown(self):
183 1a2eb2dc Michael Hanselmann
    shutil.rmtree(self.tmpdir)
184 1a2eb2dc Michael Hanselmann
185 1a2eb2dc Michael Hanselmann
  def testCanNotStat(self):
186 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "helloworld")
187 1a2eb2dc Michael Hanselmann
    self.assertFalse(os.path.exists(tmpname))
188 1a2eb2dc Michael Hanselmann
    (status, msg) = \
189 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmd(self.tmpdir, "helloworld",
190 1a2eb2dc Michael Hanselmann
                                   _owner=NotImplemented)
191 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
192 1a2eb2dc Michael Hanselmann
    self.assertTrue(msg.startswith("Can't stat(2) '"))
193 1a2eb2dc Michael Hanselmann
194 1a2eb2dc Michael Hanselmann
  def testNotExecutable(self):
195 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "cmdname")
196 1a2eb2dc Michael Hanselmann
    utils.WriteFile(tmpname, data="empty\n")
197 1a2eb2dc Michael Hanselmann
    (status, msg) = \
198 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmd(self.tmpdir, "cmdname",
199 405bffe2 Michael Hanselmann
                                   _owner=_DefRestrictedCmdOwner())
200 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
201 1a2eb2dc Michael Hanselmann
    self.assertTrue(msg.startswith("access(2) thinks '"))
202 1a2eb2dc Michael Hanselmann
203 1a2eb2dc Michael Hanselmann
  def testExecutable(self):
204 1a2eb2dc Michael Hanselmann
    tmpname = utils.PathJoin(self.tmpdir, "cmdname")
205 1a2eb2dc Michael Hanselmann
    utils.WriteFile(tmpname, data="empty\n", mode=0700)
206 1a2eb2dc Michael Hanselmann
    (status, executable) = \
207 405bffe2 Michael Hanselmann
      backend._VerifyRestrictedCmd(self.tmpdir, "cmdname",
208 405bffe2 Michael Hanselmann
                                   _owner=_DefRestrictedCmdOwner())
209 1a2eb2dc Michael Hanselmann
    self.assertTrue(status)
210 1a2eb2dc Michael Hanselmann
    self.assertEqual(executable, tmpname)
211 1a2eb2dc Michael Hanselmann
212 1a2eb2dc Michael Hanselmann
213 405bffe2 Michael Hanselmann
class TestPrepareRestrictedCmd(unittest.TestCase):
214 1a2eb2dc Michael Hanselmann
  _TEST_PATH = "/tmp/some/test/path"
215 1a2eb2dc Michael Hanselmann
216 1a2eb2dc Michael Hanselmann
  def testDirFails(self):
217 1a2eb2dc Michael Hanselmann
    def fn(path):
218 1a2eb2dc Michael Hanselmann
      self.assertEqual(path, self._TEST_PATH)
219 1a2eb2dc Michael Hanselmann
      return (False, "test error 31420")
220 1a2eb2dc Michael Hanselmann
221 1a2eb2dc Michael Hanselmann
    (status, msg) = \
222 405bffe2 Michael Hanselmann
      backend._PrepareRestrictedCmd(self._TEST_PATH, "cmd21152",
223 1a2eb2dc Michael Hanselmann
                                    _verify_dir=fn,
224 1a2eb2dc Michael Hanselmann
                                    _verify_name=NotImplemented,
225 1a2eb2dc Michael Hanselmann
                                    _verify_cmd=NotImplemented)
226 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
227 1a2eb2dc Michael Hanselmann
    self.assertEqual(msg, "test error 31420")
228 1a2eb2dc Michael Hanselmann
229 1a2eb2dc Michael Hanselmann
  def testNameFails(self):
230 1a2eb2dc Michael Hanselmann
    def fn(cmd):
231 1a2eb2dc Michael Hanselmann
      self.assertEqual(cmd, "cmd4617")
232 1a2eb2dc Michael Hanselmann
      return (False, "test error 591")
233 1a2eb2dc Michael Hanselmann
234 1a2eb2dc Michael Hanselmann
    (status, msg) = \
235 405bffe2 Michael Hanselmann
      backend._PrepareRestrictedCmd(self._TEST_PATH, "cmd4617",
236 1a2eb2dc Michael Hanselmann
                                    _verify_dir=lambda _: (True, None),
237 1a2eb2dc Michael Hanselmann
                                    _verify_name=fn,
238 1a2eb2dc Michael Hanselmann
                                    _verify_cmd=NotImplemented)
239 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
240 1a2eb2dc Michael Hanselmann
    self.assertEqual(msg, "test error 591")
241 1a2eb2dc Michael Hanselmann
242 1a2eb2dc Michael Hanselmann
  def testCommandFails(self):
243 1a2eb2dc Michael Hanselmann
    def fn(path, cmd):
244 1a2eb2dc Michael Hanselmann
      self.assertEqual(path, self._TEST_PATH)
245 1a2eb2dc Michael Hanselmann
      self.assertEqual(cmd, "cmd17577")
246 1a2eb2dc Michael Hanselmann
      return (False, "test error 25524")
247 1a2eb2dc Michael Hanselmann
248 1a2eb2dc Michael Hanselmann
    (status, msg) = \
249 405bffe2 Michael Hanselmann
      backend._PrepareRestrictedCmd(self._TEST_PATH, "cmd17577",
250 1a2eb2dc Michael Hanselmann
                                    _verify_dir=lambda _: (True, None),
251 1a2eb2dc Michael Hanselmann
                                    _verify_name=lambda _: (True, None),
252 1a2eb2dc Michael Hanselmann
                                    _verify_cmd=fn)
253 1a2eb2dc Michael Hanselmann
    self.assertFalse(status)
254 1a2eb2dc Michael Hanselmann
    self.assertEqual(msg, "test error 25524")
255 1a2eb2dc Michael Hanselmann
256 1a2eb2dc Michael Hanselmann
  def testSuccess(self):
257 1a2eb2dc Michael Hanselmann
    def fn(path, cmd):
258 1a2eb2dc Michael Hanselmann
      return (True, utils.PathJoin(path, cmd))
259 1a2eb2dc Michael Hanselmann
260 1a2eb2dc Michael Hanselmann
    (status, executable) = \
261 405bffe2 Michael Hanselmann
      backend._PrepareRestrictedCmd(self._TEST_PATH, "cmd22633",
262 1a2eb2dc Michael Hanselmann
                                    _verify_dir=lambda _: (True, None),
263 1a2eb2dc Michael Hanselmann
                                    _verify_name=lambda _: (True, None),
264 1a2eb2dc Michael Hanselmann
                                    _verify_cmd=fn)
265 1a2eb2dc Michael Hanselmann
    self.assertTrue(status)
266 1a2eb2dc Michael Hanselmann
    self.assertEqual(executable, utils.PathJoin(self._TEST_PATH, "cmd22633"))
267 1a2eb2dc Michael Hanselmann
268 1a2eb2dc Michael Hanselmann
269 405bffe2 Michael Hanselmann
def _SleepForRestrictedCmd(duration):
270 1a2eb2dc Michael Hanselmann
  assert duration > 5
271 1a2eb2dc Michael Hanselmann
272 1a2eb2dc Michael Hanselmann
273 405bffe2 Michael Hanselmann
def _GenericRestrictedCmdError(cmd):
274 1a2eb2dc Michael Hanselmann
  return "Executing command '%s' failed" % cmd
275 1a2eb2dc Michael Hanselmann
276 1a2eb2dc Michael Hanselmann
277 42bd26e8 Michael Hanselmann
class TestRunRestrictedCmd(unittest.TestCase):
278 1a2eb2dc Michael Hanselmann
  def setUp(self):
279 1a2eb2dc Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
280 1a2eb2dc Michael Hanselmann
281 1a2eb2dc Michael Hanselmann
  def tearDown(self):
282 1a2eb2dc Michael Hanselmann
    shutil.rmtree(self.tmpdir)
283 1a2eb2dc Michael Hanselmann
284 1a2eb2dc Michael Hanselmann
  def testNonExistantLockDirectory(self):
285 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "does", "not", "exist")
286 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
287 1a2eb2dc Michael Hanselmann
    self.assertFalse(os.path.exists(lockfile))
288 1a2eb2dc Michael Hanselmann
    self.assertRaises(backend.RPCFail,
289 42bd26e8 Michael Hanselmann
                      backend.RunRestrictedCmd, "test",
290 1a2eb2dc Michael Hanselmann
                      _lock_timeout=NotImplemented,
291 1a2eb2dc Michael Hanselmann
                      _lock_file=lockfile,
292 1a2eb2dc Michael Hanselmann
                      _path=NotImplemented,
293 1a2eb2dc Michael Hanselmann
                      _sleep_fn=sleep_fn,
294 1a2eb2dc Michael Hanselmann
                      _prepare_fn=NotImplemented,
295 1a2eb2dc Michael Hanselmann
                      _runcmd_fn=NotImplemented,
296 1a2eb2dc Michael Hanselmann
                      _enabled=True)
297 1a2eb2dc Michael Hanselmann
    self.assertEqual(sleep_fn.Count(), 1)
298 1a2eb2dc Michael Hanselmann
299 1a2eb2dc Michael Hanselmann
  @staticmethod
300 1a2eb2dc Michael Hanselmann
  def _TryLock(lockfile):
301 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
302 1a2eb2dc Michael Hanselmann
303 1a2eb2dc Michael Hanselmann
    result = False
304 1a2eb2dc Michael Hanselmann
    try:
305 42bd26e8 Michael Hanselmann
      backend.RunRestrictedCmd("test22717",
306 1a2eb2dc Michael Hanselmann
                               _lock_timeout=0.1,
307 1a2eb2dc Michael Hanselmann
                               _lock_file=lockfile,
308 1a2eb2dc Michael Hanselmann
                               _path=NotImplemented,
309 1a2eb2dc Michael Hanselmann
                               _sleep_fn=sleep_fn,
310 1a2eb2dc Michael Hanselmann
                               _prepare_fn=NotImplemented,
311 1a2eb2dc Michael Hanselmann
                               _runcmd_fn=NotImplemented,
312 1a2eb2dc Michael Hanselmann
                               _enabled=True)
313 1a2eb2dc Michael Hanselmann
    except backend.RPCFail, err:
314 405bffe2 Michael Hanselmann
      assert str(err) == _GenericRestrictedCmdError("test22717"), \
315 1a2eb2dc Michael Hanselmann
             "Did not fail with generic error message"
316 1a2eb2dc Michael Hanselmann
      result = True
317 1a2eb2dc Michael Hanselmann
318 1a2eb2dc Michael Hanselmann
    assert sleep_fn.Count() == 1
319 1a2eb2dc Michael Hanselmann
320 1a2eb2dc Michael Hanselmann
    return result
321 1a2eb2dc Michael Hanselmann
322 1a2eb2dc Michael Hanselmann
  def testLockHeldByOtherProcess(self):
323 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "lock")
324 1a2eb2dc Michael Hanselmann
325 1a2eb2dc Michael Hanselmann
    lock = utils.FileLock.Open(lockfile)
326 1a2eb2dc Michael Hanselmann
    lock.Exclusive(blocking=True, timeout=1.0)
327 1a2eb2dc Michael Hanselmann
    try:
328 1a2eb2dc Michael Hanselmann
      self.assertTrue(utils.RunInSeparateProcess(self._TryLock, lockfile))
329 1a2eb2dc Michael Hanselmann
    finally:
330 1a2eb2dc Michael Hanselmann
      lock.Close()
331 1a2eb2dc Michael Hanselmann
332 1a2eb2dc Michael Hanselmann
  @staticmethod
333 1a2eb2dc Michael Hanselmann
  def _PrepareRaisingException(path, cmd):
334 1a2eb2dc Michael Hanselmann
    assert cmd == "test23122"
335 1a2eb2dc Michael Hanselmann
    raise Exception("test")
336 1a2eb2dc Michael Hanselmann
337 1a2eb2dc Michael Hanselmann
  def testPrepareRaisesException(self):
338 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "lock")
339 1a2eb2dc Michael Hanselmann
340 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
341 1a2eb2dc Michael Hanselmann
    prepare_fn = testutils.CallCounter(self._PrepareRaisingException)
342 1a2eb2dc Michael Hanselmann
343 1a2eb2dc Michael Hanselmann
    try:
344 42bd26e8 Michael Hanselmann
      backend.RunRestrictedCmd("test23122",
345 1a2eb2dc Michael Hanselmann
                               _lock_timeout=1.0, _lock_file=lockfile,
346 1a2eb2dc Michael Hanselmann
                               _path=NotImplemented, _runcmd_fn=NotImplemented,
347 1a2eb2dc Michael Hanselmann
                               _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
348 1a2eb2dc Michael Hanselmann
                               _enabled=True)
349 1a2eb2dc Michael Hanselmann
    except backend.RPCFail, err:
350 405bffe2 Michael Hanselmann
      self.assertEqual(str(err), _GenericRestrictedCmdError("test23122"))
351 1a2eb2dc Michael Hanselmann
    else:
352 1a2eb2dc Michael Hanselmann
      self.fail("Didn't fail")
353 1a2eb2dc Michael Hanselmann
354 1a2eb2dc Michael Hanselmann
    self.assertEqual(sleep_fn.Count(), 1)
355 1a2eb2dc Michael Hanselmann
    self.assertEqual(prepare_fn.Count(), 1)
356 1a2eb2dc Michael Hanselmann
357 1a2eb2dc Michael Hanselmann
  @staticmethod
358 1a2eb2dc Michael Hanselmann
  def _PrepareFails(path, cmd):
359 1a2eb2dc Michael Hanselmann
    assert cmd == "test29327"
360 1a2eb2dc Michael Hanselmann
    return ("some error message", None)
361 1a2eb2dc Michael Hanselmann
362 1a2eb2dc Michael Hanselmann
  def testPrepareFails(self):
363 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "lock")
364 1a2eb2dc Michael Hanselmann
365 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
366 1a2eb2dc Michael Hanselmann
    prepare_fn = testutils.CallCounter(self._PrepareFails)
367 1a2eb2dc Michael Hanselmann
368 1a2eb2dc Michael Hanselmann
    try:
369 42bd26e8 Michael Hanselmann
      backend.RunRestrictedCmd("test29327",
370 1a2eb2dc Michael Hanselmann
                               _lock_timeout=1.0, _lock_file=lockfile,
371 1a2eb2dc Michael Hanselmann
                               _path=NotImplemented, _runcmd_fn=NotImplemented,
372 1a2eb2dc Michael Hanselmann
                               _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
373 1a2eb2dc Michael Hanselmann
                               _enabled=True)
374 1a2eb2dc Michael Hanselmann
    except backend.RPCFail, err:
375 405bffe2 Michael Hanselmann
      self.assertEqual(str(err), _GenericRestrictedCmdError("test29327"))
376 1a2eb2dc Michael Hanselmann
    else:
377 1a2eb2dc Michael Hanselmann
      self.fail("Didn't fail")
378 1a2eb2dc Michael Hanselmann
379 1a2eb2dc Michael Hanselmann
    self.assertEqual(sleep_fn.Count(), 1)
380 1a2eb2dc Michael Hanselmann
    self.assertEqual(prepare_fn.Count(), 1)
381 1a2eb2dc Michael Hanselmann
382 1a2eb2dc Michael Hanselmann
  @staticmethod
383 1a2eb2dc Michael Hanselmann
  def _SuccessfulPrepare(path, cmd):
384 1a2eb2dc Michael Hanselmann
    return (True, utils.PathJoin(path, cmd))
385 1a2eb2dc Michael Hanselmann
386 1a2eb2dc Michael Hanselmann
  def testRunCmdFails(self):
387 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "lock")
388 1a2eb2dc Michael Hanselmann
389 1a2eb2dc Michael Hanselmann
    def fn(args, env=NotImplemented, reset_env=NotImplemented,
390 1a2eb2dc Michael Hanselmann
           postfork_fn=NotImplemented):
391 1a2eb2dc Michael Hanselmann
      self.assertEqual(args, [utils.PathJoin(self.tmpdir, "test3079")])
392 1a2eb2dc Michael Hanselmann
      self.assertEqual(env, {})
393 1a2eb2dc Michael Hanselmann
      self.assertTrue(reset_env)
394 1a2eb2dc Michael Hanselmann
      self.assertTrue(callable(postfork_fn))
395 1a2eb2dc Michael Hanselmann
396 1a2eb2dc Michael Hanselmann
      trylock = utils.FileLock.Open(lockfile)
397 1a2eb2dc Michael Hanselmann
      try:
398 1a2eb2dc Michael Hanselmann
        # See if lockfile is still held
399 1a2eb2dc Michael Hanselmann
        self.assertRaises(EnvironmentError, trylock.Exclusive, blocking=False)
400 1a2eb2dc Michael Hanselmann
401 1a2eb2dc Michael Hanselmann
        # Call back to release lock
402 1a2eb2dc Michael Hanselmann
        postfork_fn(NotImplemented)
403 1a2eb2dc Michael Hanselmann
404 1a2eb2dc Michael Hanselmann
        # See if lockfile can be acquired
405 1a2eb2dc Michael Hanselmann
        trylock.Exclusive(blocking=False)
406 1a2eb2dc Michael Hanselmann
      finally:
407 1a2eb2dc Michael Hanselmann
        trylock.Close()
408 1a2eb2dc Michael Hanselmann
409 1a2eb2dc Michael Hanselmann
      # Simulate a failed command
410 1a2eb2dc Michael Hanselmann
      return utils.RunResult(constants.EXIT_FAILURE, None,
411 1a2eb2dc Michael Hanselmann
                             "stdout", "stderr406328567",
412 1a2eb2dc Michael Hanselmann
                             utils.ShellQuoteArgs(args),
413 1a2eb2dc Michael Hanselmann
                             NotImplemented, NotImplemented)
414 1a2eb2dc Michael Hanselmann
415 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
416 1a2eb2dc Michael Hanselmann
    prepare_fn = testutils.CallCounter(self._SuccessfulPrepare)
417 1a2eb2dc Michael Hanselmann
    runcmd_fn = testutils.CallCounter(fn)
418 1a2eb2dc Michael Hanselmann
419 1a2eb2dc Michael Hanselmann
    try:
420 42bd26e8 Michael Hanselmann
      backend.RunRestrictedCmd("test3079",
421 1a2eb2dc Michael Hanselmann
                               _lock_timeout=1.0, _lock_file=lockfile,
422 1a2eb2dc Michael Hanselmann
                               _path=self.tmpdir, _runcmd_fn=runcmd_fn,
423 1a2eb2dc Michael Hanselmann
                               _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
424 1a2eb2dc Michael Hanselmann
                               _enabled=True)
425 1a2eb2dc Michael Hanselmann
    except backend.RPCFail, err:
426 1a2eb2dc Michael Hanselmann
      self.assertTrue(str(err).startswith("Remote command 'test3079' failed:"))
427 1a2eb2dc Michael Hanselmann
      self.assertTrue("stderr406328567" in str(err),
428 1a2eb2dc Michael Hanselmann
                      msg="Error did not include output")
429 1a2eb2dc Michael Hanselmann
    else:
430 1a2eb2dc Michael Hanselmann
      self.fail("Didn't fail")
431 1a2eb2dc Michael Hanselmann
432 1a2eb2dc Michael Hanselmann
    self.assertEqual(sleep_fn.Count(), 0)
433 1a2eb2dc Michael Hanselmann
    self.assertEqual(prepare_fn.Count(), 1)
434 1a2eb2dc Michael Hanselmann
    self.assertEqual(runcmd_fn.Count(), 1)
435 1a2eb2dc Michael Hanselmann
436 1a2eb2dc Michael Hanselmann
  def testRunCmdSucceeds(self):
437 1a2eb2dc Michael Hanselmann
    lockfile = utils.PathJoin(self.tmpdir, "lock")
438 1a2eb2dc Michael Hanselmann
439 1a2eb2dc Michael Hanselmann
    def fn(args, env=NotImplemented, reset_env=NotImplemented,
440 1a2eb2dc Michael Hanselmann
           postfork_fn=NotImplemented):
441 1a2eb2dc Michael Hanselmann
      self.assertEqual(args, [utils.PathJoin(self.tmpdir, "test5667")])
442 1a2eb2dc Michael Hanselmann
      self.assertEqual(env, {})
443 1a2eb2dc Michael Hanselmann
      self.assertTrue(reset_env)
444 1a2eb2dc Michael Hanselmann
445 1a2eb2dc Michael Hanselmann
      # Call back to release lock
446 1a2eb2dc Michael Hanselmann
      postfork_fn(NotImplemented)
447 1a2eb2dc Michael Hanselmann
448 1a2eb2dc Michael Hanselmann
      # Simulate a successful command
449 1a2eb2dc Michael Hanselmann
      return utils.RunResult(constants.EXIT_SUCCESS, None, "stdout14463", "",
450 1a2eb2dc Michael Hanselmann
                             utils.ShellQuoteArgs(args),
451 1a2eb2dc Michael Hanselmann
                             NotImplemented, NotImplemented)
452 1a2eb2dc Michael Hanselmann
453 405bffe2 Michael Hanselmann
    sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
454 1a2eb2dc Michael Hanselmann
    prepare_fn = testutils.CallCounter(self._SuccessfulPrepare)
455 1a2eb2dc Michael Hanselmann
    runcmd_fn = testutils.CallCounter(fn)
456 1a2eb2dc Michael Hanselmann
457 42bd26e8 Michael Hanselmann
    result = backend.RunRestrictedCmd("test5667",
458 1a2eb2dc Michael Hanselmann
                                      _lock_timeout=1.0, _lock_file=lockfile,
459 1a2eb2dc Michael Hanselmann
                                      _path=self.tmpdir, _runcmd_fn=runcmd_fn,
460 1a2eb2dc Michael Hanselmann
                                      _sleep_fn=sleep_fn,
461 1a2eb2dc Michael Hanselmann
                                      _prepare_fn=prepare_fn,
462 1a2eb2dc Michael Hanselmann
                                      _enabled=True)
463 1a2eb2dc Michael Hanselmann
    self.assertEqual(result, "stdout14463")
464 1a2eb2dc Michael Hanselmann
465 1a2eb2dc Michael Hanselmann
    self.assertEqual(sleep_fn.Count(), 0)
466 1a2eb2dc Michael Hanselmann
    self.assertEqual(prepare_fn.Count(), 1)
467 1a2eb2dc Michael Hanselmann
    self.assertEqual(runcmd_fn.Count(), 1)
468 1a2eb2dc Michael Hanselmann
469 1a2eb2dc Michael Hanselmann
  def testCommandsDisabled(self):
470 1a2eb2dc Michael Hanselmann
    try:
471 42bd26e8 Michael Hanselmann
      backend.RunRestrictedCmd("test",
472 1a2eb2dc Michael Hanselmann
                               _lock_timeout=NotImplemented,
473 1a2eb2dc Michael Hanselmann
                               _lock_file=NotImplemented,
474 1a2eb2dc Michael Hanselmann
                               _path=NotImplemented,
475 1a2eb2dc Michael Hanselmann
                               _sleep_fn=NotImplemented,
476 1a2eb2dc Michael Hanselmann
                               _prepare_fn=NotImplemented,
477 1a2eb2dc Michael Hanselmann
                               _runcmd_fn=NotImplemented,
478 1a2eb2dc Michael Hanselmann
                               _enabled=False)
479 1a2eb2dc Michael Hanselmann
    except backend.RPCFail, err:
480 1a2eb2dc Michael Hanselmann
      self.assertEqual(str(err), "Remote commands disabled at configure time")
481 1a2eb2dc Michael Hanselmann
    else:
482 1a2eb2dc Michael Hanselmann
      self.fail("Did not raise exception")
483 1a2eb2dc Michael Hanselmann
484 1a2eb2dc Michael Hanselmann
485 99e222b1 Michael Hanselmann
class TestSetWatcherPause(unittest.TestCase):
486 99e222b1 Michael Hanselmann
  def setUp(self):
487 99e222b1 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
488 99e222b1 Michael Hanselmann
    self.filename = utils.PathJoin(self.tmpdir, "pause")
489 99e222b1 Michael Hanselmann
490 99e222b1 Michael Hanselmann
  def tearDown(self):
491 99e222b1 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
492 99e222b1 Michael Hanselmann
493 99e222b1 Michael Hanselmann
  def testUnsetNonExisting(self):
494 99e222b1 Michael Hanselmann
    self.assertFalse(os.path.exists(self.filename))
495 99e222b1 Michael Hanselmann
    backend.SetWatcherPause(None, _filename=self.filename)
496 99e222b1 Michael Hanselmann
    self.assertFalse(os.path.exists(self.filename))
497 99e222b1 Michael Hanselmann
498 99e222b1 Michael Hanselmann
  def testSetNonNumeric(self):
499 99e222b1 Michael Hanselmann
    for i in ["", [], {}, "Hello World", "0", "1.0"]:
500 99e222b1 Michael Hanselmann
      self.assertFalse(os.path.exists(self.filename))
501 99e222b1 Michael Hanselmann
502 99e222b1 Michael Hanselmann
      try:
503 99e222b1 Michael Hanselmann
        backend.SetWatcherPause(i, _filename=self.filename)
504 99e222b1 Michael Hanselmann
      except backend.RPCFail, err:
505 99e222b1 Michael Hanselmann
        self.assertEqual(str(err), "Duration must be numeric")
506 99e222b1 Michael Hanselmann
      else:
507 99e222b1 Michael Hanselmann
        self.fail("Did not raise exception")
508 99e222b1 Michael Hanselmann
509 99e222b1 Michael Hanselmann
      self.assertFalse(os.path.exists(self.filename))
510 99e222b1 Michael Hanselmann
511 99e222b1 Michael Hanselmann
  def testSet(self):
512 99e222b1 Michael Hanselmann
    self.assertFalse(os.path.exists(self.filename))
513 99e222b1 Michael Hanselmann
514 99e222b1 Michael Hanselmann
    for i in range(10):
515 99e222b1 Michael Hanselmann
      backend.SetWatcherPause(i, _filename=self.filename)
516 99e222b1 Michael Hanselmann
      self.assertEqual(utils.ReadFile(self.filename), "%s\n" % i)
517 99e222b1 Michael Hanselmann
      self.assertEqual(os.stat(self.filename).st_mode & 0777, 0644)
518 99e222b1 Michael Hanselmann
519 99e222b1 Michael Hanselmann
520 f942a838 Michael Hanselmann
if __name__ == "__main__":
521 f942a838 Michael Hanselmann
  testutils.GanetiTestProgram()