installer.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import subprocess
  2. import os
  3. import os.path
  4. import time
  5. import traceback
  6. import sys
  7. import glob
  8. import logging
  9. import setup_util
  10. from benchmark.utils import gather_tests
  11. class Installer:
  12. ############################################################
  13. # install_software
  14. ############################################################
  15. def install_software(self):
  16. if self.benchmarker.install == 'all' or self.benchmarker.install == 'server':
  17. self.__install_server_software()
  18. if self.benchmarker.install == 'all' or self.benchmarker.install == 'database':
  19. self.__install_database_software()
  20. if self.benchmarker.install == 'all' or self.benchmarker.install == 'client':
  21. self.__install_client_software()
  22. ############################################################
  23. # End install_software
  24. ############################################################
  25. ############################################################
  26. # __install_server_software
  27. ############################################################
  28. def __install_server_software(self):
  29. print("\nINSTALL: Installing server software (strategy=%s)\n"%self.strategy)
  30. # Install global prerequisites
  31. bash_functions_path='$FWROOT/toolset/setup/linux/bash_functions.sh'
  32. prereq_path='$FWROOT/toolset/setup/linux/prerequisites.sh'
  33. self.__run_command(". %s && . %s" % (bash_functions_path, prereq_path))
  34. tests = gather_tests(include=self.benchmarker.test,
  35. exclude=self.benchmarker.exclude,
  36. benchmarker=self.benchmarker)
  37. dirs = [t.directory for t in tests]
  38. # Locate all installation files
  39. install_files = glob.glob("%s/*/install.sh" % self.fwroot)
  40. install_files.extend(glob.glob("%s/frameworks/*/*/install.sh" % self.fwroot))
  41. # Run install for selected tests
  42. for test_install_file in install_files:
  43. test_dir = os.path.dirname(test_install_file)
  44. test_rel_dir = os.path.relpath(test_dir, self.fwroot)
  45. logging.debug("Considering install of %s (%s, %s)", test_install_file, test_rel_dir, test_dir)
  46. if test_dir not in dirs:
  47. continue
  48. logging.info("Running installation for directory %s (cwd=%s)", test_dir, test_dir)
  49. # Collect the tests in this directory
  50. # local_tests = [t for t in tests if t.directory == test_dir]
  51. # Find installation directory
  52. # e.g. FWROOT/installs or FWROOT/installs/pertest/<test-name>
  53. test_install_dir="%s/%s" % (self.fwroot, self.install_dir)
  54. if self.strategy is 'pertest':
  55. test_install_dir="%s/pertest/%s" % (test_install_dir, test_dir)
  56. if not os.path.exists(test_install_dir):
  57. os.makedirs(test_install_dir)
  58. # Move into the proper working directory
  59. previousDir = os.getcwd()
  60. os.chdir(test_dir)
  61. # Load profile for this installation
  62. profile="%s/bash_profile.sh" % test_dir
  63. if not os.path.exists(profile):
  64. logging.warning("Directory %s does not have a bash_profile"%test_dir)
  65. profile="$FWROOT/config/benchmark_profile"
  66. else:
  67. logging.info("Loading environment from %s (cwd=%s)", profile, test_dir)
  68. setup_util.replace_environ(config=profile,
  69. command='export TROOT=%s && export IROOT=%s' %
  70. (test_dir, test_install_dir))
  71. # Run test installation script
  72. # FWROOT - Path of the FwBm root
  73. # IROOT - Path of this test's install directory
  74. # TROOT - Path to this test's directory
  75. self.__run_command('''
  76. export TROOT=%s &&
  77. export IROOT=%s &&
  78. source %s &&
  79. source %s''' %
  80. (test_dir, test_install_dir,
  81. bash_functions_path, test_install_file),
  82. cwd=test_install_dir)
  83. # Move back to previous directory
  84. os.chdir(previousDir)
  85. self.__run_command("sudo apt-get -y autoremove");
  86. print("\nINSTALL: Finished installing server software\n")
  87. ############################################################
  88. # End __install_server_software
  89. ############################################################
  90. ############################################################
  91. # __install_error
  92. ############################################################
  93. def __install_error(self, message):
  94. print("\nINSTALL ERROR: %s\n" % message)
  95. if self.benchmarker.install_error_action == 'abort':
  96. sys.exit("Installation aborted.")
  97. ############################################################
  98. # End __install_error
  99. ############################################################
  100. ############################################################
  101. # __install_database_software
  102. ############################################################
  103. def __install_database_software(self):
  104. print("\nINSTALL: Installing database software\n")
  105. self.__run_command("cd .. && " + self.benchmarker.database_sftp_string(batch_file="../config/database_sftp_batch"), True)
  106. remote_script = """
  107. ##############################
  108. # Prerequisites
  109. ##############################
  110. sudo apt-get -y update
  111. sudo apt-get -y install build-essential git libev-dev libpq-dev libreadline6-dev postgresql redis-server
  112. sudo sh -c "echo '* - nofile 65535' >> /etc/security/limits.conf"
  113. # Create a user-owned directory for our databases
  114. sudo mkdir -p /ssd
  115. sudo mkdir -p /ssd/log
  116. sudo chown -R $USER:$USER /ssd
  117. # Additional user account (only use if required)
  118. sudo useradd benchmarkdbuser -p benchmarkdbpass
  119. ##############################
  120. # MySQL
  121. ##############################
  122. echo "Setting up MySQL database"
  123. sudo sh -c "echo mysql-server mysql-server/root_password_again select secret | debconf-set-selections"
  124. sudo sh -c "echo mysql-server mysql-server/root_password select secret | debconf-set-selections"
  125. sudo apt-get -y install mysql-server
  126. sudo stop mysql
  127. # disable checking of disk size
  128. sudo mv mysql /etc/init.d/mysql
  129. sudo chmod +x /etc/init.d/mysql
  130. sudo mv mysql.conf /etc/init/mysql.conf
  131. # use the my.cnf file to overwrite /etc/mysql/my.cnf
  132. sudo mv /etc/mysql/my.cnf /etc/mysql/my.cnf.orig
  133. sudo mv my.cnf /etc/mysql/my.cnf
  134. sudo cp -R -p /var/lib/mysql /ssd/
  135. sudo cp -R -p /var/log/mysql /ssd/log
  136. sudo cp usr.sbin.mysqld /etc/apparmor.d/
  137. sudo /etc/init.d/apparmor reload
  138. sudo start mysql
  139. # Insert data
  140. mysql -uroot -psecret < create.sql
  141. rm create.sql
  142. ##############################
  143. # Postgres
  144. ##############################
  145. echo "Setting up Postgres database"
  146. sudo -u postgres psql template1 < create-postgres-database.sql
  147. sudo -u benchmarkdbuser psql hello_world < create-postgres.sql
  148. rm create-postgres-database.sql create-postgres.sql
  149. sudo -u postgres -H /etc/init.d/postgresql stop
  150. # NOTE: This will cause errors on Ubuntu 12.04, as apt installs
  151. # an older version (9.1 instead of 9.3)
  152. sudo mv postgresql.conf /etc/postgresql/9.3/main/postgresql.conf
  153. sudo mv pg_hba.conf /etc/postgresql/9.3/main/pg_hba.conf
  154. sudo cp -R -p /var/lib/postgresql/9.3/main /ssd/postgresql
  155. sudo -u postgres -H /etc/init.d/postgresql start
  156. sudo mv 60-postgresql-shm.conf /etc/sysctl.d/60-postgresql-shm.conf
  157. ##############################
  158. # MongoDB
  159. ##############################
  160. echo "Setting up MongoDB database"
  161. sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
  162. echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
  163. sudo apt-get -y update
  164. sudo apt-get -y remove mongodb-clients
  165. sudo apt-get -y install mongodb-org
  166. sudo service mongod stop
  167. sudo mv /etc/mongodb.conf /etc/mongodb.conf.orig
  168. sudo mv mongodb.conf /etc/mongodb.conf
  169. sudo mv mongodb.conf /etc/mongod.conf
  170. sudo cp -R -p /var/lib/mongodb /ssd/
  171. sudo cp -R -p /var/log/mongodb /ssd/log/
  172. sudo service mongod start
  173. until nc -z localhost 27017 ; do echo Waiting for MongoDB; sleep 1; done
  174. mongo < create.js
  175. rm create.js
  176. ##############################
  177. # Apache Cassandra
  178. ##############################
  179. echo "Setting up Apache Cassandra database"
  180. sudo apt-get install -qqy openjdk-7-jdk
  181. export CASS_V=2.0.7
  182. wget -nv http://archive.apache.org/dist/cassandra/$CASS_V/apache-cassandra-$CASS_V-bin.tar.gz
  183. tar xzf apache-cassandra-$CASS_V-bin.tar.gz
  184. rm -rf /ssd/cassandra /ssd/log/cassandra
  185. mkdir -p /ssd/cassandra /ssd/log/cassandra
  186. sed -i "s/^.*seeds:.*/ - seeds: \"{database_host}\"/" cassandra/cassandra.yaml
  187. sed -i "s/^listen_address:.*/listen_address: {database_host}/" cassandra/cassandra.yaml
  188. sed -i "s/^rpc_address:.*/rpc_address: {database_host}/" cassandra/cassandra.yaml
  189. mv cassandra/cassandra.yaml apache-cassandra-$CASS_V/conf
  190. mv cassandra/log4j-server.properties apache-cassandra-$CASS_V/conf
  191. nohup apache-cassandra-$CASS_V/bin/cassandra -p c.pid > cassandra.log
  192. until nc -z {database_host} 9160 ; do echo Waiting for Cassandra; sleep 1; done
  193. cat cassandra/cleanup-keyspace.cql | apache-cassandra-$CASS_V/bin/cqlsh {database_host}
  194. python cassandra/db-data-gen.py > cassandra/tfb-data.cql
  195. apache-cassandra-$CASS_V/bin/cqlsh -f cassandra/create-keyspace.cql {database_host}
  196. apache-cassandra-$CASS_V/bin/cqlsh -f cassandra/tfb-data.cql {database_host}
  197. rm -rf apache-cassandra-*-bin.tar.gz cassandra
  198. ##############################
  199. # Redis
  200. ##############################
  201. echo "Setting up Redis database"
  202. sudo service redis-server stop
  203. # NOTE: This will cause errors on Ubuntu 12.04, as apt installs
  204. # an older version of redis
  205. sudo mv redis.conf /etc/redis/redis.conf
  206. sudo service redis-server start
  207. bash create-redis.sh
  208. rm create-redis.sh
  209. """.format(database_host=self.benchmarker.database_host)
  210. print("\nINSTALL: %s" % self.benchmarker.database_ssh_string)
  211. p = subprocess.Popen(self.benchmarker.database_ssh_string.split(" ") + ["bash"], stdin=subprocess.PIPE)
  212. p.communicate(remote_script)
  213. returncode = p.returncode
  214. if returncode != 0:
  215. self.__install_error("status code %s running subprocess '%s'." % (returncode, self.benchmarker.database_ssh_string))
  216. print("\nINSTALL: Finished installing database software\n")
  217. ############################################################
  218. # End __install_database_software
  219. ############################################################
  220. ############################################################
  221. # __install_client_software
  222. ############################################################
  223. def __install_client_software(self):
  224. print("\nINSTALL: Installing client software\n")
  225. remote_script = """
  226. ##############################
  227. # Prerequisites
  228. ##############################
  229. sudo apt-get -y update
  230. sudo apt-get -y install build-essential git libev-dev libpq-dev libreadline6-dev
  231. sudo sh -c "echo '* - nofile 65535' >> /etc/security/limits.conf"
  232. ##############################
  233. # wrk
  234. ##############################
  235. git clone https://github.com/wg/wrk.git
  236. cd wrk
  237. git checkout 205a1960c8b8de5f500bb143863ae293456b7add
  238. make
  239. sudo cp wrk /usr/local/bin
  240. cd ~
  241. #############################
  242. # pipeline.lua
  243. #############################
  244. cat << EOF | tee pipeline.lua
  245. init = function(args)
  246. wrk.init(args)
  247. local r = {}
  248. local depth = tonumber(args[1]) or 1
  249. for i=1,depth do
  250. r[i] = wrk.format()
  251. end
  252. req = table.concat(r)
  253. end
  254. request = function()
  255. return req
  256. end
  257. EOF
  258. """
  259. print("\nINSTALL: %s" % self.benchmarker.client_ssh_string)
  260. p = subprocess.Popen(self.benchmarker.client_ssh_string.split(" "), stdin=subprocess.PIPE)
  261. p.communicate(remote_script)
  262. returncode = p.returncode
  263. if returncode != 0:
  264. self.__install_error("status code %s running subprocess '%s'." % (returncode, self.benchmarker.client_ssh_string))
  265. print("\nINSTALL: Finished installing client software\n")
  266. ############################################################
  267. # End __install_client_software
  268. ############################################################
  269. ############################################################
  270. # __path_exists
  271. ############################################################
  272. def __path_exists(self, path, cwd=None):
  273. full_path = os.path.join(cwd or self.install_dir, path)
  274. if os.path.exists(full_path):
  275. print("\nEXISTS: %s " % full_path)
  276. return True
  277. print("\nNOT_EXISTS: %s" % full_path)
  278. return False
  279. ############################################################
  280. # End __path_exists
  281. ############################################################
  282. ############################################################
  283. # __run_command
  284. ############################################################
  285. def __run_command(self, command, send_yes=False, cwd=None, retry=False):
  286. if cwd is None:
  287. cwd = self.install_dir
  288. if retry:
  289. max_attempts = 5
  290. else:
  291. max_attempts = 1
  292. attempt = 1
  293. delay = 0
  294. if send_yes:
  295. command = "yes yes | " + command
  296. rel_cwd = setup_util.path_relative_to_root(cwd)
  297. print("INSTALL: %s (cwd=$FWROOT%s)" % (command, rel_cwd))
  298. while attempt <= max_attempts:
  299. error_message = ""
  300. try:
  301. # Execute command.
  302. subprocess.check_call(command, shell=True, cwd=cwd, executable='/bin/bash')
  303. break # Exit loop if successful.
  304. except:
  305. exceptionType, exceptionValue, exceptionTraceBack = sys.exc_info()
  306. error_message = "".join(traceback.format_exception_only(exceptionType, exceptionValue))
  307. # Exit if there are no more attempts left.
  308. attempt += 1
  309. if attempt > max_attempts:
  310. break
  311. # Delay before next attempt.
  312. if delay == 0:
  313. delay = 5
  314. else:
  315. delay = delay * 2
  316. print("Attempt %s/%s starting in %s seconds." % (attempt, max_attempts, delay))
  317. time.sleep(delay)
  318. if error_message:
  319. self.__install_error(error_message)
  320. ############################################################
  321. # End __run_command
  322. ############################################################
  323. ############################################################
  324. # __bash_from_string
  325. # Runs bash -c "command" in install_dir.
  326. ############################################################
  327. def __bash_from_string(self, command):
  328. self.__run_command('bash -c "%s"' % command)
  329. ############################################################
  330. # End __bash_from_string
  331. ############################################################
  332. ############################################################
  333. # __download
  334. # Downloads a file from a URI.
  335. ############################################################
  336. def __download(self, uri, filename=""):
  337. if filename:
  338. if os.path.exists(filename):
  339. return
  340. filename_option = "-O %s " % filename
  341. else:
  342. filename_option = ""
  343. command = "wget -nv --no-check-certificate --trust-server-names %s%s" % (filename_option, uri)
  344. self.__run_command(command, retry=True)
  345. ############################################################
  346. # End __download
  347. ############################################################
  348. ############################################################
  349. # __init__(benchmarker)
  350. ############################################################
  351. def __init__(self, benchmarker, install_strategy):
  352. self.benchmarker = benchmarker
  353. self.install_dir = "installs"
  354. self.fwroot = benchmarker.fwroot
  355. self.strategy = install_strategy
  356. # setup logging
  357. logging.basicConfig(stream=sys.stderr, level=logging.INFO)
  358. try:
  359. os.mkdir(self.install_dir)
  360. except OSError:
  361. pass
  362. ############################################################
  363. # End __init__
  364. ############################################################
  365. # vim: sw=2