diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..e0d5f5a7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +docs/ +tests/ diff --git a/cookiecutter.json b/cookiecutter.json index c04ca5c99..2360b9cd0 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -12,8 +12,10 @@ "add_pyup_badge": "n", "command_line_interface": ["Click", "Argparse", "No command-line interface"], "create_author_file": "y", - "open_source_license": ["MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "GNU General Public License v3", "Not open source"], + "open_source_license": ["Apache Software License 2.0", "MIT license", "BSD license", "ISC license", "GNU General Public License v3", "Not open source"], "port_digits": "94", "http_port": "80{{ cookiecutter.port_digits }}", - "https_port": "280{{ cookiecutter.port_digits }}" + "https_port": "280{{ cookiecutter.port_digits }}", + "_copy_without_render": [ + "{{cookiecutter.project_slug}}/templates/*.cfg", } diff --git a/{{cookiecutter.project_slug}}/Dockerfile b/{{cookiecutter.project_slug}}/Dockerfile index 5e98604e6..2a5800c22 100644 --- a/{{cookiecutter.project_slug}}/Dockerfile +++ b/{{cookiecutter.project_slug}}/Dockerfile @@ -1,47 +1,33 @@ # vim:set ft=dockerfile: -FROM birdhouse/bird-base:latest +FROM continuumio/miniconda3 MAINTAINER https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }} +LABEL Description="{{ cookiecutter.project_slug }} WPS" Vendor="Birdhouse" Version="{{ cookiecutter.version }}" -LABEL Description="{{ cookiecutter.project_slug }} WPS" Vendor="Birdhouse" +# Update Debian system +RUN apt-get update && apt-get install -y \ + build-essential \ +&& rm -rf /var/lib/apt/lists/* -# Configure hostname and ports for services -ENV HTTP_PORT 5000 -ENV OUTPUT_PORT 8000 -ENV HOSTNAME localhost +# Update conda +RUN conda update -n base conda -# Set current home -ENV HOME /root +# Copy WPS project +COPY . /opt/wps -# Copy application sources -COPY . /opt/birdhouse/src/{{ cookiecutter.project_slug }} +WORKDIR /opt/wps -# cd into application -WORKDIR /opt/birdhouse/src/{{ cookiecutter.project_slug }} +# Create conda environment +RUN conda env create -n wps -f environment.yml -# Provide custom.cfg with settings for docker image -COPY .docker.cfg custom.cfg +# Install WPS +RUN ["/bin/bash", "-c", "source activate wps && python setup.py develop"] -# Install system dependencies -RUN bash bootstrap.sh -i +# Start WPS service on port {{ cookiecutter.http_port }} on 0.0.0.0 +EXPOSE {{ cookiecutter.http_port }} +ENTRYPOINT ["/bin/bash", "-c"] +CMD ["source activate wps && exec emu --config /opt/wps/etc/demo.cfg"] -# Set conda enviroment -ENV ANACONDA_HOME /opt/conda -ENV CONDA_ENVS_DIR /opt/conda/envs - -# Run install and fix permissions -RUN make clean install && chmod 755 /opt/birdhouse/etc && chmod 755 /opt/birdhouse/var/run - -# Volume for data, cache, logfiles, ... -VOLUME /opt/birdhouse/var/lib -VOLUME /opt/birdhouse/var/log -# Volume for configs -VOLUME /opt/birdhouse/etc - -# Ports used in birdhouse -EXPOSE $HTTP_PORT $OUTPUT_PORT - -# Start supervisor in foreground -ENV DAEMON_OPTS --nodaemon - -# Start service ... -CMD ["make", "update-config", "start"] +# docker build -t {{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }} . +# docker run -p {{ cookiecutter.http_port }}:{{ cookiecutter.http_port }} {{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }} +# http://localhost:{{ cookiecutter.http_port }}/wps?request=GetCapabilities&service=WPS +# http://localhost:{{ cookiecutter.http_port }}/wps?request=DescribeProcess&service=WPS&identifier=all&version=1.0.0 diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.project_slug}}/Makefile index 482b54065..225fa623b 100644 --- a/{{cookiecutter.project_slug}}/Makefile +++ b/{{cookiecutter.project_slug}}/Makefile @@ -20,9 +20,6 @@ BUILDOUT_VERSION := 2.11 # Anaconda ANACONDA_HOME ?= $(HOME)/anaconda CONDA_ENV ?= $(APP_NAME) -CONDA_ENVS_DIR ?= $(HOME)/.conda/envs -CONDA_ENV_PATH := $(CONDA_ENVS_DIR)/$(CONDA_ENV) -CONDA_PINNED := $(APP_ROOT)/requirements/conda_pinned # Configuration used by update-config HOSTNAME ?= localhost @@ -32,16 +29,14 @@ OUTPUT_PORT ?= 8090 # choose anaconda installer depending on your OS ANACONDA_URL = https://repo.continuum.io/miniconda ifeq "$(OS_NAME)" "Linux" -FN := Miniconda2-latest-Linux-x86_64.sh +FN := Miniconda3-latest-Linux-x86_64.sh else ifeq "$(OS_NAME)" "Darwin" -FN := Miniconda2-latest-MacOSX-x86_64.sh +FN := Miniconda3-latest-MacOSX-x86_64.sh else FN := unknown endif -# Buildout files and folders -DOWNLOAD_CACHE := $(APP_ROOT)/downloads -BUILDOUT_FILES := parts eggs develop-eggs bin .installed.cfg .mr.developer.cfg *.egg-info bootstrap-buildout.py *.bak.* $(DOWNLOAD_CACHE) +TEMP_FILES := *.egg-info *.log *.sqlite # Docker DOCKER_IMAGE := birdhouse/$(APP_NAME) @@ -49,8 +44,7 @@ DOCKER_CONTAINER := $(APP_NAME) # end of configuration -.PHONY: clean clean-test clean-pyc clean-build docs help -.DEFAULT_GOAL := help +.DEFAULT_GOAL := all define BROWSER_PYSCRIPT import os, webbrowser, sys @@ -207,73 +201,42 @@ anaconda: @echo "Installing Anaconda ..." @test -d $(ANACONDA_HOME) || curl $(ANACONDA_URL)/$(FN) --silent --insecure --output "$(DOWNLOAD_CACHE)/$(FN)" @test -d $(ANACONDA_HOME) || bash "$(DOWNLOAD_CACHE)/$(FN)" -b -p $(ANACONDA_HOME) - @echo "Add '$(ANACONDA_HOME)/bin' to your PATH variable in '.bashrc'." - -.PHONY: conda_config -conda_config: anaconda - @echo "Update ~/.condarc" - @-"$(ANACONDA_HOME)/bin/conda" install -y conda=$(CONDA_VERSION) requests - @"$(ANACONDA_HOME)/bin/conda" config --add envs_dirs $(CONDA_ENVS_DIR) - @"$(ANACONDA_HOME)/bin/conda" config --set ssl_verify true - @"$(ANACONDA_HOME)/bin/conda" config --set use_pip true - @"$(ANACONDA_HOME)/bin/conda" config --set channel_priority true - @"$(ANACONDA_HOME)/bin/conda" config --set auto_update_conda false - @"$(ANACONDA_HOME)/bin/conda" config --add channels defaults - @"$(ANACONDA_HOME)/bin/conda" config --append channels birdhouse - @"$(ANACONDA_HOME)/bin/conda" config --append channels conda-forge + @echo "Please add '$(ANACONDA_HOME)/bin' to your PATH variable in '.bashrc'." .PHONY: conda_env -conda_env: anaconda conda_config - @echo "Update conda environment $(CONDA_ENV) ..." - @test -d $(CONDA_ENV_PATH) || "$(ANACONDA_HOME)/bin/conda" env create -n $(CONDA_ENV) -f environment.yml - "$(ANACONDA_HOME)/bin/conda" install -y -n $(CONDA_ENV) setuptools=$(SETUPTOOLS_VERSION) - -.PHONY: conda_pinned -conda_pinned: conda_env - @echo "Update pinned conda packages ..." - @-test -d $(CONDA_ENV_PATH) && test -f $(CONDA_PINNED) && cp -f "$(CONDA_PINNED)" "$(CONDA_ENV_PATH)/conda-meta/pinned" - -.PHONY: export -export: - @echo "Exporting conda enviroment ..." - @test -d $(CONDA_ENV_PATH) && "$(ANACONDA_HOME)/bin/conda" env export -n $(CONDA_ENV) -f environment.yml +conda_env: anaconda + @echo "Updating conda environment $(CONDA_ENV) ..." + "$(ANACONDA_HOME)/bin/conda" env update -n $(CONDA_ENV) -f environment.yml ## Build targets .PHONY: bootstrap -bootstrap: init conda_env conda_pinned bootstrap-buildout.py - @echo "Bootstrap buildout ..." - @test -f bin/buildout || bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);python bootstrap-buildout.py -c custom.cfg --allow-site-packages --setuptools-version=$(SETUPTOOLS_VERSION) --buildout-version=$(BUILDOUT_VERSION)" +bootstrap: conda_env bootstrap_dev + @echo "Bootstrap ..." -.PHONY: sysinstall -sysinstall: - @echo "\nInstalling system packages for bootstrap ..." - @bash bootstrap.sh -i - @echo "\nInstalling system packages for your application ..." - @-test -f requirements.sh && bash requirements.sh +.PHONY: bootstrap_dev +bootstrap_dev: + @echo "Installing development requirements for tests and docs ..." + @-bash -c "$(ANACONDA_HOME)/bin/conda install -y -n $(CONDA_ENV) pytest flake8 sphinx" + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && pip install -r requirements_dev.txt" .PHONY: install install: bootstrap - @echo "Installing application with buildout ..." - @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);bin/buildout buildout:anaconda-home=$(ANACONDA_HOME) -c custom.cfg" + @echo "Installing application..." + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && python setup.py develop" @echo "\nStart service with \`make start'" -.PHONY: update -update: - @echo "Update application config with buildout (offline mode) ..." - @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);bin/buildout buildout:anaconda-home=$(ANACONDA_HOME) -o -c custom.cfg" - -.PHONY: update-config -update-config: - @echo "Update application config with buildout (offline mode) and environment variables..." - @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);bin/buildout buildout:anaconda-home=$(ANACONDA_HOME) settings:hostname=$(HOSTNAME) settings:output-port=$(OUTPUT_PORT) settings:http-port=$(HTTP_PORT) -o -c custom.cfg" +.PHONY: start +start: + @echo "Starting application ..." + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && $(APP_NAME) -a -d" .PHONY: clean clean: srcclean envclean - @echo "Cleaning buildout files ..." - @-for i in $(BUILDOUT_FILES); do \ - test -e $$i && rm -v -rf $$i; \ - done + @echo "Cleaning generated files ..." + @-for i in $(TEMP_FILES); do \ + test -e $$i && rm -v -rf $$i; \ + done .PHONY: envclean envclean: stop @@ -286,10 +249,10 @@ srcclean: @-find $(APP_ROOT) -type f -name "*.pyc" -print | xargs rm .PHONY: distclean -distclean: backup clean - @echo "Cleaning distribution ..." +distclean: clean + @echo "Cleaning ..." @git diff --quiet HEAD || echo "There are uncommited changes! Not doing 'git clean' ..." - @-git clean -dfx -e *.bak -e custom.cfg -e Makefile.config + @-git clean -dfx -e *.bak -e custom.cfg .PHONY: passwd passwd: custom.cfg @@ -302,22 +265,24 @@ passwd: custom.cfg .PHONY: test test: @echo "Running tests (skip slow and online tests) ..." - bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV); bin/py.test -v -m 'not slow and not online'" + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);pytest -v -m 'not slow and not online'" .PHONY: testall testall: @echo "Running all tests (including slow and online tests) ..." - bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV); bin/py.test -v" + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && pytest -v" .PHONY: pep8 pep8: @echo "Running pep8 code style checks ..." - $(CONDA_ENV_PATH)/bin/flake8 + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && flake8" + +## Sphinx targets .PHONY: docs docs: @echo "Generating docs with Sphinx ..." - $(MAKE) -C $@ clean html + @-bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV);$(MAKE) -C $@ clean html" @echo "open your browser: firefox docs/build/html/index.html" .PHONY: linkcheck diff --git a/{{cookiecutter.project_slug}}/Makefile.config.example b/{{cookiecutter.project_slug}}/Makefile.config.example deleted file mode 100644 index fccdcaa54..000000000 --- a/{{cookiecutter.project_slug}}/Makefile.config.example +++ /dev/null @@ -1,3 +0,0 @@ -# Anaconda -ANACONDA_HOME ?= /opt/anaconda -CONDA_ENVS_DIR ?= /opt/anaconda/envs diff --git a/{{cookiecutter.project_slug}}/bootstrap.sh b/{{cookiecutter.project_slug}}/bootstrap.sh deleted file mode 100755 index 8f4dc1c0e..000000000 --- a/{{cookiecutter.project_slug}}/bootstrap.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -usage() { - cat <`_ and run as the installation user. +Install from GitHub +------------------- -Now, check out the {{ cookiecutter.project_slug }} code from GitHub and start the installation: +Check out code from the {{ cookiecutter.project_name }} GitHub repo and start the installation: .. code-block:: sh $ git clone https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }}.git $ cd {{ cookiecutter.project_slug }} - $ make clean install + $ conda env create -f environment.yml + $ source activate {{ cookiecutter.project_slug }} + $ python setup.py develop -After successful installation you need to start the services: +Install the lazy way +-------------------- + +The previous installation instructions assume you have Anaconda installed. +We provide also a ``Makefile`` to run this installation without additional steps: .. code-block:: sh - $ make start # starts supervisor services - $ make status # shows supervisor status + $ git clone https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }}.git + $ cd {{ cookiecutter.project_slug }} + $ make clean # cleans up a previous Conda environment + $ make install # installs Conda if necessary and runs the above installation steps -The depolyed WPS service is by default available on http://localhost:{{ cookiecutter.http_port }}/wps?service=WPS&version=1.0.0&request=GetCapabilities. +Start {{ cookiecutter.project_name }} PyWPS service +----------------------- -Check the log files for errors: +After successful installation you can start the service using the ``{{ cookiecutter.project_slug }}`` command-line. .. code-block:: sh - $ tail -f ~/birdhouse/var/log/pywps/{{ cookiecutter.project_slug }}.log - $ tail -f ~/birdhouse/var/log/supervisor/{{ cookiecutter.project_slug }}.log + $ {{ cookiecutter.project_slug }} --help # show help + $ {{ cookiecutter.project_slug }} # start service with default configuration -You will find more information about the installation in the `Makefile documentation `_. + OR -Non-default installation ------------------------- + $ {{ cookiecutter.project_slug }} --daemon # start service as daemon + loading configuration + forked process id: 42 -You can customize the installation to use different ports, locations and run user. +The deployed WPS service is by default available on: -To change the anaconda location edit the ``Makefile.config``, for example:: +http://localhost:{{ cookiecutter.http_port }}/wps?service=WPS&version=1.0.0&request=GetCapabilities. - ANACONDA_HOME ?= /opt/anaconda - CONDA_ENVS_DIR ?= /opt/anaconda/envs +.. NOTE:: Remember the process ID (PID) so you can stop the service with ``kill PID``. -You can install {{ cookiecutter.project_slug }} as ``root`` and run it as unprivileged user like ``www-data``: +Check the log files for errors: .. code-block:: sh - root$ mkdir -p /opt/birdhouse/src - root$ cd /opt/birdhouse/src - root$ git clone https://github.com/bird-house/{{ cookiecutter.project_slug }}.git - root$ cd {{ cookiecutter.project_slug }} + $ tail -f pywps.log -Edit ``custom.cfg``: +Run {{ cookiecutter.project_name }} as Docker container +--------------------------- -.. code-block:: ini +You can also run {{ cookiecutter.project_name }} as a Docker container, see the :ref:`Tutorial `. - [buildout] - extends = buildout.cfg - - [settings] - hostname = {{ cookiecutter.project_slug }} - http-port = 80 - output-port = 8000 - log-level = WARN - - # deployment options - prefix = /opt/birdhouse - user = www-data - etc-user = root - -Run the installtion and start the services: - -.. code-block:: sh +Use Ansible to deploy {{ cookiecutter.project_name }} on your System +---------------------------------------- - root$ make clean install - root$ make start # stop or restart - root$ make status +Use the `Ansible playbook`_ for PyWPS to deploy {{ cookiecutter.project_name }} on your system. +Follow the `example`_ for {{ cookiecutter.project_name }} given in the playbook. -.. _Anaconda: https://www.continuum.io/ +.. _Ansible playbook: http://ansible-wps-playbook.readthedocs.io/en/latest/index.html +.. _example: http://ansible-wps-playbook.readthedocs.io/en/latest/tutorial.html diff --git a/{{cookiecutter.project_slug}}/environment.yml b/{{cookiecutter.project_slug}}/environment.yml index 7882d0566..41f2d88b7 100644 --- a/{{cookiecutter.project_slug}}/environment.yml +++ b/{{cookiecutter.project_slug}}/environment.yml @@ -4,32 +4,6 @@ channels: - conda-forge - defaults dependencies: -- python=2.7 -- pyopenssl=0.16 -- cryptography=1.4 -- pyyaml=3.11 -- curl=7.45.0 -- icu=58 -# buildout -- mako -# tests -- pytest -# pep8 -- flake8 -# py2/3 compat -- six -# docs -- sphinx -- doc8 -# wps -- pywps=4.0.0 -- click=6 -- nginx=1.10.3 -- supervisor=3.3 -- gunicorn=19 -- lxml -- libxslt -- genshi=0.7 -- pip: - - sphinx-autoapi==0.5.0 - - -e git+https://github.com/huard/sphinx-autodoc-pywps.git#egg=sphinx_autodoc_pywps +- pywps=4.1.0 +- jinja2 +- click diff --git a/{{cookiecutter.project_slug}}/etc/debug.cfg b/{{cookiecutter.project_slug}}/etc/debug.cfg new file mode 100644 index 000000000..c00a2b7ff --- /dev/null +++ b/{{cookiecutter.project_slug}}/etc/debug.cfg @@ -0,0 +1,2 @@ +[logging] +level = DEBUG diff --git a/{{cookiecutter.project_slug}}/etc/demo.cfg b/{{cookiecutter.project_slug}}/etc/demo.cfg new file mode 100644 index 000000000..52145a38e --- /dev/null +++ b/{{cookiecutter.project_slug}}/etc/demo.cfg @@ -0,0 +1,2 @@ +[logging] +level = WARN diff --git a/{{cookiecutter.project_slug}}/etc/sample-custom.cfg b/{{cookiecutter.project_slug}}/etc/sample-custom.cfg new file mode 100644 index 000000000..e708743cd --- /dev/null +++ b/{{cookiecutter.project_slug}}/etc/sample-custom.cfg @@ -0,0 +1,6 @@ +[server] +url = http://demo.org:{{ cookiecutter.http_port }}/wps +outputurl = http://demo.org:{{ cookiecutter.http_port }}/outputs + +[logging] +level = DEBUG diff --git a/{{cookiecutter.project_slug}}/etc/sample-postgres.cfg b/{{cookiecutter.project_slug}}/etc/sample-postgres.cfg new file mode 100644 index 000000000..a16b9049f --- /dev/null +++ b/{{cookiecutter.project_slug}}/etc/sample-postgres.cfg @@ -0,0 +1,3 @@ +[logging] +level = INFO +database = postgresql+psycopg2://postgres:postgres@localhost:5432/postgres diff --git a/{{cookiecutter.project_slug}}/requirements.txt b/{{cookiecutter.project_slug}}/requirements.txt index bc7979b5f..3a41542b5 100644 --- a/{{cookiecutter.project_slug}}/requirements.txt +++ b/{{cookiecutter.project_slug}}/requirements.txt @@ -1,3 +1,3 @@ pywps>=4.0.0 -werkzeug +jinja2 click diff --git a/{{cookiecutter.project_slug}}/setup.py b/{{cookiecutter.project_slug}}/setup.py index 38db9171e..7e9ad3bcc 100644 --- a/{{cookiecutter.project_slug}}/setup.py +++ b/{{cookiecutter.project_slug}}/setup.py @@ -17,10 +17,10 @@ test_requirements = [{%- if cookiecutter.use_pytest == 'y' %}'pytest>=3',{%- endif %} ] {%- set license_classifiers = { + 'Apache Software License 2.0': 'License :: OSI Approved :: Apache Software License', 'MIT license': 'License :: OSI Approved :: MIT License', 'BSD license': 'License :: OSI Approved :: BSD License', 'ISC license': 'License :: OSI Approved :: ISC License (ISCL)', - 'Apache Software License 2.0': 'License :: OSI Approved :: Apache Software License', 'GNU General Public License v3': 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)' } %} diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py index 6e541cca1..3c61e94bb 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/__init__.py @@ -1,7 +1,7 @@ """Top-level package for {{ cookiecutter.project_name }}.""" from .wsgi import application -from .cli import main +from .cli import cli __author__ = """{{ cookiecutter.full_name }}""" __email__ = '{{ cookiecutter.email }}' diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/cli.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/cli.py index 2d1bb23cf..7c20e32f3 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/cli.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/cli.py @@ -1,5 +1,11 @@ """Console script for {{cookiecutter.project_slug}}.""" +########################################################### +# Demo WPS service for testing and debugging. +# +# See the werkzeug documentation on how to use the debugger: +# http://werkzeug.pocoo.org/docs/0.12/debug/ +########################################################### import os import sys @@ -9,6 +15,7 @@ {%- if cookiecutter.command_line_interface|lower == 'click' %} import click {%- endif %} +from jinja2 import Environment, PackageLoader, select_autoescape from pywps import configuration from . import wsgi @@ -18,12 +25,24 @@ logging.basicConfig(format='%(message)s', level=logging.INFO) LOGGER = logging.getLogger('DEMO') +template_env = Environment( + loader=PackageLoader('{{ cookiecutter.project_slug }}', 'templates'), + autoescape=select_autoescape(['yml', 'xml']) +) + +def write_user_config(**kwargs): + config_templ = template_env.get_template('pywps.cfg') + rendered_config = config_templ.render(**kwargs) + config_file = os.path.abspath(os.path.join(os.path.curdir, "custom.cfg")) + with open(config_file, 'w') as fp: + fp.write(rendered_config) + return config_file def get_host(): url = configuration.get_config_value('server', 'url') - url = url or 'http://localhost:5000/wps' + url = url or 'http://localhost:{{ cookiecutter.http_port }}/wps' - LOGGER.warn("starting WPS service on %s", url) + LOGGER.warn("starting WPS service on %s" % url) parsed_url = urlparse(url) if ':' in parsed_url.netloc: @@ -48,63 +67,66 @@ def _run(application, bind_host=None, daemon=False): hostname=bind_host, port=port, application=application, - use_debugger=True, - use_reloader=True, + use_debugger=False, + use_reloader=False, + threaded=True, + # processes=2, use_evalex=not daemon, static_files=static_files) {% if cookiecutter.command_line_interface|lower == 'click' %} @click.command() -def main(args=None): - """Console script for {{cookiecutter.project_slug}}.""" - click.echo("Replace this message by putting your code into " - "{{cookiecutter.project_slug}}.cli.main") - click.echo("See click documentation at https://click.palletsprojects.com/") - return 0 -{%- endif %} -{%- if cookiecutter.command_line_interface|lower == 'argparse' %} -def main(): - parser = argparse.ArgumentParser( - description="""Script for starting a demo WPS instance. - This service is by default available at http://localhost:5000/wps""", - epilog="""Do not use this service in a production environment. - It's intended to be running in a test environment only! - For more documentation, visit http://bird-house.github.io/ - """ - ) - parser.add_argument('--debug', - action="store_true", help="enable debug logging mode") - parser.add_argument('-c', '--config', - help="path to pywps configuration file") - parser.add_argument('-a', '--all-addresses', - action='store_true', help="run service using IPv4 0.0.0.0 (all network interfaces), " - "otherwise bind to 127.0.0.1 (localhost).") - parser.add_argument('-d', '--daemon', - action='store_true', help="run in daemon mode") - args = parser.parse_args() +@click.option('--config', metavar='PATH', help='path to pywps configuration file.') +@click.option('--bind-host', metavar='IP-ADDRESS', default='0.0.0.0', + help='IP address used to bind service.') +@click.option('--daemon/--no-daemon', default=False, help='run in daemon mode.') +@click.option('--hostname', metavar='HOSTNAME', default='localhost', help='hostname in PyWPS configuration.') +@click.option('--port', metavar='PORT', default='{{ cookiecutter.http_port }}', help='port in PyWPS configuration.') +@click.option('--maxsingleinputsize', default='200mb', help='maxsingleinputsize in PyWPS configuration.') +@click.option('--maxprocesses', metavar='INT', default='10', help='maxprocesses in PyWPS configuration.') +@click.option('--parallelprocesses', metavar='INT', default='2', help='parallelprocesses in PyWPS configuration.') +@click.option('--log-level', metavar='LEVEL', default='INFO', help='log level in PyWPS configuration.') +@click.option('--log-file', metavar='PATH', default='pywps.log', help='log file in PyWPS configuration.') +@click.option('--database', default='sqlite:///pywps-logs.sqlite', help='database in PyWPS configuration') +def cli(config, bind_host, daemon, hostname, port, + maxsingleinputsize, maxprocesses, parallelprocesses, + log_level, log_file, database): + """Command line for starting a PyWPS service. + This service is by default available at http://localhost:{{ cookiecutter.http_port }}/wps + + Do not use this service in a production environment. + It's intended to be running in a test environment only! + For more documentation, visit http://pywps.org/doc + """ cfgfiles = [] - if args.config: - cfgfiles.append(args.config) - LOGGER.warn('using pywps configuration: %s', args.config) - if args.debug: - cfgfiles.append(os.path.join(os.path.dirname(__file__), 'debug.cfg')) - if args.all_addresses: - bind_host = '0.0.0.0' - else: - bind_host = '127.0.0.1' + cfgfiles.append(write_user_config( + wps_hostname=hostname, + wps_port=port, + wps_maxsingleinputsize=maxsingleinputsize, + wps_maxprocesses=maxprocesses, + wps_parallelprocesses=parallelprocesses, + wps_log_level=log_level, + wps_log_file=log_file, + wps_database=database, + )) + if config: + cfgfiles.append(config) app = wsgi.create_app(cfgfiles) # let's start the service ... - if args.daemon: + # See: + # * https://github.com/geopython/pywps-flask/blob/master/demo.py + # * http://werkzeug.pocoo.org/docs/0.14/serving/ + if daemon: # daemon (fork) mode pid = None try: pid = os.fork() if pid: - LOGGER.warn('forked process id: %s', pid) + LOGGER.warn('forked process id: {}'.format(pid)) except OSError as e: raise Exception("%s [%d]" % (e.strerror, e.errno)) - if (pid == 0): + if pid == 0: os.setsid() _run(app, bind_host=bind_host, daemon=True) else: @@ -113,7 +135,3 @@ def main(): # no daemon _run(app, bind_host=bind_host) {%- endif %} - - -if __name__ == "__main__": - sys.exit(main()) # pragma: no cover diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/default.cfg b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/default.cfg index e94bdb8cd..1bc7f1bc4 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/default.cfg +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/default.cfg @@ -7,12 +7,12 @@ provider_name = {{ cookiecutter.project_name }} provider_url=http://{{ cookiecutter.project_slug }}.readthedocs.org/en/latest/ [server] -url = http://localhost:5000/wps -outputurl = http://localhost:5000/outputs +url = http://localhost:{{ cookiecutter.http_port }}/wps +outputurl = http://localhost:{{ cookiecutter.http_port }}/outputs allowedinputpaths = / maxsingleinputsize = 200mb -sethomedir = true -setworkdir = true +maxprocesses = 10 +parallelprocesses = 2 [logging] level = INFO diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/pywps.cfg b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/pywps.cfg new file mode 100644 index 000000000..20951f8ae --- /dev/null +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/pywps.cfg @@ -0,0 +1,27 @@ +[server] +{% if wps_url %} +url = {{ wps_url }} +{% else %} +url = http://{{ wps_hostname }}:{{ wps_port }}/wps +{% endif %} +{% if wps_outputurl %} +outputurl = {{ wps_outputurl }} +{% else %} +outputurl = http://{{ wps_hostname }}:{{ wps_port }}/outputs +{% endif %} +allowedinputpaths = / +maxsingleinputsize = {{ wps_maxsingleinputsize|default('200mb') }} +maxprocesses = {{ wps_maxprocesses|default('10') }} +parallelprocesses = {{ wps_parallelprocesses|default('2') }} +{% if wps_outputpath %} +outputpath= {{ wps_outputpath }} +{% endif %} +{% if wps_workdir %} +workdir={{ wps_workdir }} +{% endif %} + +[logging] +level = {{ wps_log_level|default('INFO') }} +file = {{ wps_log_file|default('pywps.log') }} +database = {{ wps_database|default('sqlite:///pywps-logs.sqlite') }} +format = %(asctime)s] [%(levelname)s] line=%(lineno)s module=%(module)s %(message)s