8 from wizard import plugin, shell
10 # We're going to use sqlalchemy.engine.url.URL as our database
11 # info intermediate object
14 """Convenience method for connecting to a MySQL database."""
15 engine = sqlalchemy.create_engine(url)
16 meta = sqlalchemy.MetaData()
23 If the URL has a database name but no other values, it will
24 use the global configuration, and then try the database name.
26 This function implements a plugin interface named
27 :ref:`wizard.sql.auth`.
34 # omitted port and query
35 if any((url.host, url.username, url.password)):
36 # don't try for defaults if a few of these were set
38 for entry in pkg_resources.iter_entry_points("wizard.sql.auth"):
40 r = func(copy.copy(url))
43 env_dsn = os.getenv("WIZARD_DSN")
46 url = sqlalchemy.engine.url.make_url(env_dsn)
47 url.database = old_url.database
50 def backup(outdir, deployment):
52 Generic database backup function.
54 # XXX: Change this once deployments support multiple dbs
55 if deployment.application.database == "mysql":
56 return backup_mysql(outdir, deployment)
58 raise NotImplementedError
60 def backup_mysql(outdir, deployment):
62 Database backups for MySQL using the :command:`mysqldump` utility.
64 outfile = os.path.join(outdir, "db.sql")
66 shell.call("mysqldump", "--compress", "-r", outfile, *get_mysql_args(deployment.dsn))
67 shell.call("gzip", "--best", outfile)
68 except shell.CallError as e:
69 raise BackupDatabaseError(e.stderr)
71 def restore(backup_dir, deployment):
73 Generic database restoration function.
76 if deployment.application.database == "mysql":
77 return restore_mysql(backup_dir, deployment)
79 raise NotImplementedError
81 def restore_mysql(backup_dir, deployment):
83 Database restoration for MySQL by piping SQL commands into :command:`mysql`.
85 if not os.path.exists(backup_dir):
86 raise RestoreDatabaseError("Backup %s doesn't exist" % backup_dir.rpartition("/")[2])
87 sql = open(os.path.join(backup_dir, "db.sql"), 'w+')
88 shell.call("gunzip", "-c", os.path.join(backup_dir, "db.sql.gz"), stdout=sql)
90 shell.call("mysql", *get_mysql_args(deployment.dsn), stdin=sql)
95 Generic drop database function. Attempts to run ``DROP
96 DATABASE`` on the database if no plugins succeed.
98 This function implements the plugin interface named
99 :ref:`wizard.sql.drop`.
101 r = plugin.hook("wizard.sql.drop", [url])
104 engine = sqlalchemy.create_engine(url)
105 engine.execute("DROP DATABASE `%s`" % url.database)
107 def get_mysql_args(dsn):
109 Extracts arguments that would be passed to the command line mysql utility
114 args += ["-h", dsn.host]
116 args += ["-u", dsn.username]
118 args += ["-p" + dsn.password]
119 args += [dsn.database]
122 class Error(wizard.Error):
123 """Generic error class for this module."""
126 class BackupDatabaseError(Error):
127 """Backup script failed."""
128 #: String details of failure
130 def __init__(self, details):
131 self.details = details
135 ERROR: Backing up the database failed, details:
139 class RestoreDatabaseError(Error):
140 """Restore script failed."""
141 #: String details of failure
143 def __init__(self, details):
144 self.details = details
148 ERROR: Restoring the database failed, details:
152 class RemoveDatabaseError(Error):
153 """Removing the database failed."""
154 #: String details of failure
156 def __init__(self, details):
157 self.details = details
161 ERROR: Removing the database failed, details: