@task
def setup_postgis_latest():
    """Set up postgis latest package from source..

    You can call this multiple times without it actually installing all over
    again each time since it checks for the presence of pgis first.

    We build from source because we want the latest build

    I'm using this together with the postgresql repo here:

    deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main

    which provides pg 9.3 at time of writing this.

    .. versionadded:: 0.17.0
    """
    setup_env()

    pg_file = '/usr/share/postgresql/9.3/contrib/postgis-2/postgis.sql'
    if not fabtools.files.is_file(pg_file):
        add_ubuntugis_ppa()
        fabtools.require.deb.package('postgresql-server-dev-9.3')
        fabtools.require.deb.package('build-essential')

        # Note - no postgis installation from package as we want to build 1.5
        # from source
        fabtools.require.postgres.server()

        # Now get and install postgis 1.5 if needed

        fabtools.require.deb.package('libxml2-dev')
        fabtools.require.deb.package('libgeos-dev')
        fabtools.require.deb.package('libgdal1-dev')
        fabtools.require.deb.package('libproj-dev')
        source_url = ('http://download.osgeo.org/postgis/source/'
                      'postgis-2.1.1.tar.gz')
        source = 'postgis-2.1.1'
        if not fabtools.files.is_file('%s.tar.gz' % source):
            run('wget %s' % source_url)
            run('tar xfz %s.tar.gz' % source)
        with cd(source):
            run('./configure')
            run('make')
            sudo('make install')

    create_postgis_2_template() @task
def create_postgis_1_5_db(dbname, user):
    """Create a postgis database.
    :param dbname: Name of database to create.
    :param user: User who should own the created db
    """
    setup_postgis_1_5()
    setup_postgres_superuser(env.user)
    require_postgres_user(user)
    fabtools.require.postgres.database(
        '%s' % dbname, owner='%s' % user, template='template_postgis')

    grant_sql = 'GRANT ALL ON schema public to %s;' % user
    # assumption is env.repo_alias is also database name
    run('psql %s -c "%s"' % (dbname, grant_sql))
    grant_sql = (
        'GRANT ALL ON ALL TABLES IN schema public to %s;' % user)
    # assumption is env.repo_alias is also database name
    run('psql %s -c "%s"' % (dbname, grant_sql))
    grant_sql = (
        'GRANT ALL ON ALL SEQUENCES IN schema public to %s;' % user)
    run('psql %s -c "%s"' % (dbname, grant_sql)) @task
def get_postgres_dump(dbname, ignore_permissions=False, file_name=None):
    """Get a dump of the database from the server.

    :param dbname: name of the database to restore the dump into.
    :type dbname: str

    :param ignore_permissions: whether permissions in the created dump
        should be preserved.
    :type ignore_permissions: bool (default False)

    :param file_name: optional file name for the dump. The file name should
        exclude any path. If file_name is ommitted, the dump will be written to
        fabgis_resources/sql/dumps/<dbname>->date>.dmp
        where date is in the form dd-mm-yyyy. This is the default naming
        convention used by the :func:`restore_postgres_dump` function below.
    :type file_name: str
    """
    setup_env()

    if file_name is None or file_name == '':
        date = run('date +%d-%B-%Y')
        my_file = '%s-%s.dmp' % (dbname, date)
    else:
        my_file = os.path.split(file_name)[1]
        put(file_name, '/tmp/%s' % my_file)

    if not ignore_permissions:
        extra_args = ''
    else:
        extra_args = '-x -O'

    run('pg_dump %s -Fc -f /tmp/%s %s' % (extra_args, my_file, dbname))
    get('/tmp/%s' % my_file, 'fabgis_resources/sql/dumps/%s' % my_file) @task
