# -*- coding: utf-8 -*- import os, time import sys import shutil import tempfile import unittest import json from datetime import datetime from slapos.monitor.runpromise import MonitorPromiseLauncher, getArgumentParser from slapos.grid.promise.generic import PROMISE_LOG_FOLDER_NAME, PROMISE_RESULT_FOLDER_NAME class MonitorPromiseTest(unittest.TestCase): def setUp(self): self.base_dir = tempfile.mkdtemp() self.etc_dir = os.path.join(self.base_dir, 'etc') self.output_dir = os.path.join(self.base_dir, PROMISE_RESULT_FOLDER_NAME) self.log_output_dir = os.path.join(self.base_dir, PROMISE_LOG_FOLDER_NAME) self.promise_dir = os.path.join(self.etc_dir, 'plugin') self.old_promise_dir = os.path.join(self.etc_dir, 'promise') self.public_dir = os.path.join(self.base_dir, 'public') self.private_dir = os.path.join(self.base_dir, 'private') self.run_dir = os.path.join(self.base_dir, 'run') self.log_dir = os.path.join(self.base_dir, 'log') os.mkdir(self.etc_dir) os.mkdir(self.promise_dir) os.mkdir(self.public_dir) os.mkdir(self.private_dir) os.mkdir(self.run_dir) os.mkdir(self.old_promise_dir) os.mkdir(self.log_dir) self.monitor_config = """[monitor] private-folder = %(base_dir)s/private public-folder = %(base_dir)s/public root-title = %(root_title)s log-folder = %(base_dir)s/log base-url = %(base_url)s title = %(title)s [promises] pid-path = %(base_dir)s/run/promises.pid partition-folder = %(base_dir)s computer-id = COMP-1234 partition-cert = partition-key = partition-id = slappart0 ipv6 = 2001:34c:1254:df3:89::5df3 software-release = http://some.url.com/software.cfg master-url = http://10.0.151.118:50000 software-type = default ipv4 = 10.0.151.118 """ % {'base_dir': self.base_dir, 'title': 'Monitor', 'root_title': 'Monitor ROOT', 'base_url': 'https://monitor.test.com', } self.monitor_config_file = os.path.join(self.base_dir, 'monitor.conf') with open(self.monitor_config_file, 'w') as f: f.write(self.monitor_config) def tearDown(self): if os.path.exists(self.base_dir): shutil.rmtree(self.base_dir) def writePromiseOK(self, name): content = """#!/bin/sh echo "success" exit 0 """ promise_path = os.path.join(self.old_promise_dir, name) self.writeContent(promise_path, content) os.chmod(promise_path, 0755) return promise_path def writePromiseNOK(self, name): content = """#!/bin/sh echo "failed" exit 2 """ promise_path = os.path.join(self.old_promise_dir, name) self.writeContent(promise_path, content) os.chmod(promise_path, 0755) return promise_path def generatePromiseScript(self, name, success=True, failure_count=1, content="", periodicity=0.03): promise_content = """from zope import interface as zope_interface from slapos.grid.promise import interface from slapos.grid.promise import GenericPromise class RunPromise(GenericPromise): zope_interface.implements(interface.IPromise) def __init__(self, config): GenericPromise.__init__(self, config) self.setPeriodicity(minute=%(periodicity)s) def sense(self): %(content)s if not %(success)s: self.logger.error("failed") else: self.logger.info("success") def anomaly(self): return self._anomaly(result_count=2, failure_amount=%(failure_amount)s) def test(self): return self._test(result_count=1, failure_amount=%(failure_amount)s) """ % {'success': success, 'content': content, 'failure_amount': failure_count, 'periodicity': periodicity} with open(os.path.join(self.promise_dir, name), 'w') as f: f.write(promise_content) return os.path.join(self.promise_dir, name) def writeContent(self, file_path, config): with open(file_path, 'w') as cfg: cfg.write(config) def getPromiseParser(self, use_config=True, check_anomaly=False, force=False): arg_parser = getArgumentParser() base_list = ['-c', self.monitor_config_file] if use_config: if check_anomaly: base_list.append('-a') if force: base_list.append('--force') return arg_parser.parse_args(base_list) pid_path = os.path.join(self.run_dir, 'monitor-promise.pid') promise_cmd = [ '--pid-path', '%s' % pid_path, '-o', self.public_dir, '--master-url', 'http://10.0.151.118:50000', '--partition-id', 'slappart0', '--computer-id', 'COMP-1234'] return arg_parser.parse_args(promise_cmd) def test_promise_generic(self): promise_file = self.generatePromiseScript('my_promise.py', success=True) promise_file2 = self.generatePromiseScript('my_second_promise.py', success=True) parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'my_promise.status.json') os.system('cat %s' % result_file) self.assertTrue(os.path.exists(result_file)) my_result = json.loads(open(result_file).read().decode("utf-8")) my_result['result'].pop('date') expected_result = { u'title': u'my_promise', u'name': u'my_promise.py', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s/my_promise.py' % self.promise_dir, } self.assertEqual(expected_result, my_result) result_file = os.path.join(self.output_dir, 'my_second_promise.status.json') self.assertTrue(os.path.exists(result_file)) second_result = json.loads(open(result_file).read().decode("utf-8")) second_result['result'].pop('date') expected_result = { u'title': u'my_second_promise', u'name': u'my_second_promise.py', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s/my_second_promise.py' % self.promise_dir, } self.assertEqual(expected_result, second_result) def test_promise_generic_failed(self): promise_file = self.generatePromiseScript('my_promise.py', success=False) parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'my_promise.status.json') self.assertTrue(os.path.exists(result_file)) my_result = json.loads(open(result_file).read().decode("utf-8")) my_result['result'].pop('date') expected_result = { u'title': u'my_promise', u'name': u'my_promise.py', u'result': { u'failed': True, u'message': u'failed', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s/my_promise.py' % self.promise_dir, } self.assertEqual(expected_result, my_result) def test_promise_generic_status_change(self): promise_file = self.generatePromiseScript('my_promise.py', success=False) parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'my_promise.status.json') self.assertTrue(os.path.exists(result_file)) my_result = json.loads(open(result_file).read().decode("utf-8")) my_result['result'].pop('date') expected_result = { u'title': u'my_promise', u'name': u'my_promise.py', u'result': { u'failed': True, u'message': u'failed', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s/my_promise.py' % self.promise_dir, } self.assertEqual(expected_result, my_result) os.system('rm %s/*.pyc' % self.promise_dir) time.sleep(2) self.generatePromiseScript('my_promise.py', success=True) promise_runner2 = MonitorPromiseLauncher(parser) promise_runner2.start() my_result = json.loads(open(result_file).read().decode("utf-8")) my_result['result'].pop('date') expected_result = { u'title': u'my_promise', u'name': u'my_promise.py', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s/my_promise.py' % self.promise_dir, } self.assertEqual(expected_result, my_result) def test_promise_generic_periodicity(self): promise_file = self.generatePromiseScript('my_promise.py', success=False, periodicity=0.03) parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'my_promise.status.json') self.assertTrue(os.path.exists(result_file)) # run again os.unlink(result_file) promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() self.assertFalse(os.path.exists(result_file)) time.sleep(2) promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() self.assertTrue(os.path.exists(result_file)) def test_promise_generic_run_only(self): promise_file = self.generatePromiseScript('my_promise.py', success=False) second_promise = self.generatePromiseScript('my_second_promise.py', success=False) parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'my_promise.status.json') second_result = os.path.join(self.output_dir, 'my_second_promise.status.json') self.assertTrue(os.path.exists(result_file)) self.assertTrue(os.path.exists(second_result)) config = getArgumentParser().parse_args(['-c', self.monitor_config_file, '-a', '-f', '--run-only', 'my_second_promise.py']) os.unlink(result_file) promise_runner = MonitorPromiseLauncher(config) promise_runner.start() self.assertFalse(os.path.exists(result_file)) self.assertTrue(os.path.exists(second_result)) def test_promise_OK(self): promise = self.writePromiseOK('promise_1') parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'promise_1.status.json') self.assertTrue(os.path.exists(result_file)) result1 = json.loads(open(result_file).read().decode("utf-8")) start_date = datetime.strptime(result1['result'].pop('date'), '%Y-%m-%dT%H:%M:%S') expected_result = { u'title': u'promise_1', u'name': u'promise_1', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s' % promise, } # second run parser = self.getPromiseParser(force=True) promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result2 = json.loads(open(result_file).read().decode("utf-8")) start_date2 = datetime.strptime(result2['result'].pop('date'), '%Y-%m-%dT%H:%M:%S') self.assertEqual(expected_result, result2) def test_promise_two_folder(self): promise = self.writePromiseOK('promise_1') promise2 = self.writePromiseOK('promise_2') parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'promise_1.status.json') result2_file = os.path.join(self.output_dir, 'promise_2.status.json') self.assertTrue(os.path.exists(result_file)) self.assertTrue(os.path.exists(result2_file)) result1 = json.loads(open(result_file).read().decode("utf-8")) start_date = datetime.strptime(result1['result'].pop('date'), '%Y-%m-%dT%H:%M:%S') expected_result = { u'title': u'promise_1', u'name': u'promise_1', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s' % promise, } self.assertEqual(expected_result, result1) result2 = json.loads(open(result2_file).read()) start_date2 = datetime.strptime(result2['result'].pop('date'), '%Y-%m-%dT%H:%M:%S') expected_result = { u'title': u'promise_2', u'name': u'promise_2', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s' % promise2, } self.assertEqual(expected_result, result2) def test_promise_NOK(self): promise = self.writePromiseNOK('promise_1') parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'promise_1.status.json') self.assertTrue(os.path.exists(result_file)) result1 = json.loads(open(result_file).read().decode("utf-8")) result1['result'].pop('date') expected_result = { u'title': u'promise_1', u'name': u'promise_1', u'result': { u'failed': True, u'message': u'failed', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s' % promise, } self.assertEqual(expected_result, result1) # second run promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result2 = json.loads(open(result_file).read().decode("utf-8")) result2['result'].pop('date') self.assertEqual(expected_result, result2) def test_promise_mixed(self): promise = self.writePromiseOK('promise_1') parser = self.getPromiseParser() promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result_file = os.path.join(self.output_dir, 'promise_1.status.json') self.assertTrue(os.path.exists(result_file)) result1 = json.loads(open(result_file).read().decode("utf-8")) result1['result'].pop('date') expected_result = { u'title': u'promise_1', u'name': u'promise_1', u'result': { u'failed': False, u'message': u'success', u'type': u'Test Result' }, u'execution-time': 0.1, u'path': u'%s' % promise, } self.assertEqual(expected_result, result1) # second run with failure time.sleep(1) promise = self.writePromiseNOK('promise_1') parser = self.getPromiseParser(force=True) expected_result['result']['message'] = u'failed' expected_result['result']['failed'] = True promise_runner = MonitorPromiseLauncher(parser) promise_runner.start() result2 = json.loads(open(result_file).read().decode("utf-8")) result2['result'].pop('date') self.assertEqual(expected_result, result2)