slapgrid.py 47.5 KB
Newer Older
Łukasz Nowak's avatar
Łukasz Nowak committed
1
from slapos.grid import slapgrid
Łukasz Nowak's avatar
Łukasz Nowak committed
2 3
import httplib
import logging
Łukasz Nowak's avatar
Łukasz Nowak committed
4 5
import os
import shutil
6
import signal
7
import slapos.slap.slap
Łukasz Nowak's avatar
Łukasz Nowak committed
8
import socket
9
import sys
10
import tempfile
11
import time
12
import unittest
Łukasz Nowak's avatar
Łukasz Nowak committed
13
import urlparse
14
import xml_marshaller
Łukasz Nowak's avatar
Łukasz Nowak committed
15

Łukasz Nowak's avatar
Łukasz Nowak committed
16
class BasicMixin:
17 18 19
  def assertSortedListEqual(self, list1, list2, msg=None):
    self.assertListEqual(sorted(list1), sorted(list2), msg)

Łukasz Nowak's avatar
Łukasz Nowak committed
20 21
  def setUp(self):
    self._tempdir = tempfile.mkdtemp()
22 23 24
    logging.basicConfig(level=logging.DEBUG)
    self.setSlapgrid()

Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
25
  def setSlapgrid(self, develop=False):
Łukasz Nowak's avatar
Łukasz Nowak committed
26 27
    self.software_root = os.path.join(self._tempdir, 'software')
    self.instance_root = os.path.join(self._tempdir, 'instance')
28
    if getattr(self, 'master_url', None) is None:
29
      self.master_url = 'http://127.0.0.1:80/'
Łukasz Nowak's avatar
Łukasz Nowak committed
30 31 32 33 34 35 36 37 38
    self.computer_id = 'computer'
    self.supervisord_socket = os.path.join(self._tempdir, 'supervisord.sock')
    self.supervisord_configuration_path = os.path.join(self._tempdir,
      'supervisord')
    self.usage_report_periodicity = 1
    self.buildout = None
    self.grid = slapgrid.Slapgrid(self.software_root, self.instance_root,
      self.master_url, self.computer_id, self.supervisord_socket,
      self.supervisord_configuration_path, self.usage_report_periodicity,
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
39 40
      self.buildout, develop=develop)

41

Łukasz Nowak's avatar
Łukasz Nowak committed
42
  def tearDown(self):
Łukasz Nowak's avatar
Łukasz Nowak committed
43 44 45 46 47 48 49 50 51
    # XXX: Hardcoded pid, as it is not configurable in slapos
    svc = os.path.join(self.instance_root, 'var', 'run', 'supervisord.pid')
    if os.path.exists(svc):
      try:
        pid = int(open(svc).read().strip())
      except ValueError:
        pass
      else:
        os.kill(pid, signal.SIGTERM)
52
    shutil.rmtree(self._tempdir, True)
Łukasz Nowak's avatar
Łukasz Nowak committed
53

54

55
class TestBasicSlapgridCP(BasicMixin, unittest.TestCase):
Łukasz Nowak's avatar
Łukasz Nowak committed
56 57 58 59 60 61 62 63 64 65 66
  def test_no_software_root(self):
    self.assertRaises(OSError, self.grid.processComputerPartitionList)

  def test_no_instance_root(self):
    os.mkdir(self.software_root)
    self.assertRaises(OSError, self.grid.processComputerPartitionList)

  def test_no_master(self):
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    self.assertRaises(socket.error, self.grid.processComputerPartitionList)
67 68

class MasterMixin(BasicMixin):
69

70
  def _patchHttplib(self):
71
    """Overrides httplib"""
72 73 74 75 76 77 78
    import mock.httplib

    self.saved_httplib = dict()

    for fake in vars(mock.httplib):
      self.saved_httplib[fake] = getattr(httplib, fake, None)
      setattr(httplib, fake, getattr(mock.httplib, fake))
79

80
  def _unpatchHttplib(self):
81
    """Restores httplib overriding"""
82 83 84 85
    import httplib
    for name, original_value in self.saved_httplib.items():
      setattr(httplib, name, original_value)
    del self.saved_httplib
86