def compile_osm2pgsql():
    """From-source compile of osm2pgsql.

    We build from source so we can use recent postgresql packages.

    See: http://wiki.openstreetmap.org/wiki/Osm2pgsql#From_source
    """
    add_ubuntugis_ppa()
    fabtools.require.deb.packages([
        'build-essential',
        'libxml2-dev',
        'libgeos++-dev',
        'libpq-dev',
        'libbz2-dev',
        'libproj-dev',
        'libtool',
        'automake',
        'subversion',
        'libprotobuf-c0-dev',
        'protobuf-c-compiler',
        'lua5.2',
        'liblua5.2-0',
        'liblua5.2-dev',
        'liblua5.1-0',
    ])
    with cd('/tmp'):
        if not exists('osm2pgsql'):
            run('git clone https://github.com/openstreetmap/osm2pgsql.git')

    with cd('/tmp/osm2pgsql'):
        run('./autogen.sh')
        run('./configure')
        run('make -j4')
        sudo('make install') @task
def setup_nightly_backups():
    """Setup nightly backups for all postgresql databases.

    The template script :file:`fabgis_resources/server_config/cron/pg_backups`
    will place the last 21 days of backups in the remote user's Dropbox
    directory and will maintain 6 months of backups in their home directory.

    .. seealso:: fabgis.dropbox for help on setting up dropbox on your server.
    """
    setup_env()
    setup_postgres_superuser(env.fg.user)
    with cd('/etc/cron.daily/'):
        if exists('pg_backups'):
            sudo('rm pg_backups')

        local_dir = os.path.dirname(__file__)
        local_file = os.path.abspath(os.path.join(
            local_dir,
            '..',
            'fabgis_resources',
            'server_config',
            'cron',
            'pg_backups.templ'))
        put(local_file,
            '/etc/cron.daily/pg_backups',
            use_sudo=True)

        my_tokens = {'USER': env.fg.user, }
        replace_tokens('/etc/cron.daily/pg_backups', my_tokens)

    sudo('chmod +x /etc/cron.daily/pg_backups')
    # Run once to verify it works
    sudo('/etc/cron.daily/pg_backups') @task
def setup_tilemill(proxy_url=None):
    """Set up tile mill - see http://www.mapbox.com/tilemill/ .

    We use a pure node setup as described here:

    https://github.com/mapbox/tilemill/issues/2103#issuecomment-37473991

    in order to avoid potential conflicts with ubuntugis.

    :param proxy_url: Optional parameters to specify the url to use for your
        network proxy. It should be specified in the form: ``<host>:<port>``.
        The same proxy will be used for both http and https urls. If ommitted
        no proxy will be used.
    :type proxy_url: str
    """
    # Note raring seems not to be supported yet...
    setup_env()
    repo_alias = 'tilemill'
    print env
    update_git_checkout(
        env.fg.workspace, 'https://github.com/mapbox/tilemill.git', repo_alias)
    work_path = os.path.join(env.fg.workspace, repo_alias)
    setup_node(
        work_path,
        node_version='0.10.26',  # known good version
        proxy_url=proxy_url)

    with cd(work_path):
        run('env/bin/npm install')
    fastprint(green(
        'Tilemill installed. Use the start_tilemill task to run it.')) @task
def start_tilemill():
    """Start the tilemill service - ensure it is installed first."""
    repo_alias = 'tilemill'
    work_path = os.path.join(env.fg.workspace, repo_alias)
    host_ip = get_ip_address()
    with cd(work_path):
        command = (
            'PATH=$PATH:env/bin nohup index.js '
            '--server=true '
            '--listenHost=0.0.0.0 '
            '--coreUrl=%s:20009 '
            '--tileUrl=%s:20008 &' % (host_ip, host_ip))
        run(command)
    fastprint('Tilemill is running - point your browser at:')
    fastprint('http://%s:20009' % host_ip)
    fastprint('to use it.') @task
