PageRenderTime 91ms CodeModel.GetById 20ms app.highlight 30ms RepoModel.GetById 20ms app.codeStats 0ms

/silversupport/service/mysql.py

https://bitbucket.org/ianb/silverlining/
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