Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.backend_unittest.py @ d01e51a5

History | View | Annotate | Download (18.7 kB)

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