def setup_tilestream():
    """Set up tile stream - see https://github.com/mapbox/tilestream.

    This one deserves a little explanation:

    Tilestream is a nodejs application. Node seems to be pretty unparticular
    about maintaining api compatibility between releases so if you grab one
    from e.g. apt, chances are it won't work with tilestream.

    To address this, we use the nodeenv virtualisation environment (somewhat
    equivalent to using python virtualenv) to ensure that we have the
    expected version of tilestream. e.g.::

        nodeenv env --node=0.8.15
    """
    setup_env()
    require.deb.package('curl')
    require.deb.package('build-essential')
    require.deb.package('libssl-dev')
    require.deb.package('libsqlite3-0')
    require.deb.package('libsqlite3-dev')
    require.deb.package('git-core')
    require.deb.package('nodejs nodejs-dev npm')
    require.deb.package('python-pip')

    sudo('pip install nodeenv')

    dev_dir = '/home/%s/dev/javascript' % env.fg.user
    fastprint('making directory %s' % dev_dir)
    require.directory(dev_dir)

    tile_stream_dir = os.path.join(dev_dir, 'tilestream')
    fastprint('checkout out tilestream to %s' % tile_stream_dir)

    if not exists(tile_stream_dir):
        with cd(dev_dir):
            run('git clone http://github.com/mapbox/tilestream.git')

    with cd(tile_stream_dir):
        if not exists(os.path.join(tile_stream_dir, 'env')):
            run('nodeenv env --node=0.8.15')
        # If doing this interactively from a shell you would first do:
        # . env/bin/activate
        # npm install
        # From our scripted environment (where we cant activate the venv):
        run('env/bin/npm install') @task
def start_tilestream(tile_dir=None, ui_port=8888, tiles_port=8888, host=None):
    """Start the tilestream service - ensure it is installed first.

    Use this task when you want to start tilestream manually for testing.

    :param tile_dir: Optional directory on the remote host that holds one or
        more mbtiles files to be published. If ommitted the default of
        `~/Documents/MapBox/tiles` will be used by tilestream.
    :type tile_dir: str

    :param ui_port: Port on which the tilestream ui should be available.
    :type ui_port: int

    :param tiles_port: Port on which tilestream tile service should be
        available. You may want to use a different port here and then run a
        CDN such as cloudflare in front of the tile service.
    :type tiles_port: int

    :param host: Host name under which the service will run. Must match the
        hostname to which requests are made (even if you run it behind mod
        proxy).
    :type host: str

    Example invocation of tilestream with all the bells and whistles::

        PATH=env/bin:$PATH ./index.js \
            --host = 41.74.158.13 \
            --accesslog = /tmp/tilestream.log \
            --uiPort=8888 \
            --tilePort = 8889
    """
    setup_env()
    dev_dir = '/home/%s/dev/javascript' % env.fg.user
    tile_stream_dir = os.path.join(dev_dir, 'tilestream')
    with cd(tile_stream_dir):
        params = _build_parameters(host, tile_dir, tiles_port, ui_port)
        run('PATH=env/bin:$PATH ./index.js %s' % params)

    fastprint(
        'You may need to port forward to port 8888 or set up your '
        'vagrant instance to do so....') @task
def install_qgis2(gdal_from_source=False):
    """Install QGIS 2 under /usr/local/qgis-2.0.

    :param gdal_from_source: Whether gdal should be built from source.
        Default False.
    :type gdal_from_source: bool

    TODO: create one function from this and the 1.8 function above for DRY.

    """
    setup_env()
    setup_ccache()
    add_ubuntugis_ppa()
    sudo('apt-get build-dep -y qgis')

    #fabtools.require.deb.package('python-pyspatialite')
    fabtools.require.deb.package('python-psycopg2')
    fabtools.require.deb.package('python-qscintilla2')
    fabtools.require.deb.package('libqscintilla2-dev')
    fabtools.require.deb.package('libspatialindex-dev')

    clone_qgis(branch='release-2_0')
    workspace = '%s/cpp' % env.fg.workspace
    code_path = '%s/QGIS' % workspace
    build_path = '%s/build-qgis2-fabgis' % code_path
    build_prefix = '/usr/local/qgis-2.0'
    compile_qgis(build_path, build_prefix, gdal_from_source) @task
