/silversupport/service/mysql.py
Python | 172 lines | 160 code | 10 blank | 2 comment | 11 complexity | 36ff1629cc9253f06823fa04ede6b260 MD5 | raw file
1"""MySQL support""" 2 3import os 4import sys 5from silversupport.shell import run 6from silversupport.abstractservice import AbstractService 7 8 9class Service(AbstractService): 10 11 packages = [ 12 'mysql-server-5.1', 13 'mysql-client-5.1', 14 'python-mysqldb', 15 ] 16 17 platform_packages = dict( 18 python=['python-mysqldb'], 19 php=['php5-mysql'], 20 ) 21 22 def install(self): 23 if not os.path.exists('/usr/bin/mysqld_multi'): 24 self.install_packages() 25 run(['/usr/bin/mysql', '-u', 'root', 26 '-e', 'CREATE USER wwwmgr']) 27 if self.app_config.platform == 'php': 28 # We need to restart Apache after installing php5-mysql 29 run(['/etc/init.d/apache2', 'restart']) 30 31 app_name = self.app_config.app_name 32 stdout, stderr, returncode = run( 33 ['/usr/bin/mysql', '-u', 'root', 34 '-e', 'SHOW DATABASES', '--batch', '-s'], 35 capture_stdout=True) 36 databases = [l.strip() for l in stdout.splitlines() if l.strip()] 37 if app_name in databases: 38 self.output('Database %s already exists' % app_name) 39 else: 40 self.output('Database %s does not exist; creating.' % app_name) 41 run(['/usr/bin/mysql', '-u', 'root', 42 '-e', 'CREATE DATABASE %s' % app_name]) 43 run(['/usr/bin/mysql', '-u', 'root', 44 '-e', "GRANT ALL ON %s.* TO 'wwwmgr'@'localhost'" % app_name]) 45 46 def env_setup(self): 47 environ = {} 48 app_name = self.app_config.app_name 49 platform = self.app_config.platform 50 if not self.devel: 51 environ['CONFIG_MYSQL_DBNAME'] = app_name 52 environ['CONFIG_MYSQL_USER'] = 'wwwmgr' 53 environ['CONFIG_MYSQL_PASSWORD'] = '' 54 if platform == 'php': 55 environ['CONFIG_MYSQL_HOST'] = 'localhost' 56 else: 57 environ['CONFIG_MYSQL_HOST'] = '' 58 environ['CONFIG_MYSQL_PORT'] = '' 59 if platform == 'python': 60 environ['CONFIG_MYSQL_SQLALCHEMY'] = 'mysql://wwwmgr@/%s' % app_name 61 else: 62 environ['CONFIG_MYSQL_DBNAME'] = app_name 63 environ['CONFIG_MYSQL_USER'] = 'root' 64 environ['CONFIG_MYSQL_PASSWORD'] = '' 65 environ['CONFIG_MYSQL_HOST'] = '' 66 environ['CONFIG_MYSQL_PORT'] = '' 67 for name, value in self.devel_config.items(): 68 if name.startswith('mysql.'): 69 name = name[len('mysql.'):] 70 environ['CONFIG_MYSQL_%s' % name.upper()] = value 71 sa = 'mysql://' 72 if environ.get('CONFIG_MYSQL_USER'): 73 sa += environ['CONFIG_MYSQL_USER'] 74 if environ.get('CONFIG_MYSQL_PASSWORD'): 75 sa += ':' + environ['CONFIG_MYSQL_PASSWORD'] 76 sa += '@' 77 if environ.get('CONFIG_MYSQL_HOST'): 78 ## FIXME: should this check for 'localhost', which SA actually doesn't like? 79 sa += environ['CONFIG_MYSQL_HOST'] 80 if environ.get('CONFIG_MYSQL_PORT'): 81 sa += ':' + environ['CONFIG_MYSQL_PORT'] 82 sa += '/' + environ['CONFIG_MYSQL_DBNAME'] 83 environ['CONFIG_MYSQL_SQLALCHEMY'] = sa 84 return environ 85 86 def backup(self, output_dir): 87 outfile = os.path.join(output_dir, 'mysql.dump') 88 run(["mysqldump"] + self.mysql_options() + ['--result-file', outfile]) 89 fp = open(os.path.join(output_dir, 'README.txt'), 'w') 90 fp.write(self.BACKUP_README) 91 fp.close() 92 93 BACKUP_README = """\ 94 The file mysql.dump was created with mysqldump; you can pip it into 95 mysql to restore. 96 """ 97 98 def restore(self, input_dir): 99 input_file = os.path.join(input_dir, 'mysql.dump') 100 fp = open(input_file) 101 content = fp.read() 102 fp.close() 103 run(['mysql'] + self.mysql_options() + ['--silent'], 104 stdin=content) 105 106 def mysql_options(self): 107 environ = self.env 108 options = [] 109 options.append('--user=%s' % environ['CONFIG_MYSQL_USER']) 110 for option, key in [('password', 'PASSWORD'), 111 ('user', 'USER'), 112 ('host', 'HOST'), 113 ('port', 'PORT')]: 114 if environ.get('CONFIG_MYSQL_%s' % key): 115 options.append('--%s=%s' % (option, environ['CONFIG_MYSQL_%s' % key])) 116 options.append(environ['CONFIG_MYSQL_DBNAME']) 117 return options 118 119 def clear(self): 120 run(["mysql"] + self.mysql_options(), 121 stdin='DROP DATABASE %s' % self.env['CONFIG_MYSQL_DBNAME']) 122 self.install() 123 self.output('Cleared database %s' % self.env['CONFIG_MYSQL_DBNAME']) 124 125 def check_setup(self): 126 try: 127 import MySQLdb 128 except ImportError: 129 return 'Cannot import MySQLdb (cannot check database)' 130 kw = {} 131 for envname, kwname in [ 132 ('CONFIG_MYSQL_HOST', 'host'), 133 ('CONFIG_MYSQL_USER', 'user'), 134 ('CONFIG_MYSQL_PASSWORD', 'passwd'), 135 ('CONFIG_MYSQL_DBNAME', 'db'), 136 ('CONFIG_MYSQL_PORT', 'port'), 137 ]: 138 if self.env.get(envname): 139 kw[kwname] = self.env[envname] 140 try: 141 MySQLdb.connect(**kw) 142 except MySQLdb.OperationalError, e: 143 exc_info = sys.exc_info() 144 try: 145 code = int(e.args[0]) 146 except: 147 raise exc_info[0], exc_info[1], exc_info[2] 148 if code == 1049: 149 dbname = self.env['CONFIG_MYSQL_DBNAME'] 150 result = ['No database by the name %s exists' % dbname] 151 result.append( 152 'To fix this run:') 153 result.append( 154 ' echo "CREATE DATABASE %s; GRANT ALL ON %s.* TO %s@localhost" | mysql -u root -p ' 155 % (dbname, dbname, self.env['CONFIG_MYSQL_USER'])) 156 return '\n'.join(result) 157 raise 158 159 160def mysql_connect(**kw): 161 """Connect to the configured database, returning a DBAPI/MySQLdb 162 connection object.""" 163 import MySQLdb 164 for environ_name, kw_name in [('CONFIG_MYSQL_HOST', 'host'), 165 ('CONFIG_MYSQL_USER', 'user'), 166 ('CONFIG_MYSQL_DBNAME', 'db'), 167 ('CONFIG_MYSQL_PASSWORD', 'passwd'), 168 ]: 169 if os.environ.get(environ_name): 170 kw.setdefault(kw_name, os.environ[environ_name]) 171 db = MySQLdb.connect(**kw) 172 return db