From 3fb6e51a9006dfdda45017103e2a3e43150a69d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20de=20Saint=20Martin?= <cedric.dsm@tiolive.com> Date: Fri, 30 Aug 2013 11:04:54 +0200 Subject: [PATCH] Resiliency test: add slaprunner test suite. --- slapos/resiliencytest/suites/slaprunner.py | 190 +++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 slapos/resiliencytest/suites/slaprunner.py diff --git a/slapos/resiliencytest/suites/slaprunner.py b/slapos/resiliencytest/suites/slaprunner.py new file mode 100644 index 0000000..5a4b8e0 --- /dev/null +++ b/slapos/resiliencytest/suites/slaprunner.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2013 Vifib SARL and Contributors. All Rights Reserved. +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from .resiliencytestsuite import ResiliencyTestSuite + +import cookielib +import random +import string +import time +import urllib2 + +class NotHttpOkException(Exception): + pass + +class SlaprunnerTestSuite(ResiliencyTestSuite): + """ + Run Slaprunner Resiliency Test. + It is highly suggested to read ResiliencyTestSuite code. + """ + def __init__(self, + server_url, key_file, cert_file, + computer_id, partition_id, software, + namebase, slaprunner_rootinstance_name, + total_instance_count="3"): + + # Setup urllib2 with cookie support + cookie_jar = cookielib.CookieJar() + self._opener_director = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar)) + + ResiliencyTestSuite.__init__( + self, + server_url, key_file, cert_file, + computer_id, partition_id, software, + namebase, + slaprunner_rootinstance_name + ) + + def generateData(self): + self.slaprunner_password = ''.join(random.SystemRandom().sample(string.ascii_lowercase, 8)) + self.slaprunner_user = 'slapos' + self.logger.info('Generated slaprunner user is: %s' % self.slaprunner_user) + self.logger.info('Generated slaprunner password is: %s' % self.slaprunner_password) + + def _connectToSlaprunner(self, resource, data=None): + """ + Utility. + Connect through HTTP to the slaprunner instance. + Require self.slaprunner_backend_url to be set. + """ + url = "%s/%s" % (self.slaprunner_backend_url, resource) + if data: + result = self._opener_director.open(url, data=data) + else: + result = self._opener_director.open(url) + + if result.getcode() is not 200: + raise NotHttpOkException(result.getcode()) + return result.read() + + def _login(self): + self.logger.debug('Logging in...') + self._connectToSlaprunner('doLogin', data='clogin=%s&cpwd=%s' % (self.slaprunner_user, self.slaprunner_password)) + + def _retrieveInstanceLogFile(self): + """ + Store the logfile (=data) of the instance, check it is not empty nor it is html. + """ + data = self._connectToSlaprunner(resource='fileBrowser', data='opt=9&filename=log.log&dir=instance_root%252Fslappart0%252Fvar%252Flog%252F') + self.logger.info('Retrieved data are:\n%s' % data) + + if data.find('<') is not -1: + raise IOError('Could not retrieve logfile content: retrieved content is html.') + if data.find('Could not load') is not -1: + raise IOError('Could not retrieve logfile content: server could not load the file.') + if data.find('Hello') is -1: + raise IOError('Could not retrieve logfile content: retrieve content does not match "Hello".') + return data + + def pushDataOnMainInstance(self): + """ + Create a dummy Software Release, + Build it, + Wait for build to be successful, + Deploy instance, + Wait for instance to be started. + Store the main IP of the slaprunner for future use. + """ + self.logger.debug('Getting the backend URL and recovery code...') + parameter_dict = self._getPartitionParameterDict() + self.slaprunner_backend_url = parameter_dict['backend_url'] + self.logger.info('backend_url is %s.' % self.slaprunner_backend_url) + slaprunner_recovery_code = parameter_dict['password_recovery_code'] + + self.logger.debug('Creating the slaprunner account...') + self._connectToSlaprunner(resource='configAccount', data='name=slapos&username=%s&email=slapos@slapos.org&password=%s&rcode=%s' % (self.slaprunner_user, self.slaprunner_password, slaprunner_recovery_code)) + + self._login() + + self.logger.debug('Opening hello-world software release from git...') + try: + self._connectToSlaprunner(resource='cloneRepository', data='repo=http://git.erp5.org/repos/slapos.git&name=workspace/slapos&email=slapos@slapos.org&user=slapos') + except (NotHttpOkException, urllib2.HTTPError): + # cloning can be very long. + # XXX: quite dirty way to check. + while self._connectToSlaprunner('getProjectStatus', data='project=workspace/slapos').find('On branch master') is -1: + self.logger.info('git-cloning ongoing, sleeping...') + + # XXX should be taken from parameter. + self._connectToSlaprunner(resource='setCurrentProject', data='path=workspace/slapos/software/helloworld/') + + self.logger.info('Building the Software Release...') + try: + self._connectToSlaprunner(resource='runSoftwareProfile') + except (NotHttpOkException, urllib2.HTTPError): + # The nginx frontend might timeout before software release is finished. + pass + while self._connectToSlaprunner(resource='slapgridResult', data='position=0&log=').find('"software": true') is not -1: + self.logger.info('Buildout is still running. Sleeping...') + time.sleep(15) + self.logger.info('Software Release has been built.') + + self.logger.info('Deploying instance...') + try: + self._connectToSlaprunner(resource='runInstanceProfile') + except (NotHttpOkException, urllib2.HTTPError): + # The nginx frontend might timeout before someftware release is finished. + pass + while self._connectToSlaprunner(resource='slapgridResult', data='position=0&log=').find('"instance": true') is not -1: + self.logger.info('Buildout is still running. Sleeping...') + time.sleep(15) + self.logger.info('Instance has been deployed.') + + self.data = self._retrieveInstanceLogFile() + + + def checkDataOnCloneInstance(self): + """ + Check that: + * backend_url is different + * Software Release profile is the same, + * Software Release is built and is the same, (?) + * Instance is deployed and is the same. + """ + # XXX: does the promise wait for the software to be built and the instance to be ready? + old_slaprunner_backend_url = self.slaprunner_backend_url + self.slaprunner_backend_url = self._returnNewInstanceParameter( + parameter_key='backend_url', + old_parameter_value=old_slaprunner_backend_url + ) + self._login() + new_data = self._retrieveInstanceLogFile() + + if new_data == self.data: + self.logger.info('Data are the same: success.') + return True + else: + self.logger.info('Data are different: failure.') + + +def runTestSuite(*args, **kwargs): + """ + Run Slaprunner Resiliency Test. + """ + return SlaprunnerTestSuite(*args, **kwargs).runTestSuite() + -- 2.30.9