def install_qgis1_8(gdal_from_source=False):
    """
    Install QGIS 1.8 under /usr/local/qgis-1.8.

    :param gdal_from_source: Whether gdal should be built from source.
        Default False.
    :type gdal_from_source: bool


    """
    setup_env()
    add_ubuntugis_ppa()
    setup_ccache()
    sudo('apt-get build-dep -y qgis')
    fabtools.require.deb.package('libspatialindex-dev')
    clone_qgis(branch='release-1_8')
    workspace = '%s/cpp' % env.fg.workspace
    code_path = '%s/QGIS' % workspace
    build_path = '%s/build-qgis18-fabgis' % code_path
    build_prefix = '/usr/local/qgis-1.8'
    compile_qgis(build_path, build_prefix, gdal_from_source) @task
def install_qgis_master(gdal_from_source=False):
    """Install QGIS master under /usr/local/qgis-master.

    :param gdal_from_source: Whether gdal should be built from source.
        Default False.
    :type gdal_from_source: bool

    TODO: create one function from this and the 1.8 function above for DRY.

    """
    setup_env()
    setup_ccache()
    add_ubuntugis_ppa()
    sudo('apt-get build-dep -y qgis')

    #fabtools.require.deb.package('python-pyspatialite')
    fabtools.require.deb.package('python-psycopg2')
    fabtools.require.deb.package('python-qscintilla2')
    fabtools.require.deb.package('libqscintilla2-dev')
    fabtools.require.deb.package('libspatialindex-dev')

    clone_qgis(branch='master')
    workspace = '%s/cpp' % env.fg.workspace
    code_path = '%s/QGIS' % workspace
    build_path = '%s/build-master-fabgis' % code_path
    build_prefix = '/usr/local/qgis-master'
    compile_qgis(build_path, build_prefix, gdal_from_source) @task
def setup_qgis_server(
        site_name,
        web_root='/home/web/qgis-server',
        qgis_version='2.0',
        server_admin='none@none.com',
        template_dir=None,
        **kwargs):
    """Set up QGIS Server for QGIS.

    We assume your QGIS was built using fabgis into /usr/local/qgis-<version>.

    Place your projects in subdirectories of web root for them to be published.

    :param site_name: Name of the site e.g. qgis.linfiniti.com. Should be a
        single word with only alpha characters and dots in it.
    :type site_name: str

    :param web_root: Directory where the content lives.
    :type web_root: str

    :param qgis_version: The version you wish to server maps with. Currently
        supported values are '1.8', '2.0' and 'master'.
    :type qgis_version: str

    :param server_admin: Email address for the server admin. Defaults to
        none@none.com. This value is placed in the apache config file.
        No validation is performed.
    :type server_admin: str


    :param template_dir: Directory where the template files live. If none
        will default to ``resources/server_config/apache``. Must be a
        relative path to the fabfile you are running.
    :type template_dir: str

    :param kwargs: Any extra keyword arguments that should be appended to the
        token list that will be used when rendering the apache config template.
        Use this to pass in sensitive data such as passwords.
    :type kwargs: dict

    :returns: Path to the apache conf file.
    :rtype: str
    """
    setup_env()
    if qgis_version == '1.8':
        install_qgis1_8()
    elif qgis_version == '2.0':
        install_qgis2()
        pass
    elif qgis_version == 'master':
        install_qgis_master()
    else:
        raise Exception('Invalid QGIS version requested')
    # Clone and replace tokens in apache conf
    if template_dir is None:
        template_dir = os.path.join(
            os.path.dirname(__file__),
            'fabgis_resources', 'server_config', 'apache/')
    filename = 'qgis-server.conf.templ'
    template_path = os.path.join(template_dir, filename)
    fastprint(green('Using %s for template\n' % template_path))
    cgi_path = os.path.join(web_root, 'qgis-%s' % qgis_version)
    qgis_prefix = '/usr/local/qgis-%s' % qgis_version

    require.directory(cgi_path)
    with cd(cgi_path):
        qgis_binary = os.path.join(qgis_prefix, 'bin', 'qgis_mapserv.fcgi')

        if exists('qgis_mapserv.fcgi'):
            run('rm qgis_mapserv.fcgi')

        run('ln -s %s .' % qgis_binary)

    context = {
        'escaped_server_name': site_name.replace('.', '\.'),
        'server_name': site_name,
        'server_admin': server_admin,
        'web_root': web_root,
        'site_name': site_name,
        'cgi_path': cgi_path,
        'qgis_prefix': qgis_prefix}
    context.update(kwargs)  # merge in any params passed in to this function
    destination = '/etc/apache2/sites-available/%s.apache.conf' % site_name
    fastprint(green('Context: %s\n' % context))

    require.deb.packages(['apache2', 'libapache2-mod-fcgid'])

    upload_template(
        template_path,
        destination,
        context=context,
        use_sudo=True)

    sudo('a2dissite 000-default.conf')
    sudo('a2ensite %s.apache.conf' % site_name)
    # Check if apache configs are ok - script will abort if not ok
    sudo('/usr/sbin/apache2ctl configtest')
    require.service.restarted('apache2')
    sudo('chmod o+rX -R %s' % web_root)
    fastprint(green('Now upload your QGIS project file and data to\n'))
    fastprint(green('%s\n' % cgi_path))

    return destination @task
