servers.py 9.34 KB
Newer Older
Will Daly committed
1 2 3
"""
Run and manage servers for local development.
"""
4
from __future__ import print_function
Will Daly committed
5 6
import argparse
from paver.easy import *
7 8

from .assets import collect_assets
Will Daly committed
9
from .utils.cmd import django_cmd
10
from .utils.process import run_process, run_multi_processes
Will Daly committed
11 12 13


DEFAULT_PORT = {"lms": 8000, "studio": 8001}
14
DEFAULT_SETTINGS = 'devstack'
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
OPTIMIZED_SETTINGS = "devstack_optimized"
OPTIMIZED_ASSETS_SETTINGS = "test_static_optimized"

ASSET_SETTINGS_HELP = (
    "Settings file used for updating assets. Defaults to the value of the settings variable if not provided."
)


def run_server(
        system, fast=False, settings=None, asset_settings=None, port=None, contracts=False
):
    """Start the server for LMS or Studio.

    Args:
        system (str): The system to be run (lms or studio).
        fast (bool): If true, then start the server immediately without updating assets (defaults to False).
        settings (str): The Django settings module to use; if not provided, use the default.
        asset_settings (str) The settings to use when generating assets. If not provided, assets are not generated.
        port (str): The port number to run the server on. If not provided, uses the default port for the system.
        contracts (bool) If true then PyContracts is enabled (defaults to False).
Will Daly committed
35 36
    """
    if system not in ['lms', 'studio']:
37
        print("System must be either lms or studio", file=sys.stderr)
Will Daly committed
38 39
        exit(1)

40 41 42
    if not settings:
        settings = DEFAULT_SETTINGS

43 44 45 46 47 48 49
    if not fast and asset_settings:
        args = [system, '--settings={}'.format(asset_settings), '--watch']
        # The default settings use DEBUG mode for running the server which means that
        # the optimized assets are ignored, so we skip collectstatic in that case
        # to save time.
        if settings == DEFAULT_SETTINGS:
            args.append('--skip-collect')
Will Daly committed
50 51 52 53 54
        call_task('pavelib.assets.update_assets', args=args)

    if port is None:
        port = DEFAULT_PORT[system]

55 56 57 58 59 60
    args = [settings, 'runserver', '--traceback', '--pythonpath=.', '0.0.0.0:{}'.format(port)]

    if contracts:
        args.append("--contracts")

    run_process(django_cmd(system, *args))
Will Daly committed
61 62 63 64 65 66


@task
@needs('pavelib.prereqs.install_prereqs')
@cmdopts([
    ("settings=", "s", "Django settings"),
67
    ("asset-settings=", "a", ASSET_SETTINGS_HELP),
Will Daly committed
68
    ("port=", "p", "Port"),
69
    ("fast", "f", "Skip updating assets"),
Will Daly committed
70 71 72 73 74
])
def lms(options):
    """
    Run the LMS server.
    """
75 76
    settings = getattr(options, 'settings', DEFAULT_SETTINGS)
    asset_settings = getattr(options, 'asset-settings', settings)
Will Daly committed
77 78
    port = getattr(options, 'port', None)
    fast = getattr(options, 'fast', False)
79 80 81 82 83 84 85
    run_server(
        'lms',
        fast=fast,
        settings=settings,
        asset_settings=asset_settings,
        port=port,
    )
Will Daly committed
86 87 88 89 90 91


@task
@needs('pavelib.prereqs.install_prereqs')
@cmdopts([
    ("settings=", "s", "Django settings"),
92
    ("asset-settings=", "a", ASSET_SETTINGS_HELP),
Will Daly committed
93
    ("port=", "p", "Port"),
94
    ("fast", "f", "Skip updating assets"),
Will Daly committed
95 96 97 98 99
])
def studio(options):
    """
    Run the Studio server.
    """
100 101
    settings = getattr(options, 'settings', DEFAULT_SETTINGS)
    asset_settings = getattr(options, 'asset-settings', settings)
Will Daly committed
102 103
    port = getattr(options, 'port', None)
    fast = getattr(options, 'fast', False)
104 105 106 107 108 109 110
    run_server(
        'studio',
        fast=fast,
        settings=settings,
        asset_settings=asset_settings,
        port=port,
    )
Will Daly committed
111 112 113 114 115 116 117 118 119 120 121 122


@task
@needs('pavelib.prereqs.install_prereqs')
@consume_args
def devstack(args):
    """
    Start the devstack lms or studio server
    """
    parser = argparse.ArgumentParser(prog='paver devstack')
    parser.add_argument('system', type=str, nargs=1, help="lms or studio")
    parser.add_argument('--fast', action='store_true', default=False, help="Skip updating assets")
123 124 125
    parser.add_argument('--optimized', action='store_true', default=False, help="Run with optimized assets")
    parser.add_argument('--settings', type=str, default=DEFAULT_SETTINGS, help="Settings file")
    parser.add_argument('--asset-settings', type=str, default=None, help=ASSET_SETTINGS_HELP)
126 127 128 129 130 131
    parser.add_argument(
        '--no-contracts',
        action='store_true',
        default=False,
        help="Disable contracts. By default, they're enabled in devstack."
    )
Will Daly committed
132
    args = parser.parse_args(args)
133 134 135 136 137
    settings = args.settings
    asset_settings = args.asset_settings if args.asset_settings else settings
    if args.optimized:
        settings = OPTIMIZED_SETTINGS
        asset_settings = OPTIMIZED_ASSETS_SETTINGS
138
    sh(django_cmd('cms', settings, 'reindex_course', '--setup'))