87 88 89 90 91 92 93 94 95 96 97 98 99 100
  def _mock_sleep(self):
    self.fake_waiting_time = None
    self.real_sleep = time.sleep

    def mocked_sleep(secs):
      if self.fake_waiting_time is not None:
        secs = self.fake_waiting_time
      self.real_sleep(secs)

    time.sleep = mocked_sleep

  def _unmock_sleep(self):
    time.sleep = self.real_sleep

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
  def _create_instance(self, name=0):

    if not os.path.isdir(self.instance_root):
      os.mkdir(self.instance_root)

    partition_path = os.path.join(self.instance_root, str(name))
    os.mkdir(partition_path, 0750)
    return partition_path

  def _bootstrap(self):
    os.mkdir(self.software_root)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    return software_hash

124
  def setUp(self):
125
    self._patchHttplib()
126
    self._mock_sleep()
127
    BasicMixin.setUp(self)
128 129

  def tearDown(self):
130
    self._unpatchHttplib()
131
    self._unmock_sleep()
132 133
    BasicMixin.tearDown(self)

134

Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
135
def _server_response (self_test, _requested_state, timestamp=None):
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
136 137
  def server_response(self_httplib, path, method, body, header):
    parsed_url = urlparse.urlparse(path.lstrip('/'))
138
    self_test.sequence.append(parsed_url.path)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    if method == 'GET':
      parsed_qs = urlparse.parse_qs(parsed_url.query)
    else:
      parsed_qs = urlparse.parse_qs(body)
    if parsed_url.path == 'getFullComputerInformation' and \
          'computer_id' in parsed_qs:
      slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
      slap_computer._software_release_list = []
      partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
                                                '0')
      sr = slapos.slap.SoftwareRelease()
      sr._software_release = 'http://sr/'
      partition._software_release_document = sr
      partition._requested_state = _requested_state
      if not timestamp == None :
154
        partition._parameter_dict = {'timestamp': timestamp}
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
      slap_computer._computer_partition_list = [partition]
      return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
    if parsed_url.path == 'availableComputerPartition' and \
          method == 'POST' and 'computer_partition_id' in parsed_qs:
      return (200, {}, '')
    if parsed_url.path == 'startedComputerPartition' and \
          method == 'POST' and 'computer_partition_id' in parsed_qs:
      self_test.assertEqual(parsed_qs['computer_partition_id'][0], '0')
      self_test.started = True
      return (200, {}, '')
    if parsed_url.path == 'stoppedComputerPartition' and \
          method == 'POST' and 'computer_partition_id' in parsed_qs:
      self_test.assertEqual(parsed_qs['computer_partition_id'][0], '0')
      self_test.stopped = True
      return (200, {}, '')
    if parsed_url.path == 'softwareInstanceError' and \
          method == 'POST' and 'computer_partition_id' in parsed_qs:
      self_test.error = True
      self_test.assertEqual(parsed_qs['computer_partition_id'][0], '0')
      return (200, {}, '')
    else:
      return (404, {}, '')
177

Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
178 179 180
  return server_response


181
class TestSlapgridCPWithMaster(MasterMixin, unittest.TestCase):
182

183
  def test_nothing_to_do(self):
184 185

    def server_response(self, path, method, body, header):
186
      parsed_url = urlparse.urlparse(path.lstrip('/'))
187
      parsed_qs = urlparse.parse_qs(parsed_url.query)
188
      if parsed_url.path == 'getFullComputerInformation' and \
189 190 191 192 193 194 195 196 197
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'])
        slap_computer._software_release_list = []
        slap_computer._computer_partition_list = []
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
198 199
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
200
    self.assertTrue(self.grid.processComputerPartitionList())
201 202
    self.assertSortedListEqual(os.listdir(self.instance_root), ['etc', 'var'])
    self.assertSortedListEqual(os.listdir(self.software_root), [])
203 204

  def test_one_partition(self):
205
    self.sequence = []
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
206 207
    httplib.HTTPConnection._callback = _server_response(self,
      _requested_state='stopped')
208

209 210 211 212
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
213 214
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
215 216 217 218 219 220 221 222 223
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
224 225
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
Łukasz Nowak's avatar
Łukasz Nowak committed
226 227 228
    partition = os.path.join(self.instance_root, '0')
    self.assertSortedListEqual(os.listdir(partition), ['worked',
      'buildout.cfg'])
229 230
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
231 232 233
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition'])
234

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  def test_one_free_partition(self):
    """
    Test if slapgrid don't process "free" partition
    """
    def server_response(self, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))
      parsed_qs = urlparse.parse_qs(parsed_url.query)
      if parsed_url.path == 'getFullComputerInformation' and \
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'])
        slap_computer._software_release_list = []
        slap_computer._computer_partition_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        partition._software_release_document = None
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
      else:
        return (404, {}, '')
    httplib.HTTPConnection._callback = server_response

    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['etc', 'var'])
    self.assertSortedListEqual(os.listdir(self.software_root), [])