def build_proj4(version='4.8.0'):
    """Get proj4 from tarball and build it.

    :param version: Proj version to build. The version should be consistent
        with a downloadable tar file from the project web site. Default is
        the current stable release.
    :type version: str
    """
    setup_env()
    fabtools.require.deb.package('build-essential')
    setup_ccache()

    code_base = '%s/cpp' % env.fg.workspace
    filename = 'proj-%s' % version
    source_url = 'http://download.osgeo.org/proj/%s.tar.gz' % filename
    code_path = '%s/%s' % (code_base, filename)

    if not exists(code_path):
        fastprint('Extracted tarball does not exist, creating.')
        with cd(code_base):
            if exists('%s.tar.gz' % filename):
                run('rm %s.tar.gz' % filename)
            run('wget %s' % source_url)
            run('tar xfz %s.tar.gz' % filename)

    processor_count = get_processor_count()

    with cd(code_path):
        # Dont fail if make clean does not work
        with settings(warn_only=True):
            run('make clean')
        run('./configure')
        run('make -j %s' % processor_count)
        sudo('make install')
    # Write to ld path too so libs are loaded nicely
    ld_file = '/etc/ld.so.conf.d/usr_local_lib.conf'
    with settings(warn_only=True):
        sudo('rm %s' % ld_file)
    append_if_not_present(ld_file, '/usr/local/lib', use_sudo=True)
    sudo('ldconfig') @task
def build_hdf5(version='1.8.11'):
    """Get proj4 from tarball and build it.

    :param version: hdf5 version to build. The version should be consistent
        with a downloadable tar file from the project web site. Default is
        the current stable release.
    :type version: str
    """
    setup_env()
    fabtools.require.deb.package('build-essential')
    setup_ccache()

    code_base = '%s/cpp' % env.fg.workspace
    filename = 'hdf5-%s' % version
    source_url = (
        'http://www.hdfgroup.org/ftp/HDF5/current/src/%s.tar.gz' %
        filename)
    code_path = '%s/%s' % (code_base, filename)

    if not exists(code_path):
        fastprint('Extracted tarball does not exist, creating.')
        with cd(code_base):
            if exists('%s.tar.gz' % filename):
                run('rm %s.tar.gz' % filename)
            run('wget %s' % source_url)
            run('tar xfz %s.tar.gz' % filename)

    processor_count = get_processor_count()

    with cd(code_path):
        # Dont fail if make clean does not work
        with settings(warn_only=True):
            run('make clean')
        run('./configure')
        run('make -j %s' % processor_count)
        sudo('make install')
    # Write to ld path too so libs are loaded nicely
    ld_file = '/etc/ld.so.conf.d/usr_local_lib.conf'
    with settings(warn_only=True):
        sudo('rm %s' % ld_file)
    append_if_not_present(ld_file, '/usr/local/lib', use_sudo=True)
    sudo('ldconfig') @task
