mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
Actually *add* the database schema management utilities
In r397874, the scripts were removed... but not replaced. Thanks to Michael Young for noticing this! ........ Merged revisions 397911 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397912 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
63
contrib/ast-db-manage/README.md
Normal file
63
contrib/ast-db-manage/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
Asterisk Database Manager
|
||||
=========================
|
||||
|
||||
Asterisk includes optional database integration for a variety of features.
|
||||
The purpose of this effort is to assist in managing the database schema
|
||||
for Asterisk database integration.
|
||||
|
||||
This is implemented as a set of repositories that contain database schema
|
||||
migrations, using [Alembic](http://alembic.readthedocs.org). The existing
|
||||
repositories include:
|
||||
|
||||
* `config` - Tables used for Asterisk realtime configuration
|
||||
* `voicemail` - Tables used for `ODBC_STOARGE` of voicemail messages
|
||||
|
||||
Alembic uses SQLAlchemy, which has support for
|
||||
[many databases](http://docs.sqlalchemy.org/en/rel_0_8/dialects/index.html).
|
||||
|
||||
IMPORTANT NOTE: This is brand new and the initial migrations are still subject
|
||||
to change. Only use this for testing purposes for now.
|
||||
|
||||
Example Usage
|
||||
-------------
|
||||
|
||||
First, create an ini file that contains database connection details. For help
|
||||
with connection string details, see the
|
||||
[SQLAlchemy docs](http://docs.sqlalchemy.org/en/rel_0_8/core/engines.html#database-urls).
|
||||
|
||||
$ cp config.ini.sample config.ini
|
||||
... edit config.ini and change sqlalchemy.url ...
|
||||
|
||||
Next, bring the database up to date with the current schema.
|
||||
|
||||
$ alembic -c config.ini upgrade head
|
||||
|
||||
In the future, as additional database migrations are added, you can run
|
||||
alembic again to migrate the existing tables to the latest schema.
|
||||
|
||||
$ alembic -c config.ini upgrade head
|
||||
|
||||
The migrations support both upgrading and downgrading. You could go all the
|
||||
way back to where you started with no tables by downgrading back to the base
|
||||
revision.
|
||||
|
||||
$ alembic -c config.ini downgrade base
|
||||
|
||||
`base` and `head` are special revisions. You can refer to specific revisions
|
||||
to upgrade or downgrade to, as well.
|
||||
|
||||
$ alembic -c config.ini upgrade 4da0c5f79a9c
|
||||
|
||||
Offline Mode
|
||||
------------
|
||||
|
||||
If you would like to just generate the SQL statements that would have been
|
||||
executed, you can use alembic's offline mode.
|
||||
|
||||
$ alembic -c config.ini upgrade head --sql
|
||||
|
||||
Adding Database Migrations
|
||||
--------------------------
|
||||
|
||||
The best way to learn about how to add additional database migrations is to
|
||||
refer to the [Alembic documentation](http://alembic.readthedocs.org).
|
48
contrib/ast-db-manage/config.ini.sample
Normal file
48
contrib/ast-db-manage/config.ini.sample
Normal file
@@ -0,0 +1,48 @@
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = config
|
||||
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
sqlalchemy.url = mysql://root:password@localhost/asterisk
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
71
contrib/ast-db-manage/config/env.py
Normal file
71
contrib/ast-db-manage/config/env.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import with_statement
|
||||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from logging.config import fileConfig
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
target_metadata = None
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(url=url)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
engine = engine_from_config(
|
||||
config.get_section(config.config_ini_section),
|
||||
prefix='sqlalchemy.',
|
||||
poolclass=pool.NullPool)
|
||||
|
||||
connection = engine.connect()
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata
|
||||
)
|
||||
|
||||
try:
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
|
22
contrib/ast-db-manage/config/script.py.mako
Normal file
22
contrib/ast-db-manage/config/script.py.mako
Normal file
@@ -0,0 +1,22 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
@@ -0,0 +1,292 @@
|
||||
#
|
||||
# Asterisk -- An open source telephony toolkit.
|
||||
#
|
||||
# Copyright (C) 2013, Russell Bryant
|
||||
#
|
||||
# Russell Bryant <russell@rusellbryant.net>
|
||||
#
|
||||
# See http://www.asterisk.org for more information about
|
||||
# the Asterisk project. Please do not directly contact
|
||||
# any of the maintainers of this project for assistance;
|
||||
# the project provides a web site, mailing lists and IRC
|
||||
# channels for your use.
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License Version 2. See the LICENSE file
|
||||
# at the top of the source tree.
|
||||
#
|
||||
|
||||
"""Create tables
|
||||
|
||||
Revision ID: 4da0c5f79a9c
|
||||
Revises: None
|
||||
Create Date: 2013-07-28 12:28:03.091587
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '4da0c5f79a9c'
|
||||
down_revision = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
YESNO_VALUES = ['yes', 'no']
|
||||
TYPE_VALUES = ['friend', 'user', 'peer']
|
||||
|
||||
SIP_TRANSPORT_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss', 'udp,tcp', 'tcp,udp']
|
||||
SIP_DTMFMODE_VALUES = ['rfc2833', 'info', 'shortinfo', 'inband', 'auto']
|
||||
SIP_DIRECTMEDIA_VALUES = ['yes', 'no', 'nonat', 'update']
|
||||
SIP_PROGRESSINBAND_VALUES = ['yes', 'no', 'never']
|
||||
SIP_SESSION_TIMERS_VALUES = ['accept', 'refuse', 'originate']
|
||||
SIP_SESSION_REFRESHER_VALUES = ['uac', 'uas']
|
||||
SIP_CALLINGPRES_VALUES = ['allowed_not_screened', 'allowed_passed_screen',
|
||||
'allowed_failed_screen', 'allowed',
|
||||
'prohib_not_screened', 'prohib_passed_screen',
|
||||
'prohib_failed_screen', 'prohib']
|
||||
|
||||
IAX_REQUIRECALLTOKEN_VALUES = ['yes', 'no', 'auto']
|
||||
IAX_ENCRYPTION_VALUES = ['yes', 'no', 'aes128']
|
||||
IAX_TRANSFER_VALUES = ['yes', 'no', 'mediaonly']
|
||||
|
||||
MOH_MODE_VALUES = ['custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3']
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'sippeers',
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False,
|
||||
autoincrement=True),
|
||||
sa.Column('name', sa.String(40), nullable=False, unique=True),
|
||||
sa.Column('ipaddr', sa.String(45)),
|
||||
sa.Column('port', sa.Integer),
|
||||
sa.Column('regseconds', sa.Integer),
|
||||
sa.Column('defaultuser', sa.String(40)),
|
||||
sa.Column('fullcontact', sa.String(80)),
|
||||
sa.Column('regserver', sa.String(20)),
|
||||
sa.Column('useragent', sa.String(20)),
|
||||
sa.Column('lastms', sa.Integer),
|
||||
sa.Column('host', sa.String(40)),
|
||||
sa.Column('type', sa.Enum(*TYPE_VALUES)),
|
||||
sa.Column('context', sa.String(40)),
|
||||
sa.Column('permit', sa.String(95)),
|
||||
sa.Column('deny', sa.String(95)),
|
||||
sa.Column('secret', sa.String(40)),
|
||||
sa.Column('md5secret', sa.String(40)),
|
||||
sa.Column('remotesecret', sa.String(40)),
|
||||
sa.Column('transport', sa.Enum(*SIP_TRANSPORT_VALUES)),
|
||||
sa.Column('dtmfmode', sa.Enum(*SIP_DTMFMODE_VALUES)),
|
||||
sa.Column('directmedia', sa.Enum(*SIP_DIRECTMEDIA_VALUES)),
|
||||
sa.Column('nat', sa.String(29)),
|
||||
sa.Column('callgroup', sa.String(40)),
|
||||
sa.Column('pickupgroup', sa.String(40)),
|
||||
sa.Column('language', sa.String(40)),
|
||||
sa.Column('disallow', sa.String(200)),
|
||||
sa.Column('allow', sa.String(200)),
|
||||
sa.Column('insecure', sa.String(40)),
|
||||
sa.Column('trustrpid', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('progressinband', sa.Enum(*SIP_PROGRESSINBAND_VALUES)),
|
||||
sa.Column('promiscredir', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('useclientcode', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('accountcode', sa.String(40)),
|
||||
sa.Column('setvar', sa.String(200)),
|
||||
sa.Column('callerid', sa.String(40)),
|
||||
sa.Column('amaflags', sa.String(40)),
|
||||
sa.Column('callcounter', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('busylevel', sa.Integer),
|
||||
sa.Column('allowoverlap', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('allowsubscribe', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('videosupport', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('maxcallbitrate', sa.Integer),
|
||||
sa.Column('rfc2833compensate', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('mailbox', sa.String(40)),
|
||||
sa.Column('session-timers', sa.Enum(*SIP_SESSION_TIMERS_VALUES)),
|
||||
sa.Column('session-expires', sa.Integer),
|
||||
sa.Column('session-minse', sa.Integer),
|
||||
sa.Column('session-refresher', sa.Enum(*SIP_SESSION_REFRESHER_VALUES)),
|
||||
sa.Column('t38pt_usertpsource', sa.String(40)),
|
||||
sa.Column('regexten', sa.String(40)),
|
||||
sa.Column('fromdomain', sa.String(40)),
|
||||
sa.Column('fromuser', sa.String(40)),
|
||||
sa.Column('qualify', sa.String(40)),
|
||||
sa.Column('defaultip', sa.String(45)),
|
||||
sa.Column('rtptimeout', sa.Integer),
|
||||
sa.Column('rtpholdtimeout', sa.Integer),
|
||||
sa.Column('sendrpid', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('outboundproxy', sa.String(40)),
|
||||
sa.Column('callbackextension', sa.String(40)),
|
||||
sa.Column('timert1', sa.Integer),
|
||||
sa.Column('timerb', sa.Integer),
|
||||
sa.Column('qualifyfreq', sa.Integer),
|
||||
sa.Column('constantssrc', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('contactpermit', sa.String(95)),
|
||||
sa.Column('contactdeny', sa.String(95)),
|
||||
sa.Column('usereqphone', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('textsupport', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('faxdetect', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('buggymwi', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('auth', sa.String(40)),
|
||||
sa.Column('fullname', sa.String(40)),
|
||||
sa.Column('trunkname', sa.String(40)),
|
||||
sa.Column('cid_number', sa.String(40)),
|
||||
sa.Column('callingpres', sa.Enum(*SIP_CALLINGPRES_VALUES)),
|
||||
sa.Column('mohinterpret', sa.String(40)),
|
||||
sa.Column('mohsuggest', sa.String(40)),
|
||||
sa.Column('parkinglot', sa.String(40)),
|
||||
sa.Column('hasvoicemail', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('subscribemwi', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('vmexten', sa.String(40)),
|
||||
sa.Column('autoframing', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('rtpkeepalive', sa.Integer),
|
||||
sa.Column('call-limit', sa.Integer),
|
||||
sa.Column('g726nonstandard', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('ignoresdpversion', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('allowtransfer', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('dynamic', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('path', sa.String(256)),
|
||||
sa.Column('supportpath', sa.Enum(*YESNO_VALUES))
|
||||
)
|
||||
op.create_index('sippeers_name', 'sippeers', ['name'])
|
||||
op.create_index('sippeers_name_host', 'sippeers', ['name', 'host'])
|
||||
op.create_index('sippeers_ipaddr_port', 'sippeers', ['ipaddr', 'port'])
|
||||
op.create_index('sippeers_host_port', 'sippeers', ['host', 'port'])
|
||||
|
||||
op.create_table(
|
||||
'iaxfriends',
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False,
|
||||
autoincrement=True),
|
||||
sa.Column('name', sa.String(40), nullable=False, unique=True),
|
||||
sa.Column('type', sa.Enum(*TYPE_VALUES)),
|
||||
sa.Column('username', sa.String(40)),
|
||||
sa.Column('mailbox', sa.String(40)),
|
||||
sa.Column('secret', sa.String(40)),
|
||||
sa.Column('dbsecret', sa.String(40)),
|
||||
sa.Column('context', sa.String(40)),
|
||||
sa.Column('regcontext', sa.String(40)),
|
||||
sa.Column('host', sa.String(40)),
|
||||
sa.Column('ipaddr', sa.String(40)),
|
||||
sa.Column('port', sa.Integer),
|
||||
sa.Column('defaultip', sa.String(20)),
|
||||
sa.Column('sourceaddress', sa.String(20)),
|
||||
sa.Column('mask', sa.String(20)),
|
||||
sa.Column('regexten', sa.String(40)),
|
||||
sa.Column('regseconds', sa.Integer),
|
||||
sa.Column('accountcode', sa.String(20)),
|
||||
sa.Column('mohinterpret', sa.String(20)),
|
||||
sa.Column('mohsuggest', sa.String(20)),
|
||||
sa.Column('inkeys', sa.String(40)),
|
||||
sa.Column('outkeys', sa.String(40)),
|
||||
sa.Column('language', sa.String(10)),
|
||||
sa.Column('callerid', sa.String(100)),
|
||||
sa.Column('cid_number', sa.String(40)),
|
||||
sa.Column('sendani', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('fullname', sa.String(40)),
|
||||
sa.Column('trunk', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('auth', sa.String(20)),
|
||||
sa.Column('maxauthreq', sa.Integer),
|
||||
sa.Column('requirecalltoken', sa.Enum(*IAX_REQUIRECALLTOKEN_VALUES)),
|
||||
sa.Column('encryption', sa.Enum(*IAX_ENCRYPTION_VALUES)),
|
||||
sa.Column('transfer', sa.Enum(*IAX_TRANSFER_VALUES)),
|
||||
sa.Column('jitterbuffer', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('forcejitterbuffer', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('disallow', sa.String(200)),
|
||||
sa.Column('allow', sa.String(200)),
|
||||
sa.Column('codecpriority', sa.String(40)),
|
||||
sa.Column('qualify', sa.String(10)),
|
||||
sa.Column('qualifysmoothing', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('qualifyfreqok', sa.String(10)),
|
||||
sa.Column('qualifyfreqnotok', sa.String(10)),
|
||||
sa.Column('timezone', sa.String(20)),
|
||||
sa.Column('adsi', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('amaflags', sa.String(20)),
|
||||
sa.Column('setvar', sa.String(200))
|
||||
)
|
||||
op.create_index('iaxfriends_name', 'iaxfriends', ['name'])
|
||||
op.create_index('iaxfriends_name_host', 'iaxfriends', ['name', 'host'])
|
||||
op.create_index('iaxfriends_name_ipaddr_port', 'iaxfriends',
|
||||
['name', 'ipaddr', 'port'])
|
||||
op.create_index('iaxfriends_ipaddr_port', 'iaxfriends', ['ipaddr', 'port'])
|
||||
op.create_index('iaxfriends_host_port', 'iaxfriends', ['host', 'port'])
|
||||
|
||||
op.create_table(
|
||||
'voicemail',
|
||||
sa.Column('uniqueid', sa.Integer, primary_key=True, nullable=False,
|
||||
autoincrement=True),
|
||||
sa.Column('context', sa.String(80), nullable=False),
|
||||
sa.Column('mailbox', sa.String(80), nullable=False),
|
||||
sa.Column('password', sa.String(80), nullable=False),
|
||||
sa.Column('fullname', sa.String(80)),
|
||||
sa.Column('alias', sa.String(80)),
|
||||
sa.Column('email', sa.String(80)),
|
||||
sa.Column('pager', sa.String(80)),
|
||||
sa.Column('attach', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('attachfmt', sa.String(10)),
|
||||
sa.Column('serveremail', sa.String(80)),
|
||||
sa.Column('language', sa.String(20)),
|
||||
sa.Column('tz', sa.String(30)),
|
||||
sa.Column('deletevoicemail', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('saycid', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('sendvoicemail', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('review', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('tempgreetwarn', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('operator', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('envelope', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('sayduration', sa.Integer),
|
||||
sa.Column('forcename', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('forcegreetings', sa.Enum(*YESNO_VALUES)),
|
||||
sa.Column('callback', sa.String(80)),
|
||||
sa.Column('dialout', sa.String(80)),
|
||||
sa.Column('exitcontext', sa.String(80)),
|
||||
sa.Column('maxmsg', sa.Integer),
|
||||
sa.Column('volgain', sa.Numeric(precision=5, scale=2)),
|
||||
sa.Column('imapuser', sa.String(80)),
|
||||
sa.Column('imappassword', sa.String(80)),
|
||||
sa.Column('imapserver', sa.String(80)),
|
||||
sa.Column('imapport', sa.String(8)),
|
||||
sa.Column('imapflags', sa.String(80)),
|
||||
sa.Column('stamp', sa.DateTime())
|
||||
)
|
||||
op.create_index('voicemail_mailbox', 'voicemail', ['mailbox'])
|
||||
op.create_index('voicemail_context', 'voicemail', ['context'])
|
||||
op.create_index('voicemail_mailbox_context', 'voicemail', ['mailbox', 'context'])
|
||||
op.create_index('voicemail_imapuser', 'voicemail', ['imapuser'])
|
||||
|
||||
op.create_table(
|
||||
'meetme',
|
||||
sa.Column('bookid', sa.Integer, primary_key=True, nullable=False,
|
||||
autoincrement=True),
|
||||
sa.Column('confno', sa.String(80), nullable=False),
|
||||
sa.Column('starttime', sa.DateTime()),
|
||||
sa.Column('endtime', sa.DateTime()),
|
||||
sa.Column('pin', sa.String(20)),
|
||||
sa.Column('adminpin', sa.String(20)),
|
||||
sa.Column('opts', sa.String(20)),
|
||||
sa.Column('adminopts', sa.String(20)),
|
||||
sa.Column('recordingfilename', sa.String(80)),
|
||||
sa.Column('recordingformat', sa.String(10)),
|
||||
sa.Column('maxusers', sa.Integer),
|
||||
sa.Column('members', sa.Integer, nullable=False, default=0)
|
||||
)
|
||||
op.create_index('meetme_confno_starttime_endtime', 'meetme',
|
||||
['confno', 'starttime', 'endtime'])
|
||||
|
||||
op.create_table(
|
||||
'musiconhold',
|
||||
sa.Column('name', sa.String(80), primary_key=True, nullable=False),
|
||||
sa.Column('mode', sa.Enum(*MOH_MODE_VALUES)),
|
||||
sa.Column('directory', sa.String(255)),
|
||||
sa.Column('application', sa.String(255)),
|
||||
sa.Column('digit', sa.String(1)),
|
||||
sa.Column('sort', sa.String(10)),
|
||||
sa.Column('format', sa.String(10)),
|
||||
sa.Column('stamp', sa.DateTime())
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('sippeers')
|
||||
op.drop_table('iaxfriends')
|
||||
op.drop_table('voicemail')
|
||||
op.drop_table('meetme')
|
||||
op.drop_table('musiconhold')
|
48
contrib/ast-db-manage/voicemail.ini.sample
Normal file
48
contrib/ast-db-manage/voicemail.ini.sample
Normal file
@@ -0,0 +1,48 @@
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = voicemail
|
||||
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
sqlalchemy.url = mysql://user:pass@localhost/voicemail
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
71
contrib/ast-db-manage/voicemail/env.py
Normal file
71
contrib/ast-db-manage/voicemail/env.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import with_statement
|
||||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from logging.config import fileConfig
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
target_metadata = None
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(url=url)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
engine = engine_from_config(
|
||||
config.get_section(config.config_ini_section),
|
||||
prefix='sqlalchemy.',
|
||||
poolclass=pool.NullPool)
|
||||
|
||||
connection = engine.connect()
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata
|
||||
)
|
||||
|
||||
try:
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
|
22
contrib/ast-db-manage/voicemail/script.py.mako
Normal file
22
contrib/ast-db-manage/voicemail/script.py.mako
Normal file
@@ -0,0 +1,22 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
@@ -0,0 +1,58 @@
|
||||
#
|
||||
# Asterisk -- An open source telephony toolkit.
|
||||
#
|
||||
# Copyright (C) 2013, Russell Bryant
|
||||
#
|
||||
# Russell Bryant <russell@rusellbryant.net>
|
||||
#
|
||||
# See http://www.asterisk.org for more information about
|
||||
# the Asterisk project. Please do not directly contact
|
||||
# any of the maintainers of this project for assistance;
|
||||
# the project provides a web site, mailing lists and IRC
|
||||
# channels for your use.
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License Version 2. See the LICENSE file
|
||||
# at the top of the source tree.
|
||||
#
|
||||
|
||||
"""Create tables
|
||||
|
||||
Revision ID: a2e9769475e
|
||||
Revises: None
|
||||
Create Date: 2013-07-29 23:43:09.431668
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a2e9769475e'
|
||||
down_revision = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'voicemail_messages',
|
||||
sa.Column('dir', sa.String(255), nullable=False),
|
||||
sa.Column('msgnum', sa.Integer, nullable=False),
|
||||
sa.Column('context', sa.String(80)),
|
||||
sa.Column('macrocontext', sa.String(80)),
|
||||
sa.Column('callerid', sa.String(80)),
|
||||
sa.Column('origtime', sa.Integer),
|
||||
sa.Column('duration', sa.Integer),
|
||||
sa.Column('recording', sa.LargeBinary),
|
||||
sa.Column('flag', sa.String(30)),
|
||||
sa.Column('category', sa.String(30)),
|
||||
sa.Column('mailboxuser', sa.String(30)),
|
||||
sa.Column('mailboxcontext', sa.String(30)),
|
||||
sa.Column('msg_id', sa.String(40))
|
||||
)
|
||||
op.create_primary_key('voicemail_messages_dir_msgnum',
|
||||
'voicemail_messages', ['dir', 'msgnum'])
|
||||
op.create_index('voicemail_messages_dir', 'voicemail_messages', ['dir'])
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('voicemail_messages')
|
Reference in New Issue
Block a user