139 140 141 142 143 144 145
    run_server(
        args.system[0],
        fast=args.fast,
        settings=settings,
        asset_settings=asset_settings,
        contracts=not args.no_contracts,
    )
Will Daly committed
146 147 148 149 150 151 152 153 154 155 156 157


@task
@needs('pavelib.prereqs.install_prereqs')
@cmdopts([
    ("settings=", "s", "Django settings"),
])
def celery(options):
    """
    Runs Celery workers.
    """
    settings = getattr(options, 'settings', 'dev_with_worker')
158
    run_process(django_cmd('lms', settings, 'celery', 'worker', '--beat', '--loglevel=INFO', '--pythonpath=.'))
Will Daly committed
159 160 161 162 163


@task
@needs('pavelib.prereqs.install_prereqs')
@cmdopts([
164
    ("settings=", "s", "Django settings for both LMS and Studio"),
165
    ("asset_settings=", "a", "Django settings for updating assets for both LMS and Studio (defaults to settings)"),
Will Daly committed
166
    ("worker_settings=", "w", "Celery worker Django settings"),
167
    ("fast", "f", "Skip updating assets"),
168
    ("optimized", "o", "Run with optimized assets"),
169
    ("settings_lms=", "l", "Set LMS only, overriding the value from --settings (if provided)"),
170
    ("asset_settings_lms=", None, "Set LMS only, overriding the value from --asset_settings (if provided)"),
171
    ("settings_cms=", "c", "Set Studio only, overriding the value from --settings (if provided)"),
172
    ("asset_settings_cms=", None, "Set Studio only, overriding the value from --asset_settings (if provided)"),
Will Daly committed
173 174 175 176 177
])
def run_all_servers(options):
    """
    Runs Celery workers, Studio, and LMS.
    """
178
    settings = getattr(options, 'settings', DEFAULT_SETTINGS)
179
    asset_settings = getattr(options, 'asset_settings', settings)
Will Daly committed
180 181
    worker_settings = getattr(options, 'worker_settings', 'dev_with_worker')
    fast = getattr(options, 'fast', False)
182 183 184 185 186 187 188 189 190 191
    optimized = getattr(options, 'optimized', False)

    if optimized:
        settings = OPTIMIZED_SETTINGS
        asset_settings = OPTIMIZED_ASSETS_SETTINGS

    settings_lms = getattr(options, 'settings_lms', settings)
    settings_cms = getattr(options, 'settings_cms', settings)
    asset_settings_lms = getattr(options, 'asset_settings_lms', asset_settings)
    asset_settings_cms = getattr(options, 'asset_settings_cms', asset_settings)
Will Daly committed
192 193

    if not fast:
194 195 196 197 198 199
        # First update assets for both LMS and Studio but don't collect static yet
        args = [
            'lms', 'studio',
            '--settings={}'.format(asset_settings),
            '--skip-collect'
        ]
200 201
        call_task('pavelib.assets.update_assets', args=args)

202 203 204 205 206 207 208
        # Now collect static for each system separately with the appropriate settings.
        # Note that the default settings use DEBUG mode for running the server which
        # means that the optimized assets are ignored, so we skip collectstatic in that
        # case to save time.
        if settings != DEFAULT_SETTINGS:
            collect_assets(['lms'], asset_settings_lms)
            collect_assets(['studio'], asset_settings_cms)
209

210
        # Install an asset watcher to regenerate files that change
211
        call_task('pavelib.assets.watch_assets', options={'background': True})
212 213 214 215 216 217 218

    # Start up LMS, CMS and Celery
    lms_port = DEFAULT_PORT['lms']
    cms_port = DEFAULT_PORT['studio']
    lms_runserver_args = ["0.0.0.0:{}".format(lms_port)]
    cms_runserver_args = ["0.0.0.0:{}".format(cms_port)]

Will Daly committed
219
    run_multi_processes([
220 221 222 223 224 225 226 227 228
        django_cmd(
            'lms', settings_lms, 'runserver', '--traceback', '--pythonpath=.', *lms_runserver_args
        ),
        django_cmd(
            'studio', settings_cms, 'runserver', '--traceback', '--pythonpath=.', *cms_runserver_args
        ),
        django_cmd(
            'lms', worker_settings, 'celery', 'worker', '--beat', '--loglevel=INFO', '--pythonpath=.'
        )
Will Daly committed
229 230 231 232 233 234 235 236 237 238 239 240
    ])


@task
@needs('pavelib.prereqs.install_prereqs')
@cmdopts([
    ("settings=", "s", "Django settings"),
])
def update_db():
    """
    Runs syncdb and then migrate.
    """
241
    settings = getattr(options, 'settings', DEFAULT_SETTINGS)
242 243
    for system in ('lms', 'cms'):
        sh(django_cmd(system, settings, 'syncdb', '--migrate', '--traceback', '--pythonpath=.'))
Will Daly committed
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265


@task
@needs('pavelib.prereqs.install_prereqs')
@consume_args
def check_settings(args):
    """
    Checks settings files.
    """
    parser = argparse.ArgumentParser(prog='paver check_settings')
    parser.add_argument('system', type=str, nargs=1, help="lms or studio")
    parser.add_argument('settings', type=str, nargs=1, help='Django settings')
    args = parser.parse_args(args)

    system = args.system[0]
    settings = args.settings[0]

    try:
        import_cmd = "echo 'import {system}.envs.{settings}'".format(system=system, settings=settings)
        django_shell_cmd = django_cmd(system, settings, 'shell', '--plain', '--pythonpath=.')
        sh("{import_cmd} | {shell_cmd}".format(import_cmd=import_cmd, shell_cmd=django_shell_cmd))

266
    except:  # pylint: disable=bare-except
267
        print("Failed to import settings", file=sys.stderr)