~blake-rouse/maas/maas-prometheus

« back to all changes in this revision

Viewing changes to src/metadataserver/user_data/templates/snippets/tests/test_maas_run_remote_scripts.py

  • Committer: MAAS Lander
  • Author(s): Lee Trager
  • Date: 2017-04-12 18:59:01 UTC
  • mfrom: (5921.1.9 node_side_timeout)
  • Revision ID: maas_lander-20170412185901-gwe80eh1zkk9qy7y
[r=mpontillo][bug=1679431][author=ltrager] Add machine, region, rack side timeout checking when running commissioning and testing scripts.

Machines, regions, and racks now detect timeouts when running scripts. A buffer of one minute is added to the given timeout to allow for cleanup. If the script run time exceeds the buffered time out a signal is sent to the region that the script has timed out. The machine, region, or rack will then proceed to the next script. A timed out script will still cause the node to go transition to a failed status.

The region still checks if the script has timed out and marks the node failed. However this now happens 5 minutes after the script time out to give the machine a chance to kill the script and signal that its moving on.  Region and racks are not subject to this check.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 
6
6
__all__ = []
7
7
 
 
8
from datetime import timedelta
8
9
from io import BytesIO
9
10
import json
10
11
import os
11
12
import random
 
13
from subprocess import TimeoutExpired
12
14
import tarfile
13
15
from unittest.mock import ANY
14
16
 
39
41
                'path': '%s/%s' % (factory.make_name('dir'), name),
40
42
                'script_result_id': random.randint(1, 1000),
41
43
                'script_version_id': random.randint(1, 1000),
 
44
                'timeout_seconds': random.randint(1, 500),
42
45
            })
43
46
        return scripts
44
47
 
208
211
            mock_signal,
209
212
            MockAnyCall(
210
213
                creds=None, url=None, status='WORKING', exit_status=8,
211
 
                error='Finished %s [1/1]: 8' % script['name'],
 
214
                error='Failed to execute %s [1/1]: 8' % script['name'],
212
215
                script_result_id=script['script_result_id'],
213
216
                script_version_id=script['script_version_id'],
214
217
                files={
243
246
            mock_signal,
244
247
            MockAnyCall(
245
248
                creds=None, url=None, status='WORKING', exit_status=2,
246
 
                error='Finished %s [1/1]: 2' % script['name'],
 
249
                error='Failed to execute %s [1/1]: 2' % script['name'],
247
250
                script_result_id=script['script_result_id'],
248
251
                script_version_id=script['script_version_id'],
249
252
                files={
278
281
            mock_signal,
279
282
            MockAnyCall(
280
283
                creds=None, url=None, status='WORKING', exit_status=2,
281
 
                error='Finished %s [1/1]: 2' % script['name'],
 
284
                error='Failed to execute %s [1/1]: 2' % script['name'],
282
285
                script_result_id=script['script_result_id'],
283
286
                script_version_id=script['script_version_id'],
284
287
                files={
289
292
            mock_signal,
290
293
            MockAnyCall(
291
294
                None, None, 'FAILED', '1 scripts failed to run'))
 
295
 
 
296
    def test_run_scripts_signals_timeout(self):
 
297
        scripts_dir = self.useFixture(TempDirectory()).path
 
298
        mock_signal = self.patch(maas_run_remote_scripts, 'signal')
 
299
        self.patch(maas_run_remote_scripts, 'Popen')
 
300
        scripts = self.make_scripts()
 
301
        self.make_script_output(scripts, scripts_dir)
 
302
        mock_cap = self.patch(maas_run_remote_scripts, 'capture_script_output')
 
303
        mock_cap.side_effect = TimeoutExpired(
 
304
            [factory.make_name('arg') for _ in range(3)],
 
305
            scripts[0]['timeout_seconds'])
 
306
 
 
307
        # Don't need to give the url or creds as we're not running the scripts
 
308
        # and sending the result. The scripts_dir and out_dir are the same as
 
309
        # in the test environment there isn't anything in the scripts_dir.
 
310
        self.assertEquals(
 
311
            1, run_scripts(None, None, scripts_dir, scripts_dir, scripts))
 
312
 
 
313
        self.assertThat(
 
314
            mock_signal,
 
315
            MockAnyCall(
 
316
                creds=None, url=None, status='TIMEDOUT',
 
317
                error='Timeout(%s) expired on %s [1/1]' % (
 
318
                    str(timedelta(seconds=scripts[0]['timeout_seconds'])),
 
319
                    scripts[0]['name']),
 
320
                script_result_id=scripts[0]['script_result_id'],
 
321
                script_version_id=scripts[0]['script_version_id'],
 
322
                files={
 
323
                    scripts[0]['name']: scripts[0]['output'],
 
324
                    '%s.out' % scripts[0]['name']: scripts[0]['stdout'],
 
325
                    '%s.err' % scripts[0]['name']: scripts[0]['stderr'],
 
326
                }))
 
327
        self.assertThat(
 
328
            mock_signal,
 
329
            MockAnyCall(
 
330
                None, None, 'FAILED', '1 scripts failed to run'))