El siguiente es un corredor de suite de prueba django para crear una base de datos usando Webfaction XML-RPC API. Tenga en cuenta que la configuración de la base de datos con la API puede demorar hasta un minuto y que la secuencia de comandos puede parecer bloqueada momentáneamente, solo espere un momento.
NOTA: existe un riesgo de seguridad de tener una contraseña para el panel de control en el servidor webfaction, porque alguien que infringe su servidor web SSH podría hacerse cargo de su cuenta Webfaction. Si eso es una preocupación, configure USE_SESSKEY en True y use la secuencia de comandos fabric debajo de esta secuencia de comandos para pasar una identificación de sesión al servidor. La clave de sesión expires in 1 hour de la última llamada API.
test_runner.py del archivo: en el servidor, debe configurar la prueba ./manage.py utilizar WebfactionTestRunner
"""
This test runner uses Webfaction XML-RPC API to create and destroy database
"""
# you can put your control panel username and password here.
# NOTE: there is a security risk of having control panel password in
# the webfaction server, because someone breaching into your web server
# SSH could take over your Webfaction account. If that is a concern,
# set USE_SESSKEY to True and use the fabric script below this script to
# generate a session.
USE_SESSKEY = True
# CP_USERNAME = 'webfactionusername' # required if and only if USE_SESSKEY is False
# CP_PASSWORD = 'webfactionpassword' # required if and only if USE_SESSKEY is False
import sys
import os
from django.test.simple import DjangoTestSuiteRunner
from django import db
from webfaction import Webfaction
def get_sesskey():
f = os.path.expanduser("~/sesskey")
sesskey = open(f).read().strip()
os.remove(f)
return sesskey
if USE_SESSKEY:
wf = Webfaction(get_sesskey())
else:
wf = Webfaction()
wf.login(CP_USERNAME, CP_PASSWORD)
def get_db_user_and_type(connection):
db_types = {
'django.db.backends.postgresql_psycopg2': 'postgresql',
'django.db.backends.mysql': 'mysql',
}
return (
connection.settings_dict['USER'],
db_types[connection.settings_dict['ENGINE']],
)
def _create_test_db(self, verbosity, autoclobber):
"""
Internal implementation - creates the test db tables.
"""
test_database_name = self._get_test_db_name()
db_user, db_type = get_db_user_and_type(self.connection)
try:
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error creating the test database: %s\n" % e)
if not autoclobber:
confirm = raw_input(
"Type 'yes' if you would like to try deleting the test "
"database '%s', or 'no' to cancel: " % test_database_name)
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
print("Destroying old test database '%s'..."
% self.connection.alias)
wf.delete_db(test_database_name, db_type)
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error recreating the test database: %s\n" % e)
sys.exit(2)
else:
print("Tests cancelled.")
sys.exit(1)
db.close_connection()
return test_database_name
def _destroy_test_db(self, test_database_name, verbosity):
"""
Internal implementation - remove the test db tables.
"""
db_user, db_type = get_db_user_and_type(self.connection)
wf.delete_db(test_database_name, db_type)
self.connection.close()
class WebfactionTestRunner(DjangoTestSuiteRunner):
def __init__(self, *args, **kwargs):
# Monkey patch BaseDatabaseCreation with our own version
from django.db.backends.creation import BaseDatabaseCreation
BaseDatabaseCreation._create_test_db = _create_test_db
BaseDatabaseCreation._destroy_test_db = _destroy_test_db
return super(WebfactionTestRunner, self).__init__(*args, **kwargs)
webfaction.py Archivo: esta es una envoltura delgada de API Webfaction, se necesita se pueden importar por tanto test_runner.py (en el servidor remoto) y el fabfile.py (en la máquina local)
import xmlrpclib
class Webfaction(object):
def __init__(self, sesskey=None):
self.connection = xmlrpclib.ServerProxy("https://api.webfaction.com/")
self.sesskey = sesskey
def login(self, username, password):
self.sesskey, _ = self.connection.login(username, password)
def create_db(self, db_user, db_name, db_type):
""" Create a database owned by db_user """
self.connection.create_db(self.sesskey, db_name, db_type, 'unused')
# deletes the default user created by Webfaction API
self.connection.make_user_owner_of_db(self.sesskey, db_user, db_name, db_type)
self.connection.delete_db_user(self.sesskey, db_name, db_type)
def delete_db(self, db_name, db_type):
try:
self.connection.delete_db_user(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
try:
self.connection.delete_db(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
fabfile.py archivo: Una secuencia de comandos muestra de tela para generar la clave de sesión, es necesario sólo si USE_SESSKEY = Verdadero
from fabric.api import *
from fabric.operations import run, put
from webfaction import Webfaction
import io
env.hosts = ["[email protected]"]
env.password = "webfactionpassword"
def run_test():
wf = Webfaction()
wf.login(env.hosts[0].split('@')[0], env.password)
sesskey_file = '~/sesskey'
sesskey = wf.sesskey
try:
put(io.StringIO(unicode(sesskey)), sesskey_file, mode='0600')
# put your test code here
# e.g. run('DJANGO_SETTINGS_MODULE=settings /path/to/virtualenv/python /path/to/manage.py test --testrunner=test_runner.WebfactionTestRunner')
raise Exception('write your test here')
finally:
run("rm -f %s" % sesskey_file)
Su archivo de configuración tiene un nombre de base de datos y un nombre de usuario y contraseña para esa base de datos. ¿Son correctos el nombre de usuario y la contraseña? ¿Realmente puedes usarlos para conectarte? ¿Puedes usar ese nombre de usuario y contraseña para hacer una CREATE DATABASE en Postgres? –
@S.Lott: Sí, el nombre de usuario y la contraseña son correctos. Puedo usarlos para conectar y recuperar filas. 'syncdb' funciona bien; puede crear tablas también Pero no, estoy bastante seguro de que el usuario * no puede * crear bases de datos en postgres: ese es el problema, y es por eso que quiero crearlo manualmente. – mpen
Acabo de encontrar una solución en los foros de webfaction: http://forum.webfaction.com/viewtopic.php?pid=16919 pero dejaré esta pregunta abierta por un momento para ver si alguien puede sugerir una solución menos hacky para Django 1.2. – mpen