262
  def test_one_partition_started(self):
263 264
    self.sequence = []
    self.started = False
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
265
    httplib.HTTPConnection._callback = _server_response(self,'started')
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked &&
mkdir -p etc/run &&
echo "#!/bin/sh" > etc/run/wrapper &&
echo "while :; do echo "Working\\nWorking\\n" ; done" >> etc/run/wrapper &&
chmod 755 etc/run/wrapper
""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    self.assertSortedListEqual(os.listdir(partition_path), ['.0_wrapper.log',
      'worked', 'buildout.cfg', 'etc'])
    tries = 10
    wrapper_log = os.path.join(partition_path, '.0_wrapper.log')
    while tries > 0:
      tries -= 1
      if os.path.getsize(wrapper_log) > 0:
        break
      time.sleep(0.2)
    self.assertTrue('Working' in open(wrapper_log, 'r').read())
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
300 301 302 303 304
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'startedComputerPartition'])
    self.assertTrue(self.started)

305 306

  def test_one_partition_started_stopped(self):
307 308
    self.started = True
    self.sequence = []
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
309
    httplib.HTTPConnection._callback = _server_response(self,'started')
310

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked &&
mkdir -p etc/run &&
(
cat <<'HEREDOC'
#!%(python)s
import signal
def handler(signum, frame):
  print 'Signal handler called with signal', signum
  raise SystemExit
signal.signal(signal.SIGTERM, handler)

while True:
  print "Working"
HEREDOC
)> etc/run/wrapper &&
chmod 755 etc/run/wrapper
""" % dict(python = sys.executable))
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    self.assertSortedListEqual(os.listdir(partition_path), ['.0_wrapper.log',
      'worked', 'buildout.cfg', 'etc'])
    wrapper_log = os.path.join(partition_path, '.0_wrapper.log')
    tries = 10
    while tries > 0:
      tries -= 1
      if os.path.getsize(wrapper_log) > 0:
        break
      time.sleep(0.2)
353
    os.path.getsize(wrapper_log)
354 355 356
    self.assertTrue('Working' in open(wrapper_log, 'r').read())
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
357 358 359 360
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'startedComputerPartition'])
    self.assertTrue(self.started)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
361

362 363
    self.stopped = False
    self.sequence = []
364
    self.setSlapgrid()
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
365
    httplib.HTTPConnection._callback = _server_response(self,'stopped')
366

367 368 369 370 371 372
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    self.assertSortedListEqual(os.listdir(partition_path), ['.0_wrapper.log',
      '.0_wrapper.log.1', 'worked', 'buildout.cfg', 'etc'])
    tries = 10
Łukasz Nowak's avatar
Łukasz Nowak committed
373
    expected_text = 'Signal handler called with signal 15'
374 375
    while tries > 0:
      tries -= 1
Łukasz Nowak's avatar
Łukasz Nowak committed
376 377
      found = expected_text in open(wrapper_log, 'r').read()
      if found:
378 379
        break
      time.sleep(0.2)
Łukasz Nowak's avatar
Łukasz Nowak committed
380
    self.assertTrue(found)
381 382 383 384 385
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition'])
    self.assertTrue(self.stopped)

386 387

  def test_one_partition_stopped_started(self):
388 389
    self.stopped = False
    self.sequence = []
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
390
    httplib.HTTPConnection._callback = _server_response(self,'stopped')
391

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked &&
mkdir -p etc/run &&
echo "#!/bin/sh" > etc/run/wrapper &&
echo "while :; do echo "Working\\nWorking\\n" ; done" >> etc/run/wrapper &&
chmod 755 etc/run/wrapper
""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
    self.assertSortedListEqual(os.listdir(partition), ['worked', 'etc',
      'buildout.cfg'])
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
419 420 421 422
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition'])
    self.assertTrue(self.stopped)
423

Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
424
    self.started = False
425
    self.sequence = []
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
426
    httplib.HTTPConnection._callback = _server_response(self,'started')
427

428
    self.setSlapgrid()
429 430 431 432 433 434
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
    self.assertSortedListEqual(os.listdir(partition), ['.0_wrapper.log',
      'worked', 'etc', 'buildout.cfg'])
435 436
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
437 438 439 440 441 442 443 444
    tries = 10
    wrapper_log = os.path.join(partition_path, '.0_wrapper.log')
    while tries > 0:
      tries -= 1
      if os.path.getsize(wrapper_log) > 0:
        break
      time.sleep(0.2)
    self.assertTrue('Working' in open(wrapper_log, 'r').read())
445 446 447 448 449
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'startedComputerPartition'])
    self.assertTrue(self.started)

450
class TestSlapgridCPPartitionProcessing (MasterMixin, unittest.TestCase):
451

452
  def test_partition_timestamp(self):
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
453 454

    self.sequence = []
455 456
    self.timestamp = str(int(time.time()))
    self.started = False
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
457 458
    httplib.HTTPConnection._callback = _server_response(
        self, 'stopped', self.timestamp)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
459 460 461 462 463 464 465 466 467 468 469 470 471

    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
472
touch worked""")
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
473 474 475 476
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
477
    partition = os.path.join(self.instance_root, '0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
478 479 480 481
    self.assertSortedListEqual(
        os.listdir(partition), ['.timestamp', 'worked', 'buildout.cfg'])
    self.assertSortedListEqual(
        os.listdir(self.software_root), [software_hash])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
482
    timestamp_path = os.path.join(partition_path, '.timestamp')
483

484
    self.setSlapgrid()
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
485
    self.assertTrue(self.grid.processComputerPartitionList())
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
486
    self.assertTrue(self.timestamp in open(timestamp_path,'r').read())
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
487
    self.assertEqual(self.sequence,
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
488 489 490 491
                     ['getFullComputerInformation',
                      'availableComputerPartition',
                      'stoppedComputerPartition',
                      'getFullComputerInformation'])
492

Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
493

494 495 496 497 498
  def test_partition_timestamp_develop(self):

    self.sequence = []
    self.timestamp = str(int(time.time()))
    self.started = False
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
499 500
    httplib.HTTPConnection._callback = _server_response(
        self, 'stopped', self.timestamp)
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
519 520 521 522
    self.assertSortedListEqual(
        os.listdir(partition), ['.timestamp','worked', 'buildout.cfg'])
    self.assertSortedListEqual(
        os.listdir(self.software_root), [software_hash])
523 524

    self.setSlapgrid(develop=True)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    self.assertTrue(self.grid.processComputerPartitionList())

    self.setSlapgrid()
    self.assertTrue(self.grid.processComputerPartitionList())

    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition', 'getFullComputerInformation',
                      'availableComputerPartition','stoppedComputerPartition',
                      'getFullComputerInformation'])

  def test_partition_old_timestamp(self):

    self.sequence = []
    self.timestamp = str(int(time.time()))
    self.started = False
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
541 542
    httplib.HTTPConnection._callback = _server_response(
        self,'stopped', self.timestamp)
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561

    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
