Remove postfixadmin migration script.

This commit is contained in:
Antoine Nguyen
2015-04-15 10:58:52 +02:00
parent d252f03126
commit d4f10438a4
7 changed files with 1 additions and 544 deletions
+1 -53
View File
@@ -6,56 +6,4 @@ Migrating from other software
PostfixAdmin
************
Modoboa provides a simple script to migrate an
existing `PostfixAdmin (version 2.3.3+)
<http://postfixadmin.sourceforge.net/>`_ database to a Modoboa one.
.. note::
This script is only suitable for a new installation.
First, you must follow the :ref:`installation` step to create a fresh
Modoboa database.
Once done, edit the :file:`settings.py` file. First, add a new database
connection named ``pfxadmin`` into the ``DATABASES`` variable
corresponding to your PostfixAdmin setup::
DATABASES = {
"default" : {
# default connection definition
},
"pfxadmin" : {
"ENGINE" : "<engine>",
"NAME" : "<database name>",
"USER" : "<database user>",
"PASSWORD" : "<user password>",
}
}
This connection should correspond to the one defined in PostfixAdmin's
configuration file.
Then, uncomment the line containing
``'modoboa.tools.pfxadmin_migrate'`` inside the ``MODOBOA_APPS``
variable and save your changes.
You are now ready to start the migration so run the following commands::
$ cd <modoboa_site>
$ python manage.py migrate_from_postfixadmin -s <password scheme>
``<password scheme>`` must be replaced by the scheme used within
postfixadmin (``crypt`` most of the time).
Depending on how many domains/mailboxes your existing setup contains,
the migration can be long. Just wait for the script's ending.
The procedure is over, edit the :file:`settings.py` file and:
* remove the ``pfxadmin`` database connection from the ``DATABASES``
variable
* remove the ``'modoboa.tools.pfxadmin_migrate',`` from the
``MODOBOA_APPS`` variable
You should be able to connect to Modoboa using the same credentials
you were using to connect to PostfixAdmin.
`Official repository <https://github.com/modoboa/modoboa-pfxadmin-migrate>`_.
View File
@@ -1,290 +0,0 @@
# coding: utf-8
"""Automatic postfixadmin to Modoboa migration
===========================================
This script provides an easy way to migrate an existing postfixadmin
database to a Modoboa one.
As the two products do not share the same schema, some information
will be lost on the new database. Here is the list:
* Description, transport and backup MX for domains
* Logs
* Fetchmail table
Domain administrators that manage more than one domain will not be
completly restored. They will only be administrator of the domain that
corresponds to their username.
Vacation messages will not be migrated by this script. Users will have
to define new messages by using Modoboa's autoreply plugin. (if
activated)
One last point about passwords. PostfixAdmin uses different hash
algorithms to store passwords so this script does not modify
them. They are copied "as is" in the new database. In order to use
them, use the ``--passwords-scheme`` to tell Modoboa which scheme was
used by PostfixAdmin.
.. note::
Actually, it appears that the ``crypt`` scheme is compatible with
PostfixAdmin ``md5crypt`` algorithm...
"""
from optparse import make_option
import re
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand
from django.db import transaction
import modoboa.core.models as core_models
import modoboa.extensions.admin.models as admin_models
from modoboa.lib.email_utils import split_mailbox
from modoboa.extensions.admin import grant_access_to_all_objects
from modoboa.tools.pfxadmin_migrate import models as pf_models
def set_account_password(account, password, scheme):
"""Correclty format the password before storing it.
It seems postfixadmin sometimes prepend the scheme... but not
always :p
"""
if re.search(r"\{[\w-]+\}", password):
account.password = password
else:
account.password = "{%s}%s" % (scheme.upper(), password)
class Command(BaseCommand):
"""Migration from postfixadmin."""
help = "This command eases the migration from a postfixadmin database."
option_list = BaseCommand.option_list + (
make_option(
"-f", "--from", dest="_from", default="pfxadmin",
help="Name of postfixadmin db connection declared in settings.py"
"(default is pfxadmin)"
),
make_option(
"-t", "--to", dest="_to", default="default",
help="Name of the Modoboa db connection declared in settings.py"
" (default is default)"
),
make_option(
"-s", "--passwords-scheme", default="crypt",
help="Scheme used to crypt user passwords"
)
)
def _migrate_dates(self, oldobj):
"""Creates a new ObjectDates instance.
Due to Django limitations, we only retrieve the creation date. The
modification date will be set to 'now' because the corresponding
field in Modoboa's schema has the 'auto_now' attribute to True.
(see https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField).
:param oldobj: the PostfixAdmin record which is beeing migrated.
"""
dates = admin_models.base.ObjectDates()
dates.save()
dates.creation = oldobj.created
dates.save()
return dates
def _migrate_domain_aliases(self, domain, options, creator):
"""Migrate aliases of a single domain."""
print "\tMigrating domain aliases"
old_domain_aliases = pf_models.AliasDomain.objects.using(
options["_from"]
).filter(target_domain=domain.name)
for old_da in old_domain_aliases:
try:
target_domain = admin_models.Domain.objects \
.using(options["_to"]).get(name=old_da.target_domain)
new_da = admin_models.DomainAlias()
new_da.name = old_da.alias_domain
new_da.target = target_domain
new_da.enabled = old_da.active
new_da.dates = self._migrate_dates(old_da)
new_da.save(using=options["_to"])
new_da.post_create(creator)
except core_models.Domain.DoesNotExist:
print ("Warning: target domain %s does not exists, "
"not creating alias domain %s"
% old_da.target_domain, old_da.alias_domain)
continue
def _migrate_mailbox_aliases(self, domain, options, creator):
"""Migrate mailbox aliases of a single domain."""
print "\tMigrating mailbox aliases"
old_aliases = pf_models.Alias.objects \
.using(options["_from"]).filter(domain=domain.name)
for old_al in old_aliases:
if old_al.address == old_al.goto:
continue
new_al = admin_models.Alias()
local_part, tmp = split_mailbox(old_al.address)
if local_part is None or not len(local_part):
if tmp is None or not len(tmp):
print (
"Warning: skipping alias %s (cannot retrieve local "
"part). You will need to recreate it manually."
% old_al.address
)
continue
new_al.address = "*"
else:
new_al.address = local_part
new_al.domain = domain
new_al.enabled = old_al.active
extmboxes = []
intmboxes = []
for goto in old_al.goto.split(","):
try:
mb = admin_models.Mailbox.objects \
.using(options["_to"]).get(user__username=goto)
except admin_models.Mailbox.DoesNotExist:
extmboxes += [goto]
else:
intmboxes += [mb]
new_al.dates = self._migrate_dates(old_al)
new_al.save(
int_rcpts=intmboxes, ext_rcpts=extmboxes, creator=creator,
using=options["_to"]
)
def _migrate_mailboxes(self, domain, options, creator):
"""Migrate mailboxes of a single domain."""
print "\tMigrating mailboxes"
old_mboxes = pf_models.Mailbox.objects \
.using(options["_from"]).filter(domain=domain.name)
for old_mb in old_mboxes:
new_user = core_models.User()
new_user.username = old_mb.username
new_user.first_name = old_mb.name.partition(' ')[0]
new_user.last_name = old_mb.name.partition(' ')[2]
new_user.email = old_mb.username
new_user.is_active = old_mb.active
new_user.date_joined = old_mb.created
set_account_password(
new_user, old_mb.password, options["passwords_scheme"])
new_user.dates = self._migrate_dates(old_mb)
new_user.save(creator=creator, using=options["_to"])
new_user.set_role("SimpleUsers")
new_mb = admin_models.Mailbox()
new_mb.user = new_user
new_mb.address = old_mb.local_part
new_mb.domain = domain
new_mb.dates = self._migrate_dates(old_mb)
new_mb.set_quota(old_mb.quota / 1024000, override_rules=True)
new_mb.save(creator=creator, using=options["_to"])
def _migrate_domain(self, pf_domain, options, creator):
"""Single domain migration."""
print "\nMigrating domain %s" % pf_domain.domain
newdom = admin_models.Domain()
newdom.name = pf_domain.domain
newdom.enabled = pf_domain.active
newdom.quota = pf_domain.maxquota
newdom.dates = self._migrate_dates(pf_domain)
newdom.save(creator=creator, using=options["_to"])
self._migrate_domain_aliases(newdom, options, creator)
self._migrate_mailboxes(newdom, options, creator)
self._migrate_mailbox_aliases(newdom, options, creator)
self._migrate_admins(options, creator, pf_domain, newdom)
def _migrate_admins(self, options, creator, pf_domain, newdom=None):
"""Administrators migration.
:param pf_domain: The ``pf_models.Domain`` to get the admins to migrate.
:param newdom: If None the admins will not be linked to any domain
and they will be SuperAdmins. Otherwise link them to
this domain and make them DomainAdmins.
"""
if newdom is None:
print "\nMigrating super administrators"
else:
print "\tMigrating administrators"
dagroup = Group.objects.using(options["_to"]).get(name="DomainAdmins")
for old_admin in pf_domain.admins.all():
if newdom is None:
print "\tMigrating %s" % old_admin.username
# In postfixadmin, it's possible to have an admin account
# and a user account with the same username but they are
# completely different entities, so they do not have a
# common password. In Modoboa this does not makes sense, so
# we actually merge these two entities into a single user
# if both are found. Question is, which password should we
# use?. The admin password is used to be on the secure
# side.
try:
user = core_models.User.objects \
.using(options["_to"]).get(username=old_admin.username)
if "SimpleUsers" == user.group:
print (
"Warning: Found an admin account with the same "
"username as normal user '%s'. The existing user will "
"be promoted to admin and it's password changed to the "
"admin's account password. " % user.username
)
except core_models.User.DoesNotExist:
user = core_models.User()
user.username = old_admin.username
user.email = old_admin.username
user.is_active = old_admin.active
user.save(creator=creator, using=options["_to"])
user.date_joined = old_admin.modified
set_account_password(
user, old_admin.password, options["passwords_scheme"])
if newdom is None:
grant_access_to_all_objects(user, "SuperAdmins")
user.is_superuser = True
else:
user.groups.add(dagroup)
newdom.add_admin(user)
user.save(using=options["_to"])
def _do_migration(self, options, creator_username='admin'):
"""Run the complete migration."""
pf_domains = pf_models.Domain.objects.using(
options["_from"]).exclude(domain='ALL')
creator = core_models.User.objects.using(options["_to"]).get(
username=creator_username)
for pf_domain in pf_domains:
try:
# Skip this domain if it's an alias
is_domain_alias = pf_models.AliasDomain.objects \
.using(options["_from"]).get(alias_domain=pf_domain.domain)
print "Info: %s looks like an alias domain, skipping it" \
% pf_domain.domain
continue
except pf_models.AliasDomain.DoesNotExist:
self._migrate_domain(pf_domain, options, creator)
# Handle the ALL domain
pf_domain = pf_models.Domain.objects.using(
options["_from"]).get(domain='ALL')
self._migrate_admins(options, creator, pf_domain)
def handle(self, *args, **options):
"""Command entry point."""
with transaction.commit_on_success():
self._do_migration(options)
-201
View File
@@ -1,201 +0,0 @@
# coding: utf-8
"""postfixadmin models."""
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# Feel free to rename the models, but don't rename db_table values or
# field names.
#
# Also note: You'll have to insert the output of 'django-admin.py
# sqlcustom [appname]' into your database.
from django.db import models
class Admin(models.Model):
username = models.CharField(max_length=255, primary_key=True)
password = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
class Meta:
db_table = u'admin'
app_label = 'pfxadmin_migrate'
managed = False
class Alias(models.Model):
address = models.CharField(max_length=255, primary_key=True)
goto = models.TextField()
domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
class Meta:
db_table = u'alias'
app_label = 'pfxadmin_migrate'
managed = False
class AliasDomain(models.Model):
alias_domain = models.CharField(max_length=255, primary_key=True)
target_domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
class Meta:
db_table = u'alias_domain'
app_label = 'pfxadmin_migrate'
managed = False
class Config(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=60)
value = models.CharField(max_length=60)
class Meta:
db_table = u'config'
app_label = 'pfxadmin_migrate'
managed = False
class Domain(models.Model):
domain = models.CharField(max_length=255, primary_key=True)
description = models.CharField(max_length=255)
aliases = models.IntegerField()
mailboxes = models.IntegerField()
maxquota = models.BigIntegerField()
quota = models.BigIntegerField()
transport = models.CharField(max_length=255)
backupmx = models.IntegerField()
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
admins = models.ManyToManyField(Admin, through='DomainAdmins')
class Meta:
db_table = u'domain'
app_label = 'pfxadmin_migrate'
managed = False
class DomainAdmins(models.Model):
username = models.ForeignKey(Admin, db_column='username')
domain = models.ForeignKey(Domain, db_column='domain')
created = models.DateTimeField(primary_key=True)
active = models.IntegerField()
class Meta:
db_table = u'domain_admins'
app_label = 'pfxadmin_migrate'
managed = False
class Fetchmail(models.Model):
id = models.IntegerField(primary_key=True)
mailbox = models.CharField(max_length=255)
src_server = models.CharField(max_length=255)
src_auth = models.CharField(max_length=33, blank=True)
src_user = models.CharField(max_length=255)
src_password = models.CharField(max_length=255)
src_folder = models.CharField(max_length=255)
poll_time = models.IntegerField()
fetchall = models.IntegerField()
keep = models.IntegerField()
protocol = models.CharField(max_length=12, blank=True)
usessl = models.IntegerField()
extra_options = models.TextField(blank=True)
returned_text = models.TextField(blank=True)
mda = models.CharField(max_length=255)
date = models.DateTimeField()
class Meta:
db_table = u'fetchmail'
app_label = 'pfxadmin_migrate'
managed = False
class Log(models.Model):
timestamp = models.DateTimeField()
username = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
action = models.CharField(max_length=255)
data = models.TextField()
class Meta:
db_table = u'log'
app_label = 'pfxadmin_migrate'
managed = False
class Mailbox(models.Model):
username = models.CharField(max_length=255, primary_key=True)
password = models.CharField(max_length=255)
name = models.CharField(max_length=255)
maildir = models.CharField(max_length=255)
quota = models.BigIntegerField()
local_part = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
class Meta:
db_table = u'mailbox'
app_label = 'pfxadmin_migrate'
managed = False
class Quota(models.Model):
username = models.CharField(max_length=255, primary_key=True)
path = models.CharField(max_length=100, primary_key=True)
current = models.BigIntegerField(null=True, blank=True)
class Meta:
db_table = u'quota'
app_label = 'pfxadmin_migrate'
managed = False
class Quota2(models.Model):
username = models.CharField(max_length=100, primary_key=True)
bytes = models.BigIntegerField()
messages = models.IntegerField()
class Meta:
db_table = u'quota2'
app_label = 'pfxadmin_migrate'
managed = False
class Vacation(models.Model):
email = models.CharField(max_length=255)
subject = models.CharField(max_length=255)
body = models.TextField()
cache = models.TextField()
domain = models.CharField(max_length=255)
created = models.DateTimeField()
active = models.IntegerField()
class Meta:
db_table = u'vacation'
app_label = 'pfxadmin_migrate'
managed = False
class VacationNotification(models.Model):
on_vacation = models.ForeignKey(Vacation, db_column='on_vacation')
notified = models.CharField(max_length=255, primary_key=True)
notified_at = models.DateTimeField()
class Meta:
db_table = u'vacation_notification'
app_label = 'pfxadmin_migrate'
managed = False