def setup_dropbox():
    """Setup a headless dropbox installation."""
    setup_env()
    dropbox_url = 'https://www.dropbox.com/download?plat=lnx.x86_64'
    dropbox_cli_url = 'https://www.dropbox.com/download?dl=packages/dropbox.py'

    with cd('~'):
        require.directory('bin')
        with cd('bin'):
            if not exists('dropbox.py'):
                run('wget -O dropbox.py "%s"' % dropbox_cli_url)
                run('chmod +x dropbox.py')
        if not exists('.dropbox-dist'):
            command = 'wget -O - "%s" | tar xzf -' % dropbox_url
            run(command)
        # After you have pasted the link and confirmed the machine account
        # you need to press Ctrl-c which unfortunately also terminates the
        # fabric session. capture=False is an attempt to remedy that.
        run('~/.dropbox-dist/dropboxd') @task
def setup_dropbox_daemon():
    """Set up dropbox to run on init.d.

    Unfortunately we can't run this as part of initial setup due to the
    control-c issue that prevents us from halting the initial dropboxd
    command needed to set up the dropbox synced account.

    So for example you need to do::

        fab vagrant setup_dropbox

    Then once your account is linked, press Ctrl-c - which will also
    terminate the above fabric job. Then run::

        fab vagrant setup_dropbox_daemon

    """
    setup_env()
    with cd('/etc/init.d/'):
        if not exists('dropbox'):
            local_dir = os.path.dirname(__file__)
            local_file = os.path.abspath(os.path.join(
                local_dir,
                '..',
                'fabgis_resources',
                'server_config',
                'dropbox',
                'dropbox.templ'))
            put(local_file,
                '/etc/init.d/dropbox',
                use_sudo=True)

        my_tokens = {'USER': env.fg.user, }
        replace_tokens('/etc/init.d/dropbox', my_tokens)

    sudo('chmod +x /etc/init.d/dropbox')
    sudo('update-rc.d dropbox defaults')
    start_dropbox()
    dropbox_status() @task
def dropbox_status():
    """Check the status of dropbox."""
    run('~/bin/dropbox.py status') @task
def start_dropbox():
    """Start the dropbox service."""
    sudo('service dropbox start') @task
def stop_dropbox():
    """Stop the dropbox service."""
    sudo('service dropbox stop') @task
def create_user(user, password=None):
    """Create a user on the remote system matching the user running this task.

    :param user: User name for the new user.
    :type user: str

    :param password: Password for new user - will prompt interactively if None.
    :type password: str
    """
    if password is None:
        fastprint(red('Please enter a password for the new web user.\n'))
        password = getpass()
    fabtools.require.users.user(user, password=password)
    fabtools.require.users.sudoer(user) @task