562 563
    self.assertSortedListEqual(os.listdir(partition),
                               ['.timestamp','worked', 'buildout.cfg'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
564 565 566 567
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])

    self.setSlapgrid()
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
568 569
    httplib.HTTPConnection._callback = _server_response(
        self, 'stopped', str(int(self.timestamp)-1))
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
570 571 572 573
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition', 'getFullComputerInformation'])
574

Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602


  def test_partition_timestamp_new_timestamp(self):

    self.sequence = []
    self.timestamp = str(int(time.time()))
    self.started = False
    httplib.HTTPConnection._callback = _server_response(self,
                                                        'stopped',
                                                        self.timestamp)
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
603 604
    self.assertSortedListEqual(os.listdir(partition),
                               ['.timestamp','worked', 'buildout.cfg'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
605 606 607 608 609
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
    httplib.HTTPConnection._callback = _server_response(self,
                                                        'stopped',
                                                        str(int(self.timestamp)+1))
610
    self.setSlapgrid()
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
611
    self.assertTrue(self.grid.processComputerPartitionList())
612
    self.setSlapgrid()
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition', 'getFullComputerInformation',
                      'availableComputerPartition','stoppedComputerPartition',
                      'getFullComputerInformation'])

  def test_partition_timestamp_no_timestamp(self):

    self.sequence = []
    self.timestamp = str(int(time.time()))
    self.started = False
    httplib.HTTPConnection._callback = _server_response(self,
                                                        'stopped',
                                                        self.timestamp)
    os.mkdir(self.software_root)
    os.mkdir(self.instance_root)
    partition_path = os.path.join(self.instance_root, '0')
    os.mkdir(partition_path, 0750)
    software_hash = slapos.grid.utils.getSoftwareUrlHash('http://sr/')
    srdir = os.path.join(self.software_root, software_hash)
    os.mkdir(srdir)
    open(os.path.join(srdir, 'template.cfg'), 'w').write(
      """[buildout]""")
    srbindir = os.path.join(srdir, 'bin')
    os.mkdir(srbindir)
    open(os.path.join(srbindir, 'buildout'), 'w').write("""#!/bin/sh
touch worked""")
    os.chmod(os.path.join(srbindir, 'buildout'), 0755)
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertSortedListEqual(os.listdir(self.instance_root), ['0', 'etc',
      'var'])
    partition = os.path.join(self.instance_root, '0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
646 647
    self.assertSortedListEqual(os.listdir(partition),
                               ['.timestamp','worked', 'buildout.cfg'])
Cédric Le Ninivin's avatar
Cédric Le Ninivin committed
648 649 650 651
    self.assertSortedListEqual(os.listdir(self.software_root),
      [software_hash])
    httplib.HTTPConnection._callback = _server_response(self,
                                                        'stopped')
652
    self.setSlapgrid()
653 654 655 656 657 658 659
    self.assertTrue(self.grid.processComputerPartitionList())
    self.assertEqual(self.sequence,
                     ['getFullComputerInformation', 'availableComputerPartition',
                      'stoppedComputerPartition', 'getFullComputerInformation',
                      'availableComputerPartition','stoppedComputerPartition',])


660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
class TestSlapgridArgumentTuple(unittest.TestCase):
  """
  """

  def setUp(self):
    """
      Create the minimun default argument and configuration.
    """
    self.certificate_repository_path = tempfile.mkdtemp()
    self.fake_file_descriptor = tempfile.NamedTemporaryFile()
    self.slapos_config_descriptor = tempfile.NamedTemporaryFile()
    self.slapos_config_descriptor.write("""
[slapos]
software_root = /opt/slapgrid
instance_root = /srv/slapgrid
master_url = https://slap.vifib.com/
computer_id = your computer id
buildout = /path/to/buildout/binary
""" % dict(fake_file=self.fake_file_descriptor.name))
    self.slapos_config_descriptor.seek(0)
    self.default_arg_tuple = (
        '--cert_file', self.fake_file_descriptor.name,
        '--key_file', self.fake_file_descriptor.name,
        '--master_ca_file', self.fake_file_descriptor.name,
        '--certificate_repository_path', self.certificate_repository_path,
685
        '-c', self.slapos_config_descriptor.name, '--now')
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703

    self.signature_key_file_descriptor = tempfile.NamedTemporaryFile()
    self.signature_key_file_descriptor.seek(0)

  def tearDown(self):
    """
      Removing the temp file.
    """
    self.fake_file_descriptor.close()
    self.slapos_config_descriptor.close()
    self.signature_key_file_descriptor.close()
    shutil.rmtree(self.certificate_repository_path, True)

  def test_empty_argument_tuple(self):
    """
      Raises if the argument list if empty and without configuration file.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
704 705
    # XXX: SystemExit is too generic exception, it is only known that
    #      something is wrong
Łukasz Nowak's avatar
Łukasz Nowak committed
706
    self.assertRaises(SystemExit, parser, *())
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723

  def test_default_argument_tuple(self):
    """
      Check if we can have the slapgrid object returned with the minimum
      arguments.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
    return_list = parser(*self.default_arg_tuple)
    self.assertEquals(2, len(return_list))

  def test_signature_private_key_file_non_exists(self):
    """
      Raises if the  signature_private_key_file does not exists.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
    argument_tuple = ("--signature_private_key_file", "/non/exists/path") + \
                      self.default_arg_tuple
724 725 726
    # XXX: SystemExit is too generic exception, it is only known that
    #      something is wrong
    self.assertRaises(SystemExit, parser, *argument_tuple)
727 728 729 730 731 732 733 734 735 736 737 738 739

  def test_signature_private_key_file(self):
    """
      Check if the signature private key argument value is available on
      slapgrid object.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
    argument_tuple = ("--signature_private_key_file",
                      self.signature_key_file_descriptor.name) + \
                      self.default_arg_tuple
    slapgrid_object = parser(*argument_tuple)[0]
    self.assertEquals(self.signature_key_file_descriptor.name,
                          slapgrid_object.signature_private_key_file)
740

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  def test_backward_compatibility_all(self):
    """
      Check if giving --all triggers "develop" option.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
    argument_tuple = ("--all",) + self.default_arg_tuple
    slapgrid_object = parser(*argument_tuple)[0]
    self.assertTrue(slapgrid_object.develop)

  def test_backward_compatibility_not_all(self):
    """
      Check if not giving --all neither --develop triggers "develop"
      option to be False.
    """
    parser = slapgrid.parseArgumentTupleAndReturnSlapgridObject
    argument_tuple = self.default_arg_tuple
    slapgrid_object = parser(*argument_tuple)[0]
    self.assertFalse(slapgrid_object.develop)


761
class TestSlapgridCPWithMasterPromise(MasterMixin, unittest.TestCase):
762 763 764 765 766 767 768 769 770
  def test_one_failing_promise(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)
771
      if parsed_url.path == 'getFullComputerInformation' and \
772 773 774 775 776 777 778 779
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
780
        partition._requested_state = 'started'
781 782
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
783 784 785 786 787 788 789 790
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
791
      if parsed_url.path == 'softwareInstanceError' and \
792
            method == 'POST' and 'computer_partition_id' in parsed_qs:
793 794 795 796 797 798 799
        self.error = True
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
800
    self.fake_waiting_time = 0.2
801
    self.error = False
802
    self.started = False
803 804

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
805
    self._bootstrap()
806 807 808 809

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)
    fail = os.path.join(promise_path, 'fail')
810
    worked_file = os.path.join(instance_path, 'fail_worked')
811 812
    with open(fail, 'w') as f:
      f.write("""#!/usr/bin/env sh
813 814
touch "%(worked_file)s"
exit 127""" % {'worked_file': worked_file})
815
    os.chmod(fail, 0777)
816
    self.assertFalse(self.grid.processComputerPartitionList())
817
    self.assertTrue(os.path.isfile(worked_file))
818 819

    self.assertTrue(self.error)
820
    self.assertFalse(self.started)
821 822 823 824 825 826 827 828 829 830 831

  def test_one_succeeding_promise(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)

832
      if parsed_url.path == 'getFullComputerInformation' and \
833 834 835 836 837 838 839 840
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
841
        partition._requested_state = 'started'
842 843
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
844 845 846 847 848 849 850 851
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
852 853 854 855 856 857 858 859 860
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error = True
        raise AssertionError('ComputerPartition.error was raised')
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
861
    self.fake_waiting_time = 0.2
862
    self.error = False
863
    self.started = False
864 865

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
866
    self._bootstrap()
867 868 869 870

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)
    succeed = os.path.join(promise_path, 'succeed')
871
    worked_file = os.path.join(instance_path, 'succeed_worked')
872 873
    with open(succeed, 'w') as f:
      f.write("""#!/usr/bin/env sh
874 875
touch "%(worked_file)s"
exit 0""" % {'worked_file': worked_file})
876 877
    os.chmod(succeed, 0777)
    self.assertTrue(self.grid.processComputerPartitionList())
878
    self.assertTrue(os.path.isfile(worked_file))
879 880

    self.assertFalse(self.error)
881
    self.assertTrue(self.started)
882 883 884 885 886 887 888 889 890 891 892

  def test_stderr_has_been_sent(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)

893
      if parsed_url.path == 'getFullComputerInformation' and \
894 895 896 897 898 899 900 901
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
902
        partition._requested_state = 'started'
903 904
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
905 906 907 908 909 910 911 912
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
913 914 915 916 917
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error = True
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        # XXX: Hardcoded dropPrivileges line ignore
Łukasz Nowak's avatar
Łukasz Nowak committed
918
        self.error_log = '\n'.join([line for line in parsed_qs['error_log'][0].splitlines()
919 920 921 922 923 924 925 926 927
                               if 'dropPrivileges' not in line])
        # end XXX
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
    self.fake_waiting_time = 0.5
    self.error = False
928
    self.started = False
929 930

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
931
    self._bootstrap()
932 933 934

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)
935
    succeed = os.path.join(promise_path, 'stderr_writer')
936
    worked_file = os.path.join(instance_path, 'stderr_worked')
937 938
    with open(succeed, 'w') as f:
      f.write("""#!/usr/bin/env sh
939
touch "%(worked_file)s"
940
echo Error 1>&2
941
exit 127""" % {'worked_file': worked_file})
942
    os.chmod(succeed, 0777)
943
    self.assertFalse(self.grid.processComputerPartitionList())
944
    self.assertTrue(os.path.isfile(worked_file))
945

Łukasz Nowak's avatar
Łukasz Nowak committed
946
    self.assertEqual(self.error_log, 'Error')
947
    self.assertTrue(self.error)
948 949
    self.assertFalse(self.started)

950 951 952 953 954 955 956 957 958 959

  def test_timeout_works(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)
960
      if parsed_url.path == 'getFullComputerInformation' and \
961 962 963 964 965 966 967 968
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
969
        partition._requested_state = 'started'
970 971
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
972 973 974 975 976 977 978 979
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error = True
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        # XXX: Hardcoded dropPrivileges line ignore
        error_log = '\n'.join([line for line in parsed_qs['error_log'][0].splitlines()
                               if 'dropPrivileges' not in line])
        # end XXX
        self.assertEqual(error_log, 'The promise %r timed out' % 'timed_out_promise')
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
    self.fake_waiting_time = 0.2
    self.error = False
996
    self.started = False
997 998

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
999
    self._bootstrap()
1000 1001 1002 1003

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)
    succeed = os.path.join(promise_path, 'timed_out_promise')
1004
    worked_file = os.path.join(instance_path, 'timed_out_worked')
1005 1006
    with open(succeed, 'w') as f:
      f.write("""#!/usr/bin/env sh
1007
touch "%(worked_file)s"
1008
sleep 5
1009
exit 0""" % {'worked_file': worked_file})
1010
    os.chmod(succeed, 0777)
1011
    self.assertFalse(self.grid.processComputerPartitionList())
1012
    self.assertTrue(os.path.isfile(worked_file))
1013 1014

    self.assertTrue(self.error)
1015
    self.assertFalse(self.started)
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

  def test_two_succeeding_promises(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)

1027
      if parsed_url.path == 'getFullComputerInformation' and \
1028 1029 1030 1031 1032 1033 1034 1035
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
1036
        partition._requested_state = 'started'
1037 1038
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
1039 1040 1041 1042 1043 1044 1045 1046
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error = True
        raise AssertionError('ComputerPartition.error was raised')
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
    self.fake_waiting_time = 0.2
    self.error = False
1058
    self.started = False
1059 1060

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
1061
    self._bootstrap()
1062 1063 1064 1065 1066

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)

    succeed = os.path.join(promise_path, 'succeed')
1067
    worked_file = os.path.join(instance_path, 'succeed_worked')
1068 1069
    with open(succeed, 'w') as f:
      f.write("""#!/usr/bin/env sh
1070 1071
touch "%(worked_file)s"
exit 0""" % {'worked_file': worked_file})
1072 1073
    os.chmod(succeed, 0777)

1074
    succeed_2 = os.path.join(promise_path, 'succeed_2')
1075
    worked_file_2 = os.path.join(instance_path, 'succeed_2_worked')
1076 1077
    with open(succeed_2, 'w') as f:
      f.write("""#!/usr/bin/env sh
1078 1079
touch "%(worked_file)s"
exit 0""" % {'worked_file': worked_file_2})
1080 1081 1082
    os.chmod(succeed_2, 0777)

    self.assertTrue(self.grid.processComputerPartitionList())
1083 1084
    self.assertTrue(os.path.isfile(worked_file))
    self.assertTrue(os.path.isfile(worked_file_2))
1085 1086

    self.assertFalse(self.error)
1087
    self.assertTrue(self.started)
1088

1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
  def test_one_succeeding_one_failing_promises(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)

1099
      if parsed_url.path == 'getFullComputerInformation' and \
1100 1101 1102 1103 1104 1105 1106 1107
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
1108
        partition._requested_state = 'started'
1109 1110
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
1111 1112 1113 1114 1115 1116 1117 1118
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error += 1
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
    self.fake_waiting_time = 0.2
    self.error = 0
1130
    self.started = False
1131 1132

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
1133
    self._bootstrap()
1134 1135 1136 1137

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)

1138 1139
    promises_files = []
    for i in range(2):
1140
      promise = os.path.join(promise_path, 'promise_%d' % i)
1141
      promises_files.append(promise)
1142
      worked_file = os.path.join(instance_path, 'promise_worked_%d' % i)
1143 1144 1145
      lockfile = os.path.join(instance_path, 'lock')
      with open(promise, 'w') as f:
        f.write("""#!/usr/bin/env sh
1146
touch "%(worked_file)s"
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
1147
if [ ! -f %(lockfile)s ]
1148
then
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
1149 1150 1151
  touch "%(lockfile)s"
  exit 0
else
1152 1153
  exit 127
fi""" % {'worked_file': worked_file, 'lockfile': lockfile})
1154
      os.chmod(promise, 0777)
1155
    self.assertFalse(self.grid.processComputerPartitionList())
1156 1157
    for file_ in promises_files:
      self.assertTrue(os.path.isfile(file_))
1158 1159

    self.assertEquals(self.error, 1)
1160
    self.assertFalse(self.started)
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171

  def test_one_succeeding_one_timing_out_promises(self):

    def server_response(self_httplib, path, method, body, header):
      parsed_url = urlparse.urlparse(path.lstrip('/'))

      if method == 'GET':
        parsed_qs = urlparse.parse_qs(parsed_url.query)
      else:
        parsed_qs = urlparse.parse_qs(body)

1172
      if parsed_url.path == 'getFullComputerInformation' and \
1173 1174 1175 1176 1177 1178 1179 1180
         'computer_id' in parsed_qs:
        slap_computer = slapos.slap.Computer(parsed_qs['computer_id'][0])
        slap_computer._software_release_list = []
        partition = slapos.slap.ComputerPartition(parsed_qs['computer_id'][0],
            '0')
        sr = slapos.slap.SoftwareRelease()
        sr._software_release = 'http://sr/'
        partition._software_release_document = sr
1181
        partition._requested_state = 'started'
1182 1183
        slap_computer._computer_partition_list = [partition]
        return (200, {}, xml_marshaller.xml_marshaller.dumps(slap_computer))
1184 1185 1186 1187 1188 1189 1190 1191
      if parsed_url.path == 'availableComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        return (200, {}, '')
      if parsed_url.path == 'startedComputerPartition' and \
            method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
        self.started = True
        return (200, {}, '')
1192 1193 1194
      if parsed_url.path == 'softwareInstanceError' and \
         method == 'POST' and 'computer_partition_id' in parsed_qs:
        self.error += 1
1195
        self.assertEqual(parsed_qs['computer_partition_id'][0], '0')
1196 1197 1198 1199 1200 1201 1202
        return (200, {}, '')
      else:
        return (404, {}, '')

    httplib.HTTPConnection._callback = server_response
    self.fake_waiting_time = 0.2
    self.error = 0
1203
    self.started = False
1204 1205

    instance_path = self._create_instance('0')
Cédric de Saint Martin's avatar
Cédric de Saint Martin committed
1206
    self._bootstrap()
1207 1208 1209 1210

    promise_path = os.path.join(instance_path, 'etc', 'promise')
    os.makedirs(promise_path)

1211 1212
    promises_files = []
    for i in range(2):
1213
      promise = os.path.join(promise_path, 'promise_%d' % i)
1214
      promises_files.append(promise)
1215
      worked_file = os.path.join(instance_path, 'promise_worked_%d' % i)
1216 1217 1218
      lockfile = os.path.join(instance_path, 'lock')
      with open(promise, 'w') as f:
        f.write("""#!/usr/bin/env sh
1219
touch "%(worked_file)s"
1220
if [ ! -f %(lockfile)s ]
1221
then
1222 1223
  touch "%(lockfile)s"
else
1224 1225 1226
  sleep 5
fi
exit 0"""  % {'worked_file': worked_file, 'lockfile': lockfile})
1227
      os.chmod(promise, 0777)
1228 1229


1230
    self.assertFalse(self.grid.processComputerPartitionList())
1231 1232
    for file_ in promises_files:
      self.assertTrue(os.path.isfile(file_))
1233 1234

    self.assertEquals(self.error, 1)
1235
    self.assertFalse(self.started)
1236 1237 1238

  def test_slapgrid_processes_partition_after_global_timeout(self):
    """
1239 1240
    Test that slapgrid processes again partition after delay defined by
    slapgrid even if .timestamp is up-to-date.
1241
    """
1242 1243
    # XXX Not implemented
    pass
1244 1245 1246

  def test_slapgrid_processes_partition_after_timeout_defined_by_software_release(self):
    """
1247 1248
    Test that if SR of instance defines a "buildotu delay", slapgrid processes
    again partition after that delay and NOT after delay defined by slapgrid.
1249
    """
1250 1251
    # XXX Not implemented
    pass