def setup_docker(force=False):
    """Setup docker on the target host.

    :param force: Whether to continue with installation even if
        docker already appears to be installed. Defaults to False.
    :type force: bool
    """
    fastprint(yellow('Setting up docker on host: %s\n' % env.host))
    if is_installed('lxc-docker'):
        fastprint(green(
            'This system already appears to have docker installed on it\n'))
    else:
        version = run('uname -r')
        if '3.2' in version:
            # LTS 3.2 version is too old so we install a backported one
            # see http://docs.docker.io/en/latest/installation/ubuntulinux/
            # #ubuntu-precise-12-04-lts-64-bit
            fastprint(red('Upgrading kernel to 3.8!\n'))
            response = prompt('Do you wish to continue? y/n :')
            if response != 'y':
                fastprint(red('Docker install aborted by user.\n'))
                return
            fastprint(blue('Ok upgrading kernel.'))
            require_packages([
                'linux-image-generic-lts-raring',
                'linux-headers-generic-lts-raring'])
            fastprint(red('\nWe need to reboot the system now!\n'))
            response = prompt('Do you wish to continue? y/n :')
            if response is not None:
                reboot()
        else:
            require_package('linux-image-extra-%s' % version)
        require_ppa('ppa:dotcloud/lxc-docker')
        apt_get_update()
        require_packages([
            'software-properties-common',
            'lxc-docker'])
    # Ensure ufw forwards traffic.
    # http://docs.docker.io/en/latest/installation/ubuntulinux/#ufw
    sed(
        '/etc/default/ufw',
        'DEFAULT_FORWARD_POLICY="DROP"',
        'DEFAULT_FORWARD_POLICY="ACCEPT"',
        use_sudo=False)
    setup_docker_image()
    setup_docker_user() @task
def setup_docker_image():
    """Set up the default docker image to be used in fabgis deployments.

    We base our container on dhrp/sshd image.

    After running this task you will have an image called fabgis/sshd with
    a root password of your choosing.

    On first installation we need to set the root password that will be
    used as default for this base image.
    """

    fastprint(blue(
        'Downloading the dhrp/sshd base image - may take a while.\n'))

    container_id = create_docker_container('dhrp/sshd')

    fastprint(blue(
        'setting the password in the container\n'))
    fastprint(green(
        'Enter the password "screencast" for the first root prompt below.\n'))
    fastprint(green(
        'Enter a password of YOUR OWN CHOOSING at the second prompt below.\n'))
    fastprint(green(
        'Then re-enter your own password at the confirmation prompt.\n'))
    fastprint(red(
        'Note that the password will be echoed to the console in the clear'
        '.\n'))

    mappings = get_docker_port_mappings(container_id)
    run('ssh root@localhost -p %i passwd' % mappings[22])

    fastprint(green(
        'Committing the change to a new default container fabgis/sshd\n'))

    sudo('sudo docker commit %s fabgis/sshd' % container_id)

    fastprint(red(
        'Deleting the temporary container we started during setup.\n'))

    sudo('docker kill %s' % container_id)

    fastprint(green('Installation of docker completed ok!\n')) @task
def docker():
    """Convenience function that operates in a similar way to fabtools vagrant.

    Example usage - first add this to your fabfile.py

        from fabgis.docker import docker

    Then use docker instead of a -H hostname directive e.g.::

        fab docker setup_qgis2

    This command makes no attempt to create the docker container, so will fail
    if there is not a fabgis.container.id file in the current working
    directory that contains the id of a valid container.


    .. todo:: Behaviour when more than one host is passed to fabric is still
        not defined or tested.
    """
    host_name = run('hostname')
    fastprint(green(
        'Connected on %s preparing ssh tunnel though this gateway\n' %
        host_name))
    container_id_file = 'fabgis.container.id'
    if exists(container_id_file):
        container_id = run('cat %s' % container_id_file)
    else:
        abort(red('Docker fabgis.container.id file not found.\n'))

    mappings = get_docker_port_mappings(container_id)

    ssh_port = mappings[22]
    env.port = ssh_port
    env.user = 'root'
    fastprint(env)
    host_name = run('hostname')
    fastprint(green(
        'Connected on %s via ssh tunnel though this gateway\n' % host_name)) @task
def create_docker_container(image='fabgis/sshd'):
    """Create a docker container using the provided base image.

    :param image: The image name to be used as a basis for this container.
    :type image: str

    :returns: The id of the created container.
    :rtype: str
    """
    # Id of container will be written to fabgis.container.id

    container_id_file = 'fabgis.container.id'
    if exists(container_id_file):
        sudo('rm %s' % container_id_file)

    sudo(
        'docker run -cidfile=%s -d -p 22 -p 80 %s /usr/sbin/sshd -D' %
        (container_id_file, image))

    # now get the id back - this is more reliable than reading from stdout
    container_id = run('cat %s' % container_id_file)

    return container_id @task
def install_btsync():
    """Install btsync from ppa."""
    fabtools.deb.update_index(quiet=True)
    fabtools.require.deb.package('software-properties-common')
    fabtools.require.deb.ppa('ppa:tuxpoldo/btsync')
    fabtools.require.deb.package('btsync')
    fastprint(green('BTSync installed'))
import os
from fabric.api import task, hosts, cd, run, fastprint, local, lcd
from fabric.contrib.project import rsync_project
from fabric.colors import blue
from fabgis.postgres import (
    setup_postgis_latest,
    create_postgis_1_5_db,
    get_postgres_dump,
    compile_osm2pgsql,
    setup_nightly_backups)
from fabgis.tilemill import setup_tilemill, start_tilemill
from fabgis.tilestream import setup_tilestream, start_tilestream
from fabgis.qgis import (
    install_qgis2,
    install_qgis1_8,
    install_qgis_master,
    setup_qgis_server)
from fabgis.proj4 import build_proj4
from fabgis.hdf import build_hdf5
from fabgis.dropbox import (
    setup_dropbox,
    setup_dropbox_daemon,
    dropbox_status,
    start_dropbox,
    stop_dropbox)
from fabgis.system import create_user
from fabgis.docker import (
    setup_docker, setup_docker_image, docker, create_docker_container)
from fabgis.btsync import install_btsync
from fabtools.vagrant import vagrant
# coding=utf-8
# ~/fabfile.py
"""
This is an example fabfile for the fabgis project.

Warning: These are examples and you should always test any proposed
automated deployments thoroughly before trying them on a production server.
I strongly recommend using vagrant for this kind of sandbox testing.

To use this fabfile, you should first install fabric and fabtools. The
requirements file provided in this directory will let you do this easily by
typing e.g.

sudo pip install requirements.txt

To install vagrant, download the latest version from
http://downloads.vagrantup.com/ (use the packages they provide rather than
apt as the ubuntu package is old).

Assuming you are using a vagrant sandbox, you can use the Vagrantfile
supplied with this repo to create your vagrant box. Note that there is a
one time download of around 400mb to add the base image to your boxes
collection. This command will initialise your vagrant sandbox.

vagrant up

Now you are ready to run your first fabgis task! Lets install QGIS master
and PostgreSQL into our vagrant sandbox!

fab vagrant build_server

Now go off and have a cup of tea, when it is done your vagrant box should
have everything set up. If you would like to try out your new QGIS you
could do something like this:

ssh localhost -p 2222 -X /usr/local/qgis-master/bin/qgis

That will run your newly built QGIS instance and forward the display back
to your local X-xerver.


Tim Sutton, Jan 2013
"""

# lcd = local cd
# You can also make generic tasks available at the command line simply by
# importing them. e.g.
#from fabgis.sphinx import setup_sphinx

# For vagrant support you need to do this:
# noinspection PyUnresolvedReferences


@task
def ls():
    """Simply list the directory on the remote server."""
    run('pwd')
    run('ls')


@task
def build_server():
    """Build a complete functioning FOSSGIS server instance.

    Notes:

    The installed server will have QGIS from master set up on it and postgres
    installed with postgis and a template spatial database created. A default
    database called 'gis' will be created too.

        e.g.

            fab -H root@foo create_user
            fab -H foo build_server

        You need to run the create_user task separately to bootstrap the
        creation of your user on the remote host.
    """
    build_proj4()
    build_hdf5()

    create_postgis_1_5_db('gis')