Skip to content

Instantly share code, notes, and snippets.

@gannebamm
Created February 25, 2021 14:45
Show Gist options
  • Save gannebamm/3db48be57e4532c6ef852bb0fb215cb6 to your computer and use it in GitHub Desktop.
Save gannebamm/3db48be57e4532c6ef852bb0fb215cb6 to your computer and use it in GitHub Desktop.
merged docker-composition from geonode-project into geonode core codebase. added changed nginx to use own certificates instead of letsenscrypt. added LDAP stubs and example production yml and .env.
diff --git a/.env b/.env
index ff474f6fab48be7c5c576135b0a99b493230433f..88dd61182fac0265d15345409b3780b1d51b9762 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,203 @@
COMPOSE_PROJECT_NAME=geonode
-SET_DOCKER_ENV=production
\ No newline at end of file
+BACKUPS_VOLUME_DRIVER=local
+
+DOCKER_HOST_IP=
+DOCKER_ENV=production
+# See https://github.com/geosolutions-it/geonode-generic/issues/28
+# to see why we force API version to 1.24
+DOCKER_API_VERSION="1.24"
+
+C_FORCE_ROOT=1
+IS_CELERY=false
+IS_FIRST_START=true
+FORCE_REINIT=false
+
+SITEURL=http://localhost/
+ALLOWED_HOSTS=['django',]
+
+# LANGUAGE_CODE=pt
+# LANGUAGES=(('en','English'),('pt','Portuguese'))
+
+GEONODE_INSTANCE_NAME=geonode
+DJANGO_SETTINGS_MODULE=geonode.settings
+UWSGI_CMD=uwsgi --ini /usr/src/geonode/uwsgi.ini
+
+# #################
+# backend
+# #################
+GEONODE_DATABASE=geonode
+GEONODE_DATABASE_PASSWORD=geonode
+GEONODE_GEODATABASE=geonode_data
+GEONODE_GEODATABASE_PASSWORD=geonode
+
+DATABASE_URL=postgis://geonode:geonode@db:5432/geonode
+GEODATABASE_URL=postgis://geonode_data:geonode@db:5432/geonode_data
+DEFAULT_BACKEND_DATASTORE=datastore
+BROKER_URL=amqp://guest:guest@rabbitmq:5672/
+ASYNC_SIGNALS=True
+
+# #################
+# geoserver
+# #################
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+GEOSERVER_WEB_UI_LOCATION=http://localhost/geoserver/
+GEOSERVER_PUBLIC_LOCATION=http://localhost/geoserver/
+GEOSERVER_LOCATION=http://geoserver:8080/geoserver/
+GEOSERVER_ADMIN_USER=admin
+GEOSERVER_ADMIN_PASSWORD=geoserver
+
+OGC_REQUEST_TIMEOUT=30
+OGC_REQUEST_MAX_RETRIES=1
+OGC_REQUEST_BACKOFF_FACTOR=0.3
+OGC_REQUEST_POOL_MAXSIZE=10
+OGC_REQUEST_POOL_CONNECTIONS=10
+
+# Java Options & Memory
+ENABLE_JSONP=true
+outFormat=text/javascript
+GEOSERVER_JAVA_OPTS=-Djava.awt.headless=true -Xms2G -Xmx4G -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:PerfDataSamplingInterval=500 -XX:SoftRefLRUPolicyMSPerMB=36000 -XX:-UseGCOverheadLimit -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -DALLOW_ENV_PARAMETRIZATION=true -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine
+
+# Data Uploader
+DEFAULT_BACKEND_UPLOADER=geonode.importer
+TIME_ENABLED=True
+MOSAIC_ENABLED=False
+
+# #################
+# Jenkins
+# CI/CD Server
+# #################
+JENKINS_HTTP_PORT=9080
+JENKINS_HTTPS_PORT=9443
+
+# #################
+# nginx
+# HTTPD Server
+# #################
+GEONODE_LB_HOST_IP=localhost
+GEONODE_LB_PORT=80
+
+# IP or domain name and port where the server can be reached on HTTPS (leave HOST empty if you want to use HTTP only)
+# port where the server can be reached on HTTPS
+HTTP_HOST=localhost
+HTTPS_HOST=
+
+HTTP_PORT=80
+HTTPS_PORT=443
+
+# Let's Encrypt certificates for https encryption. You must have a domain name as HTTPS_HOST (doesn't work
+# with an ip) and it must be reachable from the outside. This can be one of the following :
+# disabled : we do not get a certificate at all (a placeholder certificate will be used)
+# staging : we get staging certificates (are invalid, but allow to test the process completely and have much higher limit rates)
+# production : we get a normal certificate (default)
+LETSENCRYPT_MODE=disabled
+# LETSENCRYPT_MODE=staging
+# LETSENCRYPT_MODE=production
+
+RESOLVER=127.0.0.11
+
+# #################
+# Security
+# #################
+# Admin Settings
+ADMIN_USERNAME=admin
+ADMIN_PASSWORD=admin
+ADMIN_EMAIL=admin@localhost
+
+# EMAIL Notifications
+EMAIL_ENABLE=False
+DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
+DJANGO_EMAIL_HOST=localhost
+DJANGO_EMAIL_PORT=25
+DJANGO_EMAIL_HOST_USER=
+DJANGO_EMAIL_HOST_PASSWORD=
+DJANGO_EMAIL_USE_TLS=False
+DJANGO_EMAIL_USE_SSL=False
+DEFAULT_FROM_EMAIL='GeoNode <no-reply@geonode.org>'
+
+# Session/Access Control
+LOCKDOWN_GEONODE=False
+CORS_ORIGIN_ALLOW_ALL=True
+X_FRAME_OPTIONS=ALLOW-FROM ALL
+SESSION_EXPIRED_CONTROL_ENABLED=True
+DEFAULT_ANONYMOUS_VIEW_PERMISSION=True
+DEFAULT_ANONYMOUS_DOWNLOAD_PERMISSION=True
+
+# Users Registration
+ACCOUNT_OPEN_SIGNUP=True
+ACCOUNT_EMAIL_REQUIRED=True
+ACCOUNT_APPROVAL_REQUIRED=False
+ACCOUNT_CONFIRM_EMAIL_ON_GET=False
+ACCOUNT_EMAIL_VERIFICATION=none
+ACCOUNT_EMAIL_CONFIRMATION_EMAIL=False
+ACCOUNT_EMAIL_CONFIRMATION_REQUIRED=False
+ACCOUNT_AUTHENTICATION_METHOD=username_email
+AUTO_ASSIGN_REGISTERED_MEMBERS_TO_REGISTERED_MEMBERS_GROUP_NAME=False
+
+# OAuth2
+OAUTH2_API_KEY=
+OAUTH2_CLIENT_ID=Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV
+OAUTH2_CLIENT_SECRET=rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3
+
+# GeoNode APIs
+API_LOCKDOWN=False
+TASTYPIE_APIKEY=
+
+# #################
+# Production and
+# Monitoring
+# #################
+DEBUG=False
+
+SECRET_KEY='myv-y4#7j-d*p-__@j#*3z@!y24fz8%^z2v6atuy4bo9vqr1_a'
+
+STATIC_ROOT=/mnt/volumes/statics/static/
+MEDIA_ROOT=/mnt/volumes/statics/uploaded/
+GEOIP_PATH=/mnt/volumes/statics/geoip.db
+
+CACHE_BUSTING_STATIC_ENABLED=False
+CACHE_BUSTING_MEDIA_ENABLED=False
+
+MEMCACHED_ENABLED=True
+MEMCACHED_BACKEND=django.core.cache.backends.memcached.MemcachedCache
+MEMCACHED_LOCATION=127.0.0.1:11211
+MEMCACHED_LOCK_EXPIRE=3600
+MEMCACHED_LOCK_TIMEOUT=10
+
+MAX_DOCUMENT_SIZE=2
+CLIENT_RESULTS_LIMIT=5
+API_LIMIT_PER_PAGE=1000
+
+# GIS Client
+GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY=mapstore
+MAPBOX_ACCESS_TOKEN=
+BING_API_KEY=
+GOOGLE_API_KEY=
+
+# Monitoring
+MONITORING_ENABLED=True
+MONITORING_DATA_TTL=365
+USER_ANALYTICS_ENABLED=True
+USER_ANALYTICS_GZIP=True
+CENTRALIZED_DASHBOARD_ENABLED=False
+MONITORING_SERVICE_NAME=local-geonode
+MONITORING_HOST_NAME=geonode
+
+# Other Options/Contribs
+MODIFY_TOPICCATEGORY=True
+AVATAR_GRAVATAR_SSL=True
+AVATAR_PROVIDERS='avatar.providers.PrimaryAvatarProvider','avatar.providers.GravatarAvatarProvider','avatar.providers.DefaultAvatarProvider'
+EXIF_ENABLED=True
+CREATE_LAYER=True
+FAVORITE_ENABLED=True
+
+# LDAP
+LDAP_ENABLED=False
+LDAP_SERVER_URL=ldap://<the_ldap_server>
+LDAP_BIND_DN=uid=ldapinfo,cn=users,dc=ad,dc=example,dc=org
+LDAP_BIND_PASSWORD=<something_secret>
+LDAP_USER_SEARCH_DN=dc=ad,dc=example,dc=org
+LDAP_USER_SEARCH_FILTERSTR=(&(uid=%(user)s)(objectClass=person))
+LDAP_GROUP_SEARCH_DN=cn=groups,dc=ad,dc=example,dc=org
+LDAP_GROUP_SEARCH_FILTERSTR=(|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6))
+LDAP_GROUP_PROFILE_MEMBER_ATTR=uniqueMember
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index e1dcc3dfecc6756d85cd8629dca2ec7533c6c939..d8c032aefb6d0418bad49616f01d08c9b3a0cc68 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,17 +1,69 @@
-FROM geonode/geonode:3.1
+FROM python:3.8.3-buster
LABEL GeoNode development team
+## is aligned with geonode-project Dockerfile
-COPY requirements.txt /usr/src/app/
+RUN mkdir -p /usr/src/geonode
+
+# Enable postgresql-client-11.2
+RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
+RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
+
+# This section is borrowed from the official Django image but adds GDAL and others
+RUN apt-get update && apt-get install -y \
+ libpq-dev python-dev libxml2-dev \
+ libxml2 libxslt1-dev zlib1g-dev libjpeg-dev \
+ libmemcached-dev libldap2-dev libsasl2-dev libffi-dev
+
+RUN apt-get update && apt-get install -y \
+ gcc zip gettext geoip-bin cron \
+ postgresql-client-11 \
+ sqlite3 spatialite-bin libsqlite3-mod-spatialite \
+ python3-gdal python3-psycopg2 python3-ldap \
+ python3-pip python3-pil python3-lxml python3-pylibmc \
+ python3-dev libgdal-dev \
+ uwsgi uwsgi-plugin-python3 \
+ --no-install-recommends && rm -rf /var/lib/apt/lists/*
+
+# add bower and grunt command
+COPY . /usr/src/geonode/
+WORKDIR /usr/src/geonode
+
+COPY monitoring-cron /etc/cron.d/monitoring-cron
+RUN chmod 0644 /etc/cron.d/monitoring-cron
+RUN crontab /etc/cron.d/monitoring-cron
+RUN touch /var/log/cron.log
+RUN service cron start
+
+COPY wait-for-databases.sh /usr/bin/wait-for-databases
+RUN chmod +x /usr/bin/wait-for-databases
+RUN chmod +x /usr/src/geonode/tasks.py \
+ && chmod +x /usr/src/geonode/entrypoint.sh
+
+COPY celery.sh /usr/bin/celery-commands
+RUN chmod +x /usr/bin/celery-commands
+
+# Prepraing dependencies
+RUN apt-get update && apt-get install -y devscripts build-essential debhelper pkg-kde-tools sharutils
+# RUN git clone https://salsa.debian.org/debian-gis-team/proj.git /tmp/proj
+# RUN cd /tmp/proj && debuild -i -us -uc -b && dpkg -i ../*.deb
+
+# Install pip packages
RUN pip install pip --upgrade
-RUN pip install -r requirements.txt --upgrade
+RUN pip install --upgrade --no-cache-dir --src /usr/src -r requirements.txt \
+ && pip install pygdal==$(gdal-config --version).* \
+ && pip install flower==0.9.4
-WORKDIR /usr/src/geonode/
-RUN git pull
-RUN pip install -e . --upgrade
+RUN pip install --upgrade -e .
-RUN python manage.py makemigrations --settings=geonode.settings
-RUN python manage.py migrate --settings=geonode.settings
+# Activate "memcached"
+RUN apt install memcached
+RUN pip install pylibmc \
+ && pip install sherlock
-EXPOSE 8000
+# Install "geonode-contribs" apps
+RUN cd /usr/src; git clone https://github.com/GeoNode/geonode-contribs.git -b master
+# Install logstash and centralized dashboard dependencies
+RUN cd /usr/src/geonode-contribs/geonode-logstash; pip install --upgrade -e . \
+ cd /usr/src/geonode-contribs/ldap; pip install --upgrade -e .
-ENTRYPOINT service cron restart && /usr/src/app/entrypoint.sh
+ENTRYPOINT service cron restart && service memcached restart && /usr/src/geonode/entrypoint_ti.sh
\ No newline at end of file
diff --git a/celery.sh b/celery.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2bc4c8b3970230a8351103ca935ac5f5770dc87c
--- /dev/null
+++ b/celery.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+nohup celery -A geonode.celery_app:app beat -l DEBUG -f /var/log/celery.log &>/dev/null &
+nohup celery -A geonode.celery_app:app worker -B -E --statedb=worker.state -s celerybeat-schedule --loglevel=INFO --concurrency=10 -n worker1@%h -f /var/log/celery.log &>/dev/null &
+nohup celery -A geonode.celery_app:app flower --auto_refresh=True --debug=False --broker=${BROKER_URL} --basic_auth=${ADMIN_USERNAME}:${ADMIN_PASSWORD} --address=0.0.0.0 --port=5555 &>/dev/null &
\ No newline at end of file
diff --git a/docker/geoserver/Dockerfile b/docker/geoserver/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..bb56f6e5fc75613e596a7efaa2b54087445fd650
--- /dev/null
+++ b/docker/geoserver/Dockerfile
@@ -0,0 +1,108 @@
+FROM tomcat:9-jre8
+MAINTAINER GeoNode Development Team
+
+#
+# Set GeoServer version and data directory
+#
+ENV GEOSERVER_VERSION=2.17.2
+ENV GEOSERVER_DATA_DIR="/geoserver_data/data"
+
+#
+# Download and install GeoServer
+#
+RUN cd /usr/local/tomcat/webapps \
+ && wget --no-check-certificate --progress=bar:force:noscroll https://www.dropbox.com/s/bdl6p64cuh4xu33/geoserver-${GEOSERVER_VERSION}.war?dl=1 -O geoserver-${GEOSERVER_VERSION}.war \
+ && unzip -q geoserver-${GEOSERVER_VERSION}.war -d geoserver \
+ && rm geoserver-${GEOSERVER_VERSION}.war \
+ && mkdir -p $GEOSERVER_DATA_DIR
+
+VOLUME $GEOSERVER_DATA_DIR
+
+# added by simonelanucara https://github.com/simonelanucara
+# Optionally add JAI, ImageIO and Marlin Render for improved Geoserver performance
+WORKDIR /tmp
+ARG JAI_IMAGEIO=true
+RUN if [ "$JAI_IMAGEIO" = true ]; then \
+ # marlin plugin
+ wget https://github.com/bourgesl/marlin-renderer/releases/download/v0_9_3/marlin-0.9.3-Unsafe.jar && \
+ mv /tmp/marlin-0.9.3-Unsafe.jar /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/ ; \
+ fi
+
+RUN wget --no-check-certificate https://www.dropbox.com/s/psolxleimaft0t7/postgis-jdbc-1.3.3.jar?dl=1 -O postgis-jdbc-1.3.3.jar && \
+ wget --no-check-certificate https://www.dropbox.com/s/m9dpmfvp8p4iv2p/hibernate-spatial-postgis-1.1.3.1.jar?dl=1 -O hibernate-spatial-postgis-1.1.3.1.jar && \
+ rm /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/hibernate-spatial-h2-geodb-1.1.3.1.jar && \
+ mv hibernate-spatial-postgis-1.1.3.1.jar /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/ && \
+ mv postgis-jdbc-1.3.3.jar /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/
+
+###########docker host###############
+# Set DOCKERHOST variable if DOCKER_HOST exists
+ARG DOCKERHOST=${DOCKERHOST}
+# for debugging
+RUN echo -n #1===>DOCKERHOST=${DOCKERHOST}
+#
+ENV DOCKERHOST ${DOCKERHOST}
+# for debugging
+RUN echo -n #2===>DOCKERHOST=${DOCKERHOST}
+
+###########docker host ip#############
+# Set GEONODE_HOST_IP address if it exists
+ARG GEONODE_HOST_IP=${GEONODE_HOST_IP}
+# for debugging
+RUN echo -n #1===>GEONODE_HOST_IP=${GEONODE_HOST_IP}
+#
+ENV GEONODE_HOST_IP ${GEONODE_HOST_IP}
+# for debugging
+RUN echo -n #2===>GEONODE_HOST_IP=${GEONODE_HOST_IP}
+# If empty set DOCKER_HOST_IP to GEONODE_HOST_IP
+ENV DOCKER_HOST_IP=${DOCKER_HOST_IP:-${GEONODE_HOST_IP}}
+# for debugging
+RUN echo -n #1===>DOCKER_HOST_IP=${DOCKER_HOST_IP}
+# Trying to set the value of DOCKER_HOST_IP from DOCKER_HOST
+RUN if ! [ -z ${DOCKER_HOST_IP} ]; \
+ then echo export DOCKER_HOST_IP=${DOCKERHOST} | \
+ sed 's/tcp:\/\/\([^:]*\).*/\1/' >> /root/.bashrc; \
+ else echo "DOCKER_HOST_IP is already set!"; fi
+# for debugging
+RUN echo -n #2===>DOCKER_HOST_IP=${DOCKER_HOST_IP}
+
+# Set WEBSERVER public port
+ARG PUBLIC_PORT=${PUBLIC_PORT}
+# for debugging
+RUN echo -n #1===>PUBLIC_PORT=${PUBLIC_PORT}
+#
+ENV PUBLIC_PORT=${PUBLIC_PORT}
+# for debugging
+RUN echo -n #2===>PUBLIC_PORT=${PUBLIC_PORT}
+
+# set nginx base url for geoserver
+RUN echo export NGINX_BASE_URL=http://${NGINX_HOST}:${NGINX_PORT}/ | \
+ sed 's/tcp:\/\/\([^:]*\).*/\1/' >> /root/.bashrc
+
+# copy the script and perform the run of scripts from entrypoint.sh
+RUN mkdir -p /usr/local/tomcat/tmp
+WORKDIR /usr/local/tomcat/tmp
+COPY set_geoserver_auth.sh /usr/local/tomcat/tmp
+COPY setup_auth.sh /usr/local/tomcat/tmp
+COPY requirements.txt /usr/local/tomcat/tmp
+COPY get_dockerhost_ip.py /usr/local/tomcat/tmp
+COPY get_nginxhost_ip.py /usr/local/tomcat/tmp
+COPY entrypoint.sh /usr/local/tomcat/tmp
+COPY datasource-ovr.properties /usr/local/tomcat/tmp
+COPY multidump.sh /usr/local/tomcat/tmp
+COPY multidump-alt.sh /usr/local/tomcat/tmp
+
+RUN apt-get update \
+ && apt-get -y upgrade \
+ && apt-get install -y openjdk-8-jdk \
+ && apt-get install -y python3 python3-pip python3-dev \
+ && chmod +x /usr/local/tomcat/tmp/set_geoserver_auth.sh \
+ && chmod +x /usr/local/tomcat/tmp/setup_auth.sh \
+ && chmod +x /usr/local/tomcat/tmp/entrypoint.sh \
+ && pip3 install pip==9.0.3 \
+ && pip3 install -r requirements.txt \
+ && chmod +x /usr/local/tomcat/tmp/get_dockerhost_ip.py \
+ && chmod +x /usr/local/tomcat/tmp/get_nginxhost_ip.py
+
+ENV JAVA_OPTS="-Djava.awt.headless=true -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:MaxPermSize=512m -XX:PermSize=256m -Xms512m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3-Unsafe.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine"
+
+CMD ["/usr/local/tomcat/tmp/entrypoint.sh"]
diff --git a/docker/geoserver/README.md b/docker/geoserver/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..352ccb253f3452c33402b9b971b43304b764f3ff
--- /dev/null
+++ b/docker/geoserver/README.md
@@ -0,0 +1,128 @@
+# geoserver-docker
+
+[GeoServer](http://geoserver.org) is an open source server for sharing geospatial data.
+This is a docker image that eases setting up a GeoServer running specifically for [GeoNode](https://github.com/GeoNode/geoserver-geonode-ext) with an additional separated data directory.
+
+The image is based on the official Tomcat 9 image
+
+## Installation
+
+This image is available as a [trusted build on the docker hub](https://registry.hub.docker.com/r/geonode/geoserver/), and is the recommended method of installation.
+Simple pull the image from the docker hub.
+
+```bash
+$ docker pull geonode/geoserver
+```
+
+Alternatively you can build the image locally
+
+```bash
+$ git clone https://github.com/geonode/geoserver-docker.git
+$ cd geoserver-docker
+$ docker build -t "geonode/geoserver" .
+```
+
+## Quick start
+
+You can quick start the image using the command line
+
+```bash
+$ docker run --name "geoserver" -v /var/run/docker.sock:/var/run/docker.sock -d -p 8080:8080 geonode/geoserver
+```
+
+Point your browser to `http://localhost:8080/geoserver` and login using GeoServer's default username and password:
+
+* Username: admin
+* Password: geoserver
+
+## How to use different versions
+
+There are mainly two different versions of this image which are useful for running **GeoNode** with different authentication system types. These versions are released as specific tags for two authentication mechanisms:
+
+**Cookie based authn**:
+- [geonode/geoserver:2.9.x](https://hub.docker.com/r/geonode/geoserver/builds/bx7ydhghnlrfnsppduyva73/)
+
+**Oauth2 based authn**:
+- [geonode/geoserver:2.9.x-oauth2](https://hub.docker.com/r/geonode/geoserver/builds/bwca5rtexeoegzgroavftdr/)
+- [geonode/geoserver:2.10.x](https://hub.docker.com/r/geonode/geoserver/builds/bjohcnc29vm69acqjrvndxf/)
+- [geonode/geoserver:2.12.x](https://hub.docker.com/r/geonode/geoserver/builds/bh7pyw5atmkcljurwsnzbs7/)
+- [geonode/geoserver:2.13.x](https://hub.docker.com/r/geonode/geoserver/builds/btmjctbuvrjfnnrxrs4wyrs/)
+- [geonode/geoserver:2.14.x](https://hub.docker.com/r/geonode/geoserver/builds/bj53pi8he8uksz6ggvrs3wc/)
+
+You can declare what version to use along with the data directory tag which corresponds to the same version.
+
+## Configuration
+
+### Data volume
+
+This GeoServer container keeps its configuration data at `/geoserver_data/data` which is exposed as volume in the dockerfile.
+The volume allows for stopping and starting new containers from the same image without losing all the data and custom configuration.
+
+You may want to map this volume to a directory on the host. It will also ease the upgrade process in the future. Volumes can be mounted by passing the `-v` flag to the docker run command:
+
+```bash
+-v /your/host/data/path:/geoserver_data/data
+```
+
+### Data volume container
+
+In case you are running Compose for automatically having GeoServer up and running then a data volume container will be mounted with a default preloaded *GEOSERVER_DATA_DIR* at the configuration data directory of the container.
+Make sure that the image from the repository [data-docker](https://github.com/GeoNode/data-docker) is available from the [GeoNode Docker Hub](https://hub.docker.com/u/geonode/) or has been built locally:
+
+```bash
+docker build -t geonode/geoserver_data .
+```
+
+#### Persistance behavior
+
+If you run:
+
+```bash
+docker-compose stop
+```
+
+Data are retained in the *GEOSERVER_DATA_DIR* and can then be mounted in a new GeoServer instance by running again:
+
+```bash
+docker-compose up
+```
+
+If you run:
+
+```bash
+docker-compose down
+```
+
+Data are completely gone but you can ever start from the base GeoServer Data Directory built for Geonode.
+
+#### Data directory versions
+
+There has to be a correspondence one-to-one between the data directory version and the tag of the GeoServer image used in the Docker compose file. So at the end you can consume these images below:
+
+* **2.9.x**: [geonode/geoserver_data:2.9.x](https://hub.docker.com/r/geonode/geoserver_data/builds/bsus6alnddg4bc7icwymevp/)
+* **2.9.x-oauth2**: [geonode/geoserver_data:2.9.x-oauth2](https://hub.docker.com/r/geonode/geoserver_data/builds/bwkxcupsunvuitzusi9gsnt/)
+* **2.10.x**: [geonode/geoserver_data:2.10.x](https://hub.docker.com/r/geonode/geoserver_data/builds/b5jqhpzapkqxzyevjizccug/)
+* **2.12.x**: [geonode/geoserver_data:2.12.x](https://hub.docker.com/r/geonode/geoserver_data/builds/byaaalw3lnasunpveyg3x4i/)
+* **2.13.x**: [geonode/geoserver_data:2.13.x](https://hub.docker.com/r/geonode/geoserver_data/builds/bunuqzq7a7dk65iumjhkbtc/)
+* **2.14.x**: [geonode/geoserver_data:2.14.x](https://hub.docker.com/r/geonode/geoserver_data/builds/blpdjzkrv7pm3stunzpn4pp/)
+
+### Database
+
+GeoServer recommends the usage of a spatial database
+
+#### PostGIS container (PostgreSQL + GIS Extension)
+
+If you want to use a [PostGIS](http://postgis.org/) container, you can link it to this image. You're free to use any PostGIS container.
+An example with [kartooza/postgis](https://registry.hub.docker.com/u/kartoza/postgis/) image:
+
+```bash
+$ docker run -d --name="postgis" kartoza/postgis
+```
+
+For further information see [kartooza/postgis](https://registry.hub.docker.com/u/kartoza/postgis/).
+
+Now start the GeoServer instance by adding the `--link` option to the docker run command:
+
+```bash
+--link postgis:postgis
+```
diff --git a/docker/geoserver/datasource-ovr.properties b/docker/geoserver/datasource-ovr.properties
new file mode 100644
index 0000000000000000000000000000000000000000..b78d3616c265f80524e4423be700d76e688ccf3e
--- /dev/null
+++ b/docker/geoserver/datasource-ovr.properties
@@ -0,0 +1,6 @@
+geofenceVendorAdapter.databasePlatform=org.hibernatespatial.postgis.PostgisDialect
+geofenceDataSource.driverClassName=org.postgresql.Driver
+geofenceDataSource.url=jdbc:postgresql://db:5432/geonode_data
+geofenceDataSource.username=geonode_data
+geofenceDataSource.password=geonode
+geofenceEntityManagerFactory.jpaPropertyMap[hibernate.default_schema]=public
diff --git a/docker/geoserver/docker-compose.yml b/docker/geoserver/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6ebed4ab04f4417392e1207c30f0c14392d0ed4e
--- /dev/null
+++ b/docker/geoserver/docker-compose.yml
@@ -0,0 +1,44 @@
+version: '2.2'
+
+services:
+
+ geoserver:
+ image: geonode/geoserver:2.17.2
+ build:
+ context: .
+ args:
+ - DOCKERHOST
+ - GEONODE_HOST_IP
+ - PUBLIC_PORT=80
+ links:
+ - postgis
+ ports:
+ - "8080:8080"
+ volumes:
+ - /geoserver_data/data
+ environment:
+ - DOCKERHOST
+ - GEONODE_HOST_IP
+ - PUBLIC_PORT=80
+ - DOCKER_HOST_IP
+ - DJANGO_URL=http://localhost/
+
+ data_dir_conf:
+ image: geonode/geoserver_data:2.17.2
+ container_name: geoserver_data_dir # named data container
+ command: /bin/true
+ volumes:
+ - /geoserver_data/data
+
+ postgis:
+ image: geonode/postgis
+ ports:
+ - "25432:5432"
+ volumes:
+ - /srv/docker/geoserver/postgis:/var/lib/postgresql
+ #volumes_from:
+ #- pgstore
+
+volumes:
+ # reference to the named data container that holds the preloaded geoserver data directory
+ geoserver_data_dir:
diff --git a/docker/geoserver/entrypoint.sh b/docker/geoserver/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1dda7f4164b6d2646f119b0005819679d465d927
--- /dev/null
+++ b/docker/geoserver/entrypoint.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+set -e
+
+source /root/.bashrc
+
+# control the value of DOCKER_HOST_IP variable
+if [ -z ${DOCKER_HOST_IP} ]
+then
+
+ echo "DOCKER_HOST_IP is empty so I'll run the python utility \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+ echo export DOCKER_HOST_IP=`python3 /usr/local/tomcat/tmp/get_dockerhost_ip.py` >> /root/.override_env
+ echo "The calculated value is now DOCKER_HOST_IP='$DOCKER_HOST_IP' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+else
+
+ echo "DOCKER_HOST_IP is filled so I'll leave the found value '$DOCKER_HOST_IP' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+fi
+
+# control the values of LB settings if present
+if [ ${GEONODE_LB_HOST_IP} ]
+then
+
+ echo "GEONODE_LB_HOST_IP is filled so I replace the value of '$DOCKER_HOST_IP' with '$GEONODE_LB_HOST_IP' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+ echo export DOCKER_HOST_IP=${GEONODE_LB_HOST_IP} >> /root/.override_env
+
+fi
+
+if [ ${GEONODE_LB_PORT} ]
+then
+
+ echo "GEONODE_LB_PORT is filled so I replace the value of '$PUBLIC_PORT' with '$GEONODE_LB_PORT' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+ echo export PUBLIC_PORT=${GEONODE_LB_PORT} >> /root/.override_env
+
+fi
+
+if [ ! -z "${GEOSERVER_JAVA_OPTS}" ]
+then
+
+ echo "GEOSERVER_JAVA_OPTS is filled so I replace the value of '$JAVA_OPTS' with '$GEOSERVER_JAVA_OPTS' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+ JAVA_OPTS=${GEOSERVER_JAVA_OPTS}
+
+fi
+
+# control the value of NGINX_BASE_URL variable
+if [ -z `echo ${NGINX_BASE_URL} | sed 's/http:\/\/\([^:]*\).*/\1/'` ]
+then
+ echo "NGINX_BASE_URL is empty so I'll use the static nginx hostname \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+ # echo export NGINX_BASE_URL=`python3 /usr/local/tomcat/tmp/get_nginxhost_ip.py` >> /root/.override_env
+ # TODO rework get_nginxhost_ip to get URL with static hostname from nginx service name
+ # + exposed port of that container i.e. http://geonode:80
+ echo export NGINX_BASE_URL=http://geonode:80 >> /root/.override_env
+ echo "The calculated value is now NGINX_BASE_URL='$NGINX_BASE_URL' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+else
+ echo "NGINX_BASE_URL is filled so I'll leave the found value '$NGINX_BASE_URL' \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+fi
+
+# set basic tagname
+TAGNAME=( "baseUrl" )
+
+if ! [ -f ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ]
+then
+
+ echo "Configuration file '$GEOSERVER_DATA_DIR'/security/auth/geonodeAuthProvider/config.xml is not available so it is gone to skip \n" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+else
+
+ # backup geonodeAuthProvider config.xml
+ cp ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml.orig
+ # run the setting script for geonodeAuthProvider
+ /usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/ ${TAGNAME} >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+fi
+
+# backup geonode REST role service config.xml
+cp "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml.orig"
+# run the setting script for geonode REST role service
+/usr/local/tomcat/tmp/set_geoserver_auth.sh "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/" ${TAGNAME} >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+# set oauth2 filter tagname
+TAGNAME=( "accessTokenUri" "userAuthorizationUri" "redirectUri" "checkTokenEndpointUrl" "logoutUri" )
+
+# backup geonode-oauth2 config.xml
+cp ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml.orig
+# run the setting script for geonode-oauth2
+/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/ "${TAGNAME[@]}" >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+# set global tagname
+TAGNAME=( "proxyBaseUrl" )
+
+# backup global.xml
+cp ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/global.xml.orig
+# run the setting script for global configuration
+/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/ ${TAGNAME} >> /usr/local/tomcat/tmp/set_geoserver_auth.log
+
+# set correct amqp broker url
+sed -i -e 's/localhost/rabbitmq/g' ${GEOSERVER_DATA_DIR}/notifier/notifier.xml
+
+# exclude wrong dependencies
+sed -i -e 's/xom-\*\.jar/xom-\*\.jar,bcprov\*\.jar/g' /usr/local/tomcat/conf/catalina.properties
+
+# enable geofence-datasource to Postgis
+cp /usr/local/tomcat/tmp/datasource-ovr.properties ${GEOSERVER_DATA_DIR}/geofence/geofence-datasource-ovr.properties
+
+# start tomcat
+exec env JAVA_OPTS="${JAVA_OPTS}" catalina.sh run
diff --git a/docker/geoserver/get_dockerhost_ip.py b/docker/geoserver/get_dockerhost_ip.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b5a42ed3104628b8e5561bda42d1d2c5e41a25b
--- /dev/null
+++ b/docker/geoserver/get_dockerhost_ip.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+import logging
+
+import docker
+
+BOOTSTRAP_IMAGE_CHEIP = 'codenvy/che-ip:nightly'
+# AF: why call before definition? print _docker_host_ip()
+
+def _docker_host_ip():
+ client = docker.from_env()
+ ip_list = client.containers.run(BOOTSTRAP_IMAGE_CHEIP,
+ network_mode='host'
+ ).split("\n")
+ if len(ip_list) > 1:
+ logging.info("Docker daemon is running on more than one \
+address {0}".format(ip_list))
+ logging.info("Only the first address:{0} will be returned!".format(
+ ip_list[0]
+ ))
+ else:
+ logging.info("Docker daemon is running at the following \
+address {0}".format(ip_list[0]))
+ return ip_list[0]
diff --git a/docker/geoserver/get_nginxhost_ip.py b/docker/geoserver/get_nginxhost_ip.py
new file mode 100644
index 0000000000000000000000000000000000000000..c6a67d8490d991a642e340cdef1ea169a61bc281
--- /dev/null
+++ b/docker/geoserver/get_nginxhost_ip.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+
+import logging
+import os
+
+import docker
+
+client = docker.from_env()
+# print(client.info())
+# TODO avoid this script can fail and fall in the loop where the geoserver
+# service is not available and consequently the nginx too which has geoserver
+# as a reference link
+for network in client.networks.list():
+ if 'geonode' in network.name:
+ geonode_network = network.name
+ else:
+ geonode_network = 'geonode_default'
+
+try:
+ containers = {
+ c.attrs['Config']['Image']: c.attrs['NetworkSettings']['\
+Networks'][geonode_network]['\
+IPAddress'] for c in client.containers.list() if c.status in 'running'
+ }
+ for item in containers.items():
+ if "geonode/nginx" in item[0]:
+ ipaddr = item[1]
+
+ try:
+ os.environ["NGINX_BASE_URL"] = "http://" + ipaddr + ":" + "80"
+ nginx_base_url = "http://{}:80".format(ipaddr)
+ except NameError as er:
+ logging.info("NGINX container is not running maybe exited! Running\
+containers are:{0}".format(containers))
+except KeyError as ke:
+ logging.info("There has been a problem with the docker\
+network which has raised the following exception: {0}".format(ke))
+else:
+ # nginx_base_url = None
+ pass
+finally:
+ try:
+ print(nginx_base_url)
+ except NameError as ne:
+ print("http://geonode:80")
diff --git a/docker/geoserver/multidump-alt.sh b/docker/geoserver/multidump-alt.sh
new file mode 100644
index 0000000000000000000000000000000000000000..cc237e17bec8a2155d0a65b69f0172310e64af23
--- /dev/null
+++ b/docker/geoserver/multidump-alt.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+if [ $# -ne 3 ]; then
+ echo "Usage: $0 pid interval count"
+ exit 1
+fi
+
+PID=$1
+INTERVAL=$2
+COUNT=$3
+
+top -bH -d $INTERVAL -n $COUNT -p $PID >> top.out 2>&1 &
+for i in `seq $COUNT`; do
+ kill -3 $PID
+ sleep $INTERVAL
+done
diff --git a/docker/geoserver/multidump.sh b/docker/geoserver/multidump.sh
new file mode 100644
index 0000000000000000000000000000000000000000..21dfd2ba6609d06148b86331f3fada66dfdcaffa
--- /dev/null
+++ b/docker/geoserver/multidump.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if [ $# -ne 3 ]; then
+ echo "Usage: $0 pid interval count"
+ exit 1
+fi
+
+PID=$1
+INTERVAL=$2
+COUNT=$3
+
+top -bH -d $INTERVAL -n $COUNT -p $PID >> top.out 2>&1 &
+for i in `seq $COUNT`; do
+ echo "stack trace $i of $COUNT" >> jstack.out
+ jstack -l $PID >> jstack.out
+ echo "--------------------" >> jstack.out
+ sleep $INTERVAL
+done
diff --git a/docker/geoserver/requirements.txt b/docker/geoserver/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b31242fdae7241919b80d00c6dab068a930e8b3
--- /dev/null
+++ b/docker/geoserver/requirements.txt
@@ -0,0 +1 @@
+docker==3.1.1
diff --git a/docker/geoserver/set_geoserver_auth.sh b/docker/geoserver/set_geoserver_auth.sh
new file mode 100644
index 0000000000000000000000000000000000000000..27dd11ef54e341f4d3f93f0e36fc25cbcdf97b4d
--- /dev/null
+++ b/docker/geoserver/set_geoserver_auth.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+auth_conf_source="$1"
+auth_conf_target="$2"
+# Creating a temporary file for sed to write the changes to
+temp_file="xml.tmp"
+touch $temp_file
+
+source /root/.bashrc
+source /root/.override_env
+
+test -z "$auth_conf_source" && echo "You must specify a source file" && exit 1
+test -z "$auth_conf_target" && echo "You must specify a target conf directory" && exit 1
+
+test ! -f "$auth_conf_source" && echo "Source $auth_conf_source does not exist or is not a file" && exit 1
+test ! -d "$auth_conf_target" && echo "Target directory $auth_conf_target does not exist or is not a directory" && exit 1
+
+# for debugging
+echo -e "NGINX_BASE_URL=${NGINX_BASE_URL}\n"
+if [ "$PUBLIC_PORT" == "443" ]; then
+ SUBSTITUTION_URL="https://${DOCKER_HOST_IP}"
+ if [ "$PUBLIC_PORT" != "443" ]; then
+ SUBSTITUTION_URL="https://${DOCKER_HOST_IP}:${PUBLIC_PORT}"
+ fi
+else
+ SUBSTITUTION_URL="http://${DOCKER_HOST_IP}"
+ if [ "$PUBLIC_PORT" != "80" ]; then
+ SUBSTITUTION_URL="http://${DOCKER_HOST_IP}:${PUBLIC_PORT}"
+ fi
+fi
+
+echo -e "SUBSTITUTION_URL=$SUBSTITUTION_URL\n"
+echo -e "auth_conf_source=$auth_conf_source\n"
+echo -e "auth_conf_target=$auth_conf_target\n"
+
+# Elegance is the key -> adding an empty last line for Mr. “sed” to pick up
+echo " " >> "$auth_conf_source"
+
+cat "$auth_conf_source"
+
+tagname=( ${@:3:5} )
+
+# for debugging
+for i in "${tagname[@]}"
+do
+ echo "tagname=<$i>"
+done
+
+echo "DEBUG: Starting... [Ok]\n"
+
+for i in "${tagname[@]}"
+do
+ echo "DEBUG: Working on '$auth_conf_source' for tagname <$i>"
+ # Extracting the value from the <$tagname> element
+ # echo -ne "<$i>$tagvalue</$i>" | xmlstarlet sel -t -m "//a" -v . -n
+ tagvalue=`grep "<$i>.*<.$i>" "$auth_conf_source" | sed -e "s/^.*<$i/<$i/" | cut -f2 -d">"| cut -f1 -d"<"`
+
+ echo "DEBUG: Found the current value for the element <$i> - '$tagvalue'"
+
+ # Setting new substituted value
+ case $i in
+ proxyBaseUrl )
+ if [ ${GEONODE_LB_HOST_IP} ]
+ then
+ echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$SUBSTITUTION_URL'"
+ newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$SUBSTITUTION_URL@"`
+ else
+ echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$NGINX_BASE_URL'"
+ newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$NGINX_BASE_URL@"`
+ fi;;
+ accessTokenUri | checkTokenEndpointUrl | baseUrl )
+ echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$NGINX_BASE_URL'"
+ newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$NGINX_BASE_URL@"`;;
+ userAuthorizationUri | redirectUri | logoutUri )
+ echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$SUBSTITUTION_URL'"
+ newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$SUBSTITUTION_URL@"`;;
+ *) echo -n "an unknown variable has been found";;
+ esac
+
+ echo "DEBUG: Found the new value for the element <$i> - '$newvalue'"
+ # Replacing element’s value with $SUBSTITUTION_URL
+ # echo -ne "<$i>$tagvalue</$i>" | xmlstarlet sel -t -m "//a" -v . -n
+ sed -e "s@<$i>$tagvalue<\/$i>@<$i>$newvalue<\/$i>@g" "$auth_conf_source" > "$temp_file"
+ cp "$temp_file" "$auth_conf_source"
+done
+# Writing our changes back to the original file ($auth_conf_source)
+# no longer needed
+# mv $temp_file $auth_conf_source
+
+echo "DEBUG: Finished... [Ok] --- Final xml file is \n"
+cat "$auth_conf_source"
diff --git a/docker/geoserver/setup_auth.sh b/docker/geoserver/setup_auth.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6f9373b978cb7a8ec2626f5a6f3081d5570b7d9f
--- /dev/null
+++ b/docker/geoserver/setup_auth.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+sed -i.bak 's@<baseUrl>\([^<][^<]*\)</baseUrl>@<baseUrl>'"$DJANGO_URL"'</baseUrl>@'\
+ /geoserver_data/data/security/auth/geonodeAuthProvider/config.xml
\ No newline at end of file
diff --git a/docker/jenkins/.env b/docker/jenkins/.env
new file mode 100644
index 0000000000000000000000000000000000000000..c49c4da4f4c699fd3402ea3cf0dc7a7eaa1320f6
--- /dev/null
+++ b/docker/jenkins/.env
@@ -0,0 +1,3 @@
+COMPOSE_PROJECT_NAME=geonode_jenkins
+JENKINS_HTTP_PORT=9080
+JENKINS_HTTPS_PORT=9443
diff --git a/docker/jenkins/README.md b/docker/jenkins/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4f17d9f2a5b9ece6a062a9021f206041b122c0c2
--- /dev/null
+++ b/docker/jenkins/README.md
@@ -0,0 +1,94 @@
+Docker Composer Setup
+=====================
+
+> How to easily get Jenkins with the Blue Ocean UI up and running on your computer using `docker` and `docker-compose`
+
+## How to use:
+
+0. - Install [Docker and Docker Compose](https://www.docker.com/community-edition) for your OS.
+
+ + For Windows OS without Hyper-V Capability
+ + Install Docker toolbox (https://docs.docker.com/toolbox/toolbox_install_windows/)
+ + Once installed you might need to remove the line `"credsStore": "wincred"` from `~/.docker/config.json`
+ + Execute all command using `Docker Quickstart Terminal`
+
+1. In your directory, copy `.env.sample` to `.env` and customize as needed. In particular, change `JENKINS_HTTP_PORT` and `JENKINS_HTTPS_PORT` to a high port (e.g. 18443) on Minikube.
+
+2. Run docker-compose to bring up Jenkins
+
+```sh
+$ docker-compose up -d
+```
+
+3. Get your initial admin password
+
+```sh
+$ docker-compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
+```
+
+4. Open Jenkins in your browser by going to either http://0.0.0.0:8080/ or https://0.0.0.0:8443/ (or whatever your Docker Machine IP is).
+
+5. Enter your initial admin password when the setup wizard asks you to.
+
+![Start the setup wizard by entering the intial admin password](images/jenkins-unlock.png)
+
+6. Choose `Install suggested plugins`
+
+![Jenkins Install Options](images/jenkins-install.png)
+
+![Jenkins is Installing](images/jenkins-setup.png)
+
+7. Enter your admin user details and click `Save and Finish`
+
+![Jenkins Admin User Setup](images/jenkins-admin-user.png)
+
+8. Click `Open Blue Ocean` from the left hand menu
+
+![Blue Ocean](images/jenkins-blue-ocean.png)
+
+> Congratulations! You may now use Jenkins with the Blue Ocean UI and the Jenkins Pipelines of 2.0
+
+## Troubleshooting
+
+#### Mounted volumes are empty
+
+This guide is for:
+- Windows users that did not meet the system requirements of __Docker for Windows__
+(You may check out the system requirements [here](https://docs.docker.com/docker-for-windows/install/#what-to-know-before-you-install))
+- Uses __Docker Toolbox__
+- Uses __Virtualbox__ for virtualization
+
+_Note: We will assume that your current working directory is at `D:\Projects\Jenkins`_
+_Note: All commands are executed inside the __Docker Quickstart Terminal___
+
+1. In your virtual machine, create a shared folder that has access to your working directory
+You may share `D:\Projects` instead of `D:\Projects\Jenkins`.
+Everything under `D:\Projects` will be accessible in the vm.
+
+ - Open Virtualbox
+ - Open the vm's settings
+ - Your vm's name is probably __default__
+ - You can see which machine is currently active by running `docker-machine ls`
+ The active machine should have an asterisk (`*`) on the `ACTIVE` column.
+ - Under _Shared Folders_ add a new entry
+ - If folder path is `D:\Projects`, folder name should be `d/Projects`
+ - Tick `Auto-mount`
+ - Tick `Make Permanent`
+
+![vm settings](images/vm_settings.png)
+
+sometimes, `Make Permanent` won't be an option. Don't bother looking for that if so, it'll still be fine. Auto-mount is what we want.
+
+2. If your vm is running, Restart your vm by executing `docker-machine restart`
+If your vm is stopped, you are either not executing these inside the _quickstart terminal_
+or you need to execute `docker-machine start <vm-name-here>`
+
+3. Verify the shared folder by logging in to the vm
+ - run `docker-machine ssh`
+ - run `ls /d/Projects`
+
+Now your containers should have access to your current folder.
+
+### NOTES
+- When setting up the `Folder Name` in the VM settings, assure that it's a valid linux path and must be relative to `/` (root) directory (eg `e/projects`).
+- The directory that contains `jenkins` **must not contain** any whitespaces or any characters that must be escaped. (e.g `F19 Source Code`, `Source\ Code`) The reason is that it'll serve as a `Folder Name` in your VM settings, and you cannot click OK when you do supply such names.
diff --git a/docker/jenkins/docker-compose.override.yml b/docker/jenkins/docker-compose.override.yml
new file mode 100644
index 0000000000000000000000000000000000000000..60bf7435db95ce0eb4223aa239965b53375d9306
--- /dev/null
+++ b/docker/jenkins/docker-compose.override.yml
@@ -0,0 +1,6 @@
+version: '2.2'
+services:
+
+ jenkins:
+ volumes:
+ - '/data/backup_restore:/backup_restore'
diff --git a/docker/jenkins/docker-compose.yml b/docker/jenkins/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bbe5ed75a1d90e4e634356296746648d1479fdff
--- /dev/null
+++ b/docker/jenkins/docker-compose.yml
@@ -0,0 +1,23 @@
+version: '2.2'
+services:
+ jenkins:
+ image: 'jenkins/jenkins:lts'
+ labels:
+ kompose.service.type: nodeport
+ ports:
+ - '${JENKINS_HTTP_PORT}:8080'
+ - '${JENKINS_HTTPS_PORT}:8443'
+ - '50000:50000'
+ volumes:
+ - 'jenkins_data:/var/jenkins_home'
+ - backup-restore:/backup_restore
+ env_file:
+ - .env
+ environment:
+ - 'JENKINS_OPTS=--httpPort=8080 --httpsPort=8443'
+
+volumes:
+ jenkins_data:
+ driver: local
+ backup-restore:
+ name: ${COMPOSE_PROJECT_NAME}-backup-restore
diff --git a/docker/jenkins/images/jenkins-admin-user.png b/docker/jenkins/images/jenkins-admin-user.png
new file mode 100644
index 0000000000000000000000000000000000000000..09ddb280b41abbeed7ad85932910962d620a4c89
Binary files /dev/null and b/docker/jenkins/images/jenkins-admin-user.png differ
diff --git a/docker/jenkins/images/jenkins-blue-ocean.png b/docker/jenkins/images/jenkins-blue-ocean.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb6fa974ecd36a58fcfea3053e36461bae9a0d3b
Binary files /dev/null and b/docker/jenkins/images/jenkins-blue-ocean.png differ
diff --git a/docker/jenkins/images/jenkins-install.png b/docker/jenkins/images/jenkins-install.png
new file mode 100644
index 0000000000000000000000000000000000000000..9c5e2013026f5e012420a0d1457ae45881227132
Binary files /dev/null and b/docker/jenkins/images/jenkins-install.png differ
diff --git a/docker/jenkins/images/jenkins-setup.png b/docker/jenkins/images/jenkins-setup.png
new file mode 100644
index 0000000000000000000000000000000000000000..077046dcd95c1465bfea0036ede4375e6df132b4
Binary files /dev/null and b/docker/jenkins/images/jenkins-setup.png differ
diff --git a/docker/jenkins/images/jenkins-unlock.png b/docker/jenkins/images/jenkins-unlock.png
new file mode 100644
index 0000000000000000000000000000000000000000..7af18e6261ed98d1c8e2d6d0dcebcc7e12181681
Binary files /dev/null and b/docker/jenkins/images/jenkins-unlock.png differ
diff --git a/docker/jenkins/images/vm_settings.png b/docker/jenkins/images/vm_settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..811e09bcfaa4d40c00c4b82fbc85dd838be27df8
Binary files /dev/null and b/docker/jenkins/images/vm_settings.png differ
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..a8e71f29a17296972fb3ef9e7f8b8bbf0155390f
--- /dev/null
+++ b/docker/nginx/Dockerfile
@@ -0,0 +1,15 @@
+FROM nginx:1.17.2-alpine
+
+RUN apk add --no-cache openssl inotify-tools
+
+WORKDIR /etc/nginx/
+
+ADD nginx.conf.envsubst nginx.https.available.conf.envsubst ./
+ADD geonode.conf.envsubst ./sites-enabled/
+
+ADD docker-autoreload.sh docker-entrypoint.sh /
+ENTRYPOINT ["/docker-entrypoint.sh"]
+RUN chmod +x /docker-autoreload.sh
+RUN chmod +x /docker-entrypoint.sh
+
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/docker/nginx/docker-autoreload.sh b/docker/nginx/docker-autoreload.sh
new file mode 100644
index 0000000000000000000000000000000000000000..65f3982e0f884330163898f886e8e298624eb00e
--- /dev/null
+++ b/docker/nginx/docker-autoreload.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# This will watch the /geonode-certificates folder and run nginx -s reload whenever there are some changes.
+# We use this to reload nginx config when certificates changed.
+
+# inspired/copied from https://github.com/kubernetes/kubernetes/blob/master/examples/https-nginx/auto-reload-nginx.sh
+
+while true
+do
+ inotifywait -e create -e modify -e delete -e move -r --exclude "\\.certbot\\.lock|\\.well-known" "/geonode-certificates/"
+ echo "Changes noticed in /geonode-certificates"
+
+ echo "Waiting 5s for additionnal changes"
+ sleep 5
+
+ echo "Creating symbolic link for WAN host"
+ # for some reason, the ln -f flag doesn't work below...
+ rm -f /certificate_symlink
+ if [ -f "/geonode-certificates/fullchain.pem" ] && [ -f "/geonode-certificates/privkey.pem" ]; then
+ echo "Certbot certificate exists, we symlink to the live cert"
+ ln -sf "/geonode-certificates/" /certificate_symlink
+ else
+ echo "Certbot certificate does not exist, we symlink to autoissued"
+ ln -sf "/geonode-certificates/autoissued" /certificate_symlink
+ fi
+
+ # Test nginx configuration
+ nginx -t
+ # If it passes, we reload
+ if [ $? -eq 0 ]
+ then
+ echo "Configuration valid, we reload..."
+ nginx -s reload
+ else
+ echo "Configuration not valid, we do not reload."
+ fi
+done
diff --git a/docker/nginx/docker-entrypoint.sh b/docker/nginx/docker-entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6fea5522d768b2243797a1ff65afff5b86edff59
--- /dev/null
+++ b/docker/nginx/docker-entrypoint.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# Exit script in case of error
+set -e
+
+echo $"\n\n\n"
+echo "-----------------------------------------------------"
+echo "STARTING NGINX ENTRYPOINT ---------------------------"
+date
+
+# We make the config dir
+mkdir -p "/geonode-certificates/$LETSENCRYPT_MODE"
+
+echo "Creating autoissued certificates for HTTP host"
+if [ ! -f "/geonode-certificates/autoissued/privkey.pem" ] || [[ $(find /geonode-certificates/autoissued/privkey.pem -mtime +365 -print) ]]; then
+ echo "Autoissued certificate does not exist or is too old, we generate one"
+ mkdir -p "/geonode-certificates/autoissued/"
+ openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout "/geonode-certificates/autoissued/privkey.pem" -out "/geonode-certificates/autoissued/fullchain.pem" -subj "/CN=${HTTP_HOST:-null}"
+else
+ echo "Autoissued certificate already exists"
+fi
+
+echo "Creating symbolic link for HTTPS certificate"
+# for some reason, the ln -f flag doesn't work below...
+# TODO : not DRY (reuse same scripts as docker-autoreload.sh)
+rm -f /certificate_symlink
+if [ -f "/geonode-certificates/fullchain.pem" ] && [ -f "/geonode-certificates/privkey.pem" ]; then
+ echo "Certbot certificate exists, we symlink to the live cert"
+ ln -sf "/geonode-certificates/" /certificate_symlink
+else
+ echo "Certbot certificate does not exist, we symlink to autoissued"
+ ln -sf "/geonode-certificates/autoissued" /certificate_symlink
+fi
+
+echo "Sanity checks on http/s ports configuration"
+if [ -z "${HTTP_PORT}" ]; then
+ HTTP_PORT=80
+fi
+if [ -z "${HTTPS_PORT}" ]; then
+ HTTPS_PORT=443
+fi
+if [ -z "${JENKINS_HTTP_PORT}" ]; then
+ JENKINS_HTTP_PORT=9080
+fi
+
+echo "Replacing environement variables"
+envsubst '\$HTTP_PORT \$HTTPS_PORT \$HTTP_HOST \$HTTPS_HOST \$RESOLVER' < /etc/nginx/nginx.conf.envsubst > /etc/nginx/nginx.conf
+envsubst '\$HTTP_PORT \$HTTPS_PORT \$HTTP_HOST \$HTTPS_HOST \$RESOLVER' < /etc/nginx/nginx.https.available.conf.envsubst > /etc/nginx/nginx.https.available.conf
+envsubst '\$HTTP_PORT \$HTTPS_PORT \$HTTP_HOST \$HTTPS_HOST \$JENKINS_HTTP_PORT' < /etc/nginx/sites-enabled/geonode.conf.envsubst > /etc/nginx/sites-enabled/geonode.conf
+
+echo "Enabling or not https configuration"
+if [ -z "${HTTPS_HOST}" ]; then
+ echo "" > /etc/nginx/nginx.https.enabled.conf
+else
+ ln -sf /etc/nginx/nginx.https.available.conf /etc/nginx/nginx.https.enabled.conf
+fi
+
+echo "Loading nginx autoreloader"
+sh /docker-autoreload.sh &
+
+echo "-----------------------------------------------------"
+echo "FINISHED NGINX ENTRYPOINT ---------------------------"
+echo "-----------------------------------------------------"
+
+# Run the CMD
+exec "$@"
diff --git a/docker/nginx/geonode.conf.envsubst b/docker/nginx/geonode.conf.envsubst
new file mode 100644
index 0000000000000000000000000000000000000000..3e2bd9d4cbf5bfbecc35f0c5934a008163e32bc7
--- /dev/null
+++ b/docker/nginx/geonode.conf.envsubst
@@ -0,0 +1,155 @@
+include /etc/nginx/mime.types;
+
+# This is the main geonode conf
+charset utf-8;
+
+# max upload size
+client_max_body_size 100G;
+client_body_buffer_size 256K;
+large_client_header_buffers 4 64k;
+proxy_read_timeout 600s;
+
+fastcgi_hide_header Set-Cookie;
+
+etag on;
+
+# compression
+gzip on;
+gzip_vary on;
+gzip_proxied any;
+gzip_http_version 1.1;
+gzip_disable "MSIE [1-6]\.";
+gzip_buffers 16 8k;
+gzip_min_length 1100;
+gzip_comp_level 6;
+gzip_types
+ text/css
+ text/javascript
+ text/xml
+ text/plain
+ application/xml
+ application/xml+rss
+ application/javascript
+ application/x-javascript
+ application/json;
+
+# GeoServer
+location /geoserver {
+
+ # Using a variable is a trick to let Nginx start even if upstream host is not up yet
+ # (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/)
+ set $upstream geoserver:8080;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://$upstream;
+}
+
+# Jenkins
+location /jenkins {
+
+ # Using a variable is a trick to let Nginx start even if upstream host is not up yet
+ # (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/)
+ set $upstream jenkins:$JENKINS_HTTP_PORT;
+ # set $upstream $HTTP_HOST$HTTPS_HOST:$JENKINS_HTTP_PORT;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://$upstream;
+}
+
+# GeoNode
+location /static/ {
+ alias /mnt/volumes/statics/static/;
+
+ location ~* \.(?:html|js|jpg|jpeg|gif|png|css|tgz|gz|rar|bz2|doc|pdf|ppt|tar|wav|bmp|ttf|rtf|swf|ico|flv|txt|woff|woff2|svg|xml)$ {
+ gzip_static always;
+ expires 30d;
+ access_log off;
+ add_header Pragma "public";
+ add_header Cache-Control "max-age=31536000, public";
+ }
+}
+
+location /uploaded/ {
+ alias /mnt/volumes/statics/uploaded/;
+
+ location ~* \.(?:html|js|jpg|jpeg|gif|png|css|tgz|gz|rar|bz2|doc|pdf|ppt|tar|wav|bmp|ttf|rtf|swf|ico|flv|txt|woff|woff2|svg|xml)$ {
+ gzip_static always;
+ expires 30d;
+ access_log off;
+ add_header Pragma "public";
+ add_header Cache-Control "max-age=31536000, public";
+ }
+}
+
+location ~ ^/celery-monitor/? {
+
+ # Using a variable is a trick to let Nginx start even if upstream host is not up yet
+ # (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/)
+ set $upstream celerymonitor:5555;
+
+ rewrite ^/celery-monitor/?(.*)$ /$1 break;
+
+ sub_filter '="/' '="/celery-monitor/';
+ sub_filter_last_modified on;
+ sub_filter_once off;
+
+ # proxy_pass http://unix:/tmp/flower.sock:/;
+ proxy_pass http://$upstream;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_http_version 1.1;
+}
+
+location / {
+ # Using a variable is a trick to let Nginx start even if upstream host is not up yet
+ # (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/)
+ set $upstream django:8000;
+
+ if ($request_method = OPTIONS) {
+ add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, OPTIONS";
+ add_header Access-Control-Allow-Headers "Authorization, Content-Type, Accept";
+ add_header Access-Control-Allow-Credentials true;
+ add_header Content-Length 0;
+ add_header Content-Type text/plain;
+ add_header Access-Control-Max-Age 1728000;
+ return 200;
+ }
+
+ add_header Access-Control-Allow-Credentials false;
+ add_header Access-Control-Allow-Headers "Content-Type, Accept, Authorization, Origin, User-Agent";
+ add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, OPTIONS";
+
+ proxy_connect_timeout 600;
+ proxy_send_timeout 600;
+ proxy_read_timeout 600;
+ send_timeout 600;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Host $server_name;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://$upstream;
+
+ # uwsgi_params
+ include /etc/nginx/uwsgi_params;
+
+ location ~* \.(?:js|jpg|jpeg|gif|png|tgz|gz|rar|bz2|doc|pdf|ppt|tar|wav|bmp|ttf|rtf|swf|ico|flv|woff|woff2|svg|xml)$ {
+ gzip_static always;
+ expires 30d;
+ access_log off;
+ add_header Pragma "public";
+ add_header Cache-Control "max-age=31536000, public";
+ }
+}
diff --git a/docker/nginx/nginx.conf.envsubst b/docker/nginx/nginx.conf.envsubst
new file mode 100644
index 0000000000000000000000000000000000000000..5ba6493347b567b5553a3c6c8a863117598a6750
--- /dev/null
+++ b/docker/nginx/nginx.conf.envsubst
@@ -0,0 +1,39 @@
+# NOTE : $VARIABLES are env variables replaced by entrypoint.sh using envsubst
+# not to be mistaken for nginx variables (also starting with $, but usually lowercase)
+
+worker_processes auto;
+
+events {
+
+}
+
+http {
+ server_names_hash_bucket_size 64;
+
+ # Allow Nginx to resolve Docker host names (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/)
+ resolver $RESOLVER; # it seems rancher uses 169.254.169.250 instead of 127.0.0.11 which works well in docker-compose (see /etc/resolv.conf)
+
+ # https - listens on specific name - this uses letsencrypt cert
+ # this includes a symlink that links either to nginx.https.available.conf if https in enabled
+ # or to an empty file if https is disabled.
+ include nginx.https.enabled.conf;
+
+ # http - listens to specific HTTP_HOST only - this is not encrypted (not ideal but admissible on LAN for instance)
+ # even if not used (HTTP_HOST empty), we must keep it as it's used for internal API calls between django and geoserver
+ # TODO : do not use unencrypted connection even on LAN, but is it possible to have browser not complaining about unknown authority ?
+ server {
+ listen $HTTP_PORT;
+ server_name $HTTP_HOST 127.0.0.1 geonode;
+
+ include sites-enabled/*.conf;
+ }
+
+ # Default server closes the connection (we can connect only using HTTP_HOST and HTTPS_HOST)
+ server {
+ listen $HTTP_PORT default_server;
+ listen $HTTPS_PORT;
+ server_name _;
+ return 444;
+ }
+
+}
diff --git a/docker/nginx/nginx.https.available.conf.envsubst b/docker/nginx/nginx.https.available.conf.envsubst
new file mode 100644
index 0000000000000000000000000000000000000000..b9baaf8aa501c52773d4a1cd7cb5fba8173c4713
--- /dev/null
+++ b/docker/nginx/nginx.https.available.conf.envsubst
@@ -0,0 +1,37 @@
+# NOTE : $VARIABLES are env variables replaced by entrypoint.sh using envsubst
+# not to be mistaken for nginx variables (also starting with $, but usually lowercase)
+
+# This file is to be included in the main nginx.conf configuration if HTTPS_HOST is set
+ssl_session_cache shared:SSL:10m;
+ssl_session_timeout 10m;
+
+# this is the actual HTTPS host
+server {
+ listen $HTTPS_PORT ssl;
+ server_name $HTTPS_HOST;
+ keepalive_timeout 70;
+
+ ssl_certificate /certificate_symlink/fullchain.pem;
+ ssl_certificate_key /certificate_symlink/privkey.pem;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ include sites-enabled/*.conf;
+}
+
+# if we try to connect from http, we redirect to https
+server {
+ listen 80;
+ server_name $HTTPS_HOST $HTTP_HOST; # TODO : once geoserver supports relative urls, we should allow access though both HTTP and HTTPS at the same time and hence remove HTTP_HOST from this line
+
+ # Except for let's encrypt challenge
+ location /.well-known {
+ alias /geonode-certificates/.well-known;
+ include /etc/nginx/mime.types;
+ }
+
+ # Redirect to https
+ location / {
+ return 302 https://$HTTPS_HOST$request_uri; # TODO : we should use 301 (permanent redirect, but not practical for debug)
+ }
+}
diff --git a/entrypoint_ti.sh b/entrypoint_ti.sh
new file mode 100755
index 0000000000000000000000000000000000000000..485d0b772c5e5eaddc8ccb46dc37bf256fbe91a9
--- /dev/null
+++ b/entrypoint_ti.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+set -e
+
+/usr/local/bin/invoke update >> /usr/src/geonode/invoke.log
+
+source $HOME/.bashrc
+source $HOME/.override_env
+
+echo DATABASE_URL=$DATABASE_URL
+echo GEODATABASE_URL=$GEODATABASE_URL
+echo SITEURL=$SITEURL
+echo ALLOWED_HOSTS=$ALLOWED_HOSTS
+echo GEOSERVER_PUBLIC_LOCATION=$GEOSERVER_PUBLIC_LOCATION
+echo MONITORING_ENABLED=$MONITORING_ENABLED
+echo MONITORING_HOST_NAME=$MONITORING_HOST_NAME
+echo MONITORING_SERVICE_NAME=$MONITORING_SERVICE_NAME
+echo MONITORING_DATA_TTL=$MONITORING_DATA_TTL
+
+/usr/local/bin/invoke waitfordbs >> /usr/src/geonode/invoke.log
+echo "waitfordbs task done"
+
+echo "running migrations"
+/usr/local/bin/invoke migrations >> /usr/src/geonode/invoke.log
+echo "migrations task done"
+
+cmd="$@"
+
+echo DOCKER_ENV=$DOCKER_ENV
+
+if [ -z ${DOCKER_ENV} ] || [ ${DOCKER_ENV} = "development" ]
+then
+ echo "Executing standard Django server $cmd for Development"
+else
+ if [ ${IS_CELERY} = "true" ] || [ ${IS_CELERY} = "True" ]
+ then
+ cmd=$CELERY_CMD
+ echo "Executing Celery server $cmd for Production"
+ else
+
+ /usr/local/bin/invoke prepare >> /usr/src/geonode/invoke.log
+ echo "prepare task done"
+
+ if [ ${IS_FIRST_START} = "true" ] || [ ${IS_FIRST_START} = "True" ] || [ ${FORCE_REINIT} = "true" ] || [ ${FORCE_REINIT} = "True" ] || [ ! -e "/mnt/volumes/statics/geonode_init.lock" ]; then
+ /usr/local/bin/invoke updategeoip >> /usr/src/geonode/invoke.log
+ echo "updategeoip task done"
+ /usr/local/bin/invoke fixtures >> /usr/src/geonode/invoke.log
+ echo "fixture task done"
+ /usr/local/bin/invoke monitoringfixture >> /usr/src/geonode/invoke.log
+ echo "monitoringfixture task done"
+ /usr/local/bin/invoke initialized >> /usr/src/geonode/invoke.log
+ echo "initialized"
+ fi
+
+ echo "refresh static data"
+ /usr/local/bin/invoke statics >> /usr/src/geonode/invoke.log
+ echo "static data refreshed"
+ /usr/local/bin/invoke waitforgeoserver >> /usr/src/geonode/invoke.log
+ echo "waitforgeoserver task done"
+ /usr/local/bin/invoke geoserverfixture >> /usr/src/geonode/invoke.log
+ echo "geoserverfixture task done"
+ /usr/local/bin/invoke updateadmin >> /usr/src/geonode/invoke.log
+ echo "updateadmin task done"
+
+ cmd=$UWSGI_CMD
+ echo "Executing UWSGI server $cmd for Production"
+ fi
+fi
+echo "got command $cmd"
+exec $cmd
\ No newline at end of file
diff --git a/fixtures/default_oauth_apps.json b/fixtures/default_oauth_apps.json
new file mode 100644
index 0000000000000000000000000000000000000000..41b8bd9d4147b91d4632ce8e3e908747ad1e8e22
--- /dev/null
+++ b/fixtures/default_oauth_apps.json
@@ -0,0 +1,21 @@
+[
+{
+ "model": "oauth2_provider.application",
+ "pk": 1001,
+ "fields": {
+ "skip_authorization": true,
+ "created": "2018-05-31T10:00:31.661Z",
+ "updated": "2018-05-31T11:30:31.245Z",
+ "algorithm": "RS256",
+ "redirect_uris": "http://localhost:8080/geoserver/index.html\nhttp://localhost/geoserver/index.html",
+ "name": "GeoServer",
+ "authorization_grant_type": "authorization-code",
+ "client_type": "confidential",
+ "client_id": "Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV",
+ "client_secret": "rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3",
+ "user": [
+ "admin"
+ ]
+ }
+}
+]
diff --git a/fixtures/default_oauth_apps_docker.json b/fixtures/default_oauth_apps_docker.json
new file mode 100644
index 0000000000000000000000000000000000000000..975680f67221f4d806891c25044dfa98daee8517
--- /dev/null
+++ b/fixtures/default_oauth_apps_docker.json
@@ -0,0 +1,21 @@
+[
+{
+ "model": "oauth2_provider.application",
+ "pk": 1001,
+ "fields": {
+ "skip_authorization": true,
+ "created": "2018-05-31T10:00:31.661Z",
+ "updated": "2018-05-31T11:30:31.245Z",
+ "algorithm": "RS256",
+ "redirect_uris": "http://geonode/geoserver",
+ "name": "GeoServer",
+ "authorization_grant_type": "authorization-code",
+ "client_type": "confidential",
+ "client_id": "Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV",
+ "client_secret": "rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDBY9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3",
+ "user": [
+ "admin"
+ ]
+ }
+}
+]
diff --git a/fixtures/django_celery_beat.json b/fixtures/django_celery_beat.json
new file mode 100644
index 0000000000000000000000000000000000000000..66c2b6a61fca88bdb767572af4c55a3f951067fe
--- /dev/null
+++ b/fixtures/django_celery_beat.json
@@ -0,0 +1,72 @@
+[
+ {
+ "model": "django_celery_beat.intervalschedule",
+ "pk": 1,
+ "fields": {
+ "every": 60,
+ "period": "seconds"
+ }
+ },
+ {
+ "model": "django_celery_beat.crontabschedule",
+ "pk": 1,
+ "fields": {
+ "minute": "0",
+ "hour": "4",
+ "day_of_week": "*",
+ "day_of_month": "*",
+ "month_of_year": "*"
+ }
+ },
+ {
+ "model": "django_celery_beat.periodictasks",
+ "pk": 1,
+ "fields": {
+ "last_update": "2019-10-14T12:56:49.352Z"
+ }
+ },
+ {
+ "model": "django_celery_beat.periodictask",
+ "pk": 1,
+ "fields": {
+ "name": "celery.backend_cleanup",
+ "task": "celery.backend_cleanup",
+ "interval": null,
+ "crontab": 1,
+ "solar": null,
+ "args": "[]",
+ "kwargs": "{}",
+ "queue": null,
+ "exchange": null,
+ "routing_key": null,
+ "expires": null,
+ "enabled": true,
+ "last_run_at": null,
+ "total_run_count": 0,
+ "date_changed": "2019-10-14T12:50:54.847Z",
+ "description": ""
+ }
+ },
+ {
+ "model": "django_celery_beat.periodictask",
+ "pk": 2,
+ "fields": {
+ "name": "delayed-security-sync-task",
+ "task": "geonode.security.tasks.synch_guardian",
+ "interval": 1,
+ "crontab": null,
+ "solar": null,
+ "args": "[]",
+ "kwargs": "{}",
+ "queue": null,
+ "exchange": null,
+ "routing_key": null,
+ "expires": null,
+ "enabled": true,
+ "last_run_at": null,
+ "total_run_count": 0,
+ "date_changed": "2019-10-14T12:56:37.554Z",
+ "description": ""
+ }
+ }
+]
\ No newline at end of file
diff --git a/fixtures/initial_data.json b/fixtures/initial_data.json
new file mode 100644
index 0000000000000000000000000000000000000000..03c684f43de5d3d265f0205d054a1c8e884ff6a1
--- /dev/null
+++ b/fixtures/initial_data.json
@@ -0,0 +1,4856 @@
+[
+ {
+ "pk": 1,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "information pertaining to earth sciences. Examples: geophysical features and processes, geology, minerals, sciences dealing with the composition, structure and origin of the earth s rocks, risks of earthquakes, volcanic activity, landslides, gravity information, soils, permafrost, hydrogeology, erosion",
+ "gn_description": "Geoscientific Information",
+ "is_choice": true,
+ "fa_class": "fa-bullseye",
+ "identifier": "geoscientificInformation"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "rearing of animals and/or cultivation of plants. Examples: agriculture, irrigation, aquaculture, plantations, herding, pests and diseases affecting crops and livestock",
+ "gn_description": "Farming",
+ "is_choice": true,
+ "fa_class": "fa-lemon-o",
+ "identifier": "farming"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "height above or below sea level. Examples: altitude, bathymetry, digital elevation models, slope, derived products",
+ "gn_description": "Elevation",
+ "is_choice": true,
+ "fa_class": "fa-flag",
+ "identifier": "elevation"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "energy, water and waste systems and communications infrastructure and services. Examples: hydroelectricity, geothermal, solar and nuclear sources of energy, water purification and distribution, sewage collection and disposal, electricity and gas distribution, data communication, telecommunication, radio, communication networks",
+ "gn_description": "Utilities Communication",
+ "is_choice": true,
+ "fa_class": "fa-phone",
+ "identifier": "utilitiesCommunication"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "features and characteristics of salt water bodies (excluding inland waters). Examples: tides, tidal waves, coastal information, reefs",
+ "gn_description": "Oceans",
+ "is_choice": true,
+ "fa_class": "fa-anchor",
+ "identifier": "oceans"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "legal land descriptions. Examples: political and administrative boundaries",
+ "gn_description": "Boundaries",
+ "is_choice": true,
+ "fa_class": "fa-ellipsis-h",
+ "identifier": "boundaries"
+ }
+ },
+ {
+ "pk": 7,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "inland water features, drainage systems and their characteristics. Examples: rivers and glaciers, salt lakes, water utilization plans, dams, currents, floods, water quality, hydrographic charts",
+ "gn_description": "Inland Waters",
+ "is_choice": true,
+ "fa_class": "fa-tint",
+ "identifier": "inlandWaters"
+ }
+ },
+ {
+ "pk": 8,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "military bases, structures, activities. Examples: barracks, training grounds, military transportation, information collection",
+ "gn_description": "Intelligence Military",
+ "is_choice": true,
+ "fa_class": "fa-fighter-jet",
+ "identifier": "intelligenceMilitary"
+ }
+ },
+ {
+ "pk": 9,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "environmental resources, protection and conservation. Examples: environmental pollution, waste storage and treatment, environmental impact assessment, monitoring environmental risk, nature reserves, landscape",
+ "gn_description": "Environment",
+ "is_choice": true,
+ "fa_class": "fa-tree",
+ "identifier": "environment"
+ }
+ },
+ {
+ "pk": 10,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "positional information and services. Examples: addresses, geodetic networks, control points, postal zones and services, place names",
+ "gn_description": "Location",
+ "is_choice": true,
+ "fa_class": "fa-map-marker",
+ "identifier": "location"
+ }
+ },
+ {
+ "pk": 11,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "economic activities, conditions and employment. Examples: production, labour, revenue, commerce, industry, tourism and ecotourism, forestry, fisheries, commercial or subsistence hunting, exploration and exploitation of resources such as minerals, oil and gas",
+ "gn_description": "Economy",
+ "is_choice": true,
+ "fa_class": "fa-shopping-cart",
+ "identifier": "economy"
+ }
+ },
+ {
+ "pk": 12,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "information used for appropriate actions for future use of the land. Examples: land use maps, zoning maps, cadastral surveys, land ownership",
+ "gn_description": "Planning Cadastre",
+ "is_choice": true,
+ "fa_class": "fa-home",
+ "identifier": "planningCadastre"
+ }
+ },
+ {
+ "pk": 13,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "flora and/or fauna in natural environment. Examples: wildlife, vegetation, biological sciences, ecology, wilderness, sealife, wetlands, habitat",
+ "gn_description": "Biota",
+ "is_choice": true,
+ "fa_class": "fa-leaf",
+ "identifier": "biota"
+ }
+ },
+ {
+ "pk": 14,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "health, health services, human ecology, and safety. Examples: disease and illness, factors affecting health, hygiene, substance abuse, mental and physical health, health services",
+ "gn_description": "Health",
+ "is_choice": true,
+ "fa_class": "fa-stethoscope",
+ "identifier": "health"
+ }
+ },
+ {
+ "pk": 15,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "base maps. Examples: land cover, topographic maps, imagery, unclassified images, annotations",
+ "gn_description": "Imagery Base Maps Earth Cover",
+ "is_choice": true,
+ "fa_class": "fa-globe",
+ "identifier": "imageryBaseMapsEarthCover"
+ }
+ },
+ {
+ "pk": 16,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "means and aids for conveying persons and/or goods. Examples: roads, airports/airstrips, shipping routes, tunnels, nautical charts, vehicle or vessel location, aeronautical charts, railways",
+ "gn_description": "Transportation",
+ "is_choice": true,
+ "fa_class": "fa-truck",
+ "identifier": "transportation"
+ }
+ },
+ {
+ "pk": 17,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "characteristics of society and cultures. Examples: settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information",
+ "gn_description": "Society",
+ "is_choice": true,
+ "fa_class": "fa-comments",
+ "identifier": "society"
+ }
+ },
+ {
+ "pk": 18,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "man-made construction. Examples: buildings, museums, churches, factories, housing, monuments, shops, towers",
+ "gn_description": "Structure",
+ "is_choice": true,
+ "fa_class": "fa-building",
+ "identifier": "structure"
+ }
+ },
+ {
+ "pk": 19,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "processes and phenomena of the atmosphere. Examples: cloud cover, weather, climate, atmospheric conditions, climate change, precipitation",
+ "gn_description": "Climatology Meteorology Atmosphere",
+ "is_choice": true,
+ "fa_class": "fa-cloud",
+ "identifier": "climatologyMeteorologyAtmosphere"
+ }
+ },
+ {
+ "pk": 20,
+ "model": "base.topiccategory",
+ "fields": {
+ "description": "settlements, anthropology, archaeology, education, traditional beliefs, manners and customs, demographic data, recreational areas and activities, social impact assessments, crime and justice, census information. Economic activities, conditions and employment",
+ "gn_description": "Population",
+ "is_choice": true,
+ "fa_class": "fa-male",
+ "identifier": "population"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "vector data is used to represent geographic data",
+ "identifier": "vector",
+ "description": "vector data is used to represent geographic data"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "grid data is used to represent geographic data",
+ "identifier": "grid",
+ "description": "grid data is used to represent geographic data"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "textual or tabular data is used to represent geographic data",
+ "identifier": "textTable",
+ "description": "textual or tabular data is used to represent geographic data"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "triangulated irregular network",
+ "identifier": "tin",
+ "description": "triangulated irregular network"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images",
+ "identifier": "stereoModel",
+ "description": "three-dimensional view formed by the intersecting homologous rays of an overlapping pair of images"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "base.spatialrepresentationtype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "scene from a video recording",
+ "identifier": "video",
+ "description": "scene from a video recording"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "base.license",
+ "fields": {
+ "identifier": "not_specified",
+ "name":"Not Specified",
+ "abbreviation":"",
+ "description":"The original author did not specify a license.",
+ "url":"",
+ "license_text":"Not applicable"
+ }
+ },
+{
+ "pk": 2,
+ "model": "base.license",
+ "fields": {
+ "identifier":"varied_original",
+ "name":"Varied / Original",
+ "abbreviation":"",
+ "description":"This item is either licensed under multiple licenses. See the item's abstract for more information or contact the distributor.",
+ "url":"",
+ "license_text":"Not applicable"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "base.license",
+ "fields": {
+ "identifier":"varied_derived",
+ "name":"Varied / Derived",
+ "abbreviation":"",
+ "description":"The constituent parts of this item have different licenses. Go to each part to see license information.",
+ "url":"",
+ "license_text":"Not applicable"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "base.license",
+ "fields": {
+ "identifier":"public_domain",
+ "name":"Public Domain",
+ "abbreviation":"PD",
+ "description":"Works in the public domain may be used freely without the permission of the former copyright owner.",
+ "url":"http://www.copyright.gov/help/faq/faq-definitions.html",
+ "license_text":"The public domain is not a place. A work of authorship is in the “public domain” if it is no longer under copyright protection or if it failed to meet the requirements for copyright protection. Works in the public domain may be used freely without the permission of the former copyright owner."
+ }
+ },
+ {
+ "pk": 5,
+ "model": "base.license",
+ "fields": {
+ "identifier":"public_domain_usg",
+ "name":"Public Domain / USG",
+ "abbreviation":"PD/USG",
+ "description":"This project constitutes a work of the United States Government and is not subject to domestic copyright protection under 17 USC § 105.",
+ "url":"https://raw.githubusercontent.com/state-hiu/cybergis-licenses/master/licenses/PUBLICDOMAIN-LICENSE-RAW.txt",
+ "license_text":"This project constitutes a work of the United States Government and is not subject to domestic copyright protection under 17 USC § 105."
+ }
+ },
+ {
+ "pk": 6,
+ "model": "base.license",
+ "fields": {
+ "identifier":"odbl",
+ "name":"Open Data Commons Open Database License / OSM",
+ "abbreviation":"ODbL/OSM",
+ "description":"You are free to copy, distribute, transmit and adapt our data, as long as you credit OpenStreetMap and its contributors\nIf you alter or build upon our data, you may distribute the result only under the same licence.",
+ "url":"http://www.openstreetmap.org/copyright",
+ "license_text":""
+ }
+ },
+ {
+ "pk": 7,
+ "model": "base.license",
+ "fields": {
+ "identifier":"nextview",
+ "name":"NextView",
+ "abbreviation":"NV",
+ "description":"This data is licensed for use by the US Government (USG) under the NextView (NV) license and copyrighted by Digital Globe or GeoEye. The NV license allows the USG to share the imagery and Literal Imagery Derived Products (LIDP) with entities outside the USG when that entity is working directly with the USG, for the USG, or in a manner that is directly beneficial to the USG. The party receiving the data can only use the imagery or LIDP for the original purpose or only as otherwise agreed to by the USG. The party receiving the data cannot share the imagery or LIDP with a third party without express permission from the USG. At no time should this imagery or LIDP be used for other than USG-related purposes and must not be used for commercial gain. The copyright information should be maintained at all times. Your acceptance of these license terms is implied by your use.\nIn other words, you may only use NextView imagery linked from this site for digitizing OpenStreetMap data for humanitarian purposes.",
+ "url":"https://raw.githubusercontent.com/state-hiu/cybergis-licenses/master/licenses/NEXTVIEW-LICENSE-RAW.txt",
+ "license_text":""
+ }
+ },
+ {
+ "pk": 1,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor",
+ "identifier": "copyright",
+ "description": "exclusive right to the publication, production, or sale of the rights to a literary, dramatic, musical, or artistic work, or to the use of a commercial print or label, granted by law for a specified period of time to an author, composer, artist, distributor"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity",
+ "identifier": "intellectualPropertyRights",
+ "description": "rights to financial benefit from and control of distribution of non-tangible property that is a result of creativity"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "formal permission to do something",
+ "identifier": "license",
+ "description": "formal permission to do something"
+ }
+ },
+ {
+ "pk": 8,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "otherRestrictions",
+ "identifier": "limitation not listed",
+ "description": "otherRestrictions"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "government has granted exclusive right to make, sell, use or license an invention or discovery",
+ "identifier": "patent",
+ "description": "government has granted exclusive right to make, sell, use or license an invention or discovery"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "produced or sold information awaiting a patent",
+ "identifier": "patentPending",
+ "description": "produced or sold information awaiting a patent"
+ }
+ },
+ {
+ "pk": 7,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "withheld from general circulation or disclosure",
+ "identifier": "restricted",
+ "description": "withheld from general circulation or disclosure"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "base.restrictioncodetype",
+ "fields": {
+ "is_choice": true,
+ "gn_description": "a name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer",
+ "identifier": "trademark",
+ "description": "a name, symbol, or other device identifying a product, officially registered and legally restricted to the use of the owner or manufacturer"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "base.region",
+ "fields": {
+ "rght": 516,
+ "code": "GLO",
+ "name": "Global",
+ "parent": null,
+ "level": 0,
+ "lft": 1,
+ "tree_id": 90,
+ "bbox_x0": -180,
+ "bbox_x1": 180,
+ "bbox_y0": -90,
+ "bbox_y1": 90
+ }
+ },
+ {
+ "pk": 2,
+ "model": "base.region",
+ "fields": {
+ "rght": 212,
+ "code": "NAM",
+ "name": "North America",
+ "parent": 254,
+ "level": 2,
+ "lft": 203,
+ "tree_id": 90,
+ "bbox_x0": -167.276413,
+ "bbox_x1": -52.23304,
+ "bbox_y0": 5.49955,
+ "bbox_y1": 83.162102
+ }
+ },
+ {
+ "pk": 3,
+ "model": "base.region",
+ "fields": {
+ "rght": 202,
+ "code": "CAM",
+ "name": "Central America",
+ "parent": 254,
+ "level": 2,
+ "lft": 187,
+ "tree_id": 90,
+ "bbox_x0": -118.867172,
+ "bbox_x1": -66.869827,
+ "bbox_y0": -4.23048,
+ "bbox_y1": 32.71862
+ }
+ },
+ {
+ "pk": 4,
+ "model": "base.region",
+ "fields": {
+ "rght": 242,
+ "code": "SAM",
+ "name": "South America",
+ "parent": 254,
+ "level": 2,
+ "lft": 213,
+ "tree_id": 90,
+ "bbox_x0": -109.47493,
+ "bbox_x1": -26.33247,
+ "bbox_y0": -59.450451,
+ "bbox_y1": 13.39029
+ }
+ },
+ {
+ "pk": 5,
+ "model": "base.region",
+ "fields": {
+ "rght": 433,
+ "code": "EUR",
+ "name": "Europe",
+ "parent": null,
+ "level": 1,
+ "lft": 318,
+ "tree_id": 90,
+ "bbox_x0": -31.266001,
+ "bbox_x1": 39.869301,
+ "bbox_y0": 27.636311,
+ "bbox_y1": 81.008797
+ }
+ },
+ {
+ "pk": 6,
+ "model": "base.region",
+ "fields": {
+ "rght": 317,
+ "code": "ASI",
+ "name": "Asia",
+ "parent": null,
+ "level": 1,
+ "lft": 246,
+ "tree_id": 90,
+ "bbox_x0": 19.6381,
+ "bbox_x1": 180,
+ "bbox_y0": -12.56111,
+ "bbox_y1": 82.50045
+ }
+ },
+ {
+ "pk": 7,
+ "model": "base.region",
+ "fields": {
+ "rght": 316,
+ "code": "SEA",
+ "name": "Southeast Asia",
+ "parent": 6,
+ "level": 2,
+ "lft": 293,
+ "tree_id": 90,
+ "bbox_x0": 68.0327,
+ "bbox_x1": 141.021805,
+ "bbox_y0": -12.56111,
+ "bbox_y1": 35.504211
+ }
+ },
+ {
+ "pk": 8,
+ "model": "base.region",
+ "fields": {
+ "rght": 260,
+ "code": "CTA",
+ "name": "Central Asia",
+ "parent": 6,
+ "level": 2,
+ "lft": 247,
+ "tree_id": 90,
+ "bbox_x0": 44.236641,
+ "bbox_x1": 90.076767,
+ "bbox_y0": 33.890511,
+ "bbox_y1": 54.845139
+ }
+ },
+ {
+ "pk": 9,
+ "model": "base.region",
+ "fields": {
+ "rght": 292,
+ "code": "SAS",
+ "name": "South Asia",
+ "parent": 6,
+ "level": 2,
+ "lft": 277,
+ "tree_id": 90,
+ "bbox_x0": 19.6381,
+ "bbox_x1": 180,
+ "bbox_y0": -12.56111,
+ "bbox_y1": 82.50045
+ }
+ },
+ {
+ "pk": 10,
+ "model": "base.region",
+ "fields": {
+ "rght": 127,
+ "code": "AFR",
+ "name": "Africa",
+ "parent": null,
+ "level": 1,
+ "lft": 2,
+ "tree_id": 90,
+ "bbox_x0": -25.35874,
+ "bbox_x1": 63.525379,
+ "bbox_y0": -46.900452,
+ "bbox_y1": 37.56712
+ }
+ },
+ {
+ "pk": 11,
+ "model": "base.region",
+ "fields": {
+ "rght": 64,
+ "code": "NAF",
+ "name": "North Africa",
+ "parent": 10,
+ "level": 2,
+ "lft": 49,
+ "tree_id": 90,
+ "bbox_x0": -17.10317,
+ "bbox_x1": 38.833801,
+ "bbox_y0": 3.48639,
+ "bbox_y1": 37.56712
+ }
+ },
+ {
+ "pk": 12,
+ "model": "base.region",
+ "fields": {
+ "rght": 48,
+ "code": "EAF",
+ "name": "East Africa",
+ "parent": 10,
+ "level": 2,
+ "lft": 13,
+ "tree_id": 90,
+ "bbox_x0": 22.855089,
+ "bbox_x1": 63.94656,
+ "bbox_y0": -25.84763,
+ "bbox_y1": 17.467039
+ }
+ },
+ {
+ "pk": 13,
+ "model": "base.region",
+ "fields": {
+ "rght": 126,
+ "code": "WAF",
+ "name": "West Africa",
+ "parent": 10,
+ "level": 2,
+ "lft": 83,
+ "tree_id": 90,
+ "bbox_x0": -26.758421,
+ "bbox_x1": 24.002661,
+ "bbox_y0": -9.29925,
+ "bbox_y1": 27.702801
+ }
+ },
+ {
+ "pk": 14,
+ "model": "base.region",
+ "fields": {
+ "rght": 82,
+ "code": "SAF",
+ "name": "Southern Africa",
+ "parent": 10,
+ "level": 2,
+ "lft": 65,
+ "tree_id": 90,
+ "bbox_x0": 8.93107,
+ "bbox_x1": 42.74847,
+ "bbox_y0": -35.507481,
+ "bbox_y1": -13.27553
+ }
+ },
+ {
+ "pk": 15,
+ "model": "base.region",
+ "fields": {
+ "rght": 463,
+ "code": "MES",
+ "name": "Middle East",
+ "parent": null,
+ "level": 1,
+ "lft": 434,
+ "tree_id": 90,
+ "bbox_x0": 24.698099,
+ "bbox_x1": 63.317459,
+ "bbox_y0": 12.111,
+ "bbox_y1": 42.10751
+ }
+ },
+ {
+ "pk": 16,
+ "model": "base.region",
+ "fields": {
+ "rght": 245,
+ "code": "ANT",
+ "name": "Antarctica",
+ "parent": null,
+ "level": 1,
+ "lft": 244,
+ "tree_id": 90,
+ "bbox_x0": -180,
+ "bbox_x1": 180,
+ "bbox_y0": -90,
+ "bbox_y1": -73
+ }
+ },
+ {
+ "pk": 17,
+ "model": "base.region",
+ "fields": {
+ "rght": 249,
+ "code": "AFG",
+ "name": "Afghanistan",
+ "parent": 8,
+ "level": 3,
+ "lft": 248,
+ "tree_id": 90,
+ "bbox_x0": 60.478439,
+ "bbox_x1": 74.879433,
+ "bbox_y0": 29.37747,
+ "bbox_y1": 38.483421
+ }
+ },
+ {
+ "pk": 18,
+ "model": "base.region",
+ "fields": {
+ "rght": 320,
+ "code": "ALA",
+ "name": "Aland Islands",
+ "parent": 5,
+ "level": 2,
+ "lft": 319,
+ "tree_id": 90,
+ "bbox_x0": 19.262711,
+ "bbox_x1": 21.324409,
+ "bbox_y0": 59.736301,
+ "bbox_y1": 60.665581
+ }
+ },
+ {
+ "pk": 19,
+ "model": "base.region",
+ "fields": {
+ "rght": 322,
+ "code": "ALB",
+ "name": "Albania",
+ "parent": 5,
+ "level": 2,
+ "lft": 321,
+ "tree_id": 90,
+ "bbox_x0": 19.28219,
+ "bbox_x1": 21.057819,
+ "bbox_y0": 39.644489,
+ "bbox_y1": 42.660801
+ }
+ },
+ {
+ "pk": 20,
+ "model": "base.region",
+ "fields": {
+ "rght": 51,
+ "code": "DZA",
+ "name": "Algeria",
+ "parent": 11,
+ "level": 3,
+ "lft": 50,
+ "tree_id": 90,
+ "bbox_x0": -8.67386,
+ "bbox_x1": 11.97955,
+ "bbox_y0": 18.96002,
+ "bbox_y1": 37.093731
+ }
+ },
+ {
+ "pk": 21,
+ "model": "base.region",
+ "fields": {
+ "rght": 466,
+ "code": "ASM",
+ "name": "American Samoa",
+ "parent": 256,
+ "level": 2,
+ "lft": 465,
+ "tree_id": 90,
+ "bbox_x0": -171.091873,
+ "bbox_x1": -169.416077,
+ "bbox_y0": -14.38247,
+ "bbox_y1": -11.04969
+ }
+ },
+ {
+ "pk": 22,
+ "model": "base.region",
+ "fields": {
+ "rght": 324,
+ "code": "AND",
+ "name": "Andorra",
+ "parent": 5,
+ "level": 2,
+ "lft": 323,
+ "tree_id": 90,
+ "bbox_x0": 1.41382,
+ "bbox_x1": 1.78659,
+ "bbox_y0": 42.42873,
+ "bbox_y1": 42.65601
+ }
+ },
+ {
+ "pk": 23,
+ "model": "base.region",
+ "fields": {
+ "rght": 85,
+ "code": "AGO",
+ "name": "Angola",
+ "parent": 13,
+ "level": 3,
+ "lft": 84,
+ "tree_id": 90,
+ "bbox_x0": 11.6792,
+ "bbox_x1": 24.082109,
+ "bbox_y0": -18.04207,
+ "bbox_y1": -4.37259
+ }
+ },
+ {
+ "pk": 24,
+ "model": "base.region",
+ "fields": {
+ "rght": 131,
+ "code": "AIA",
+ "name": "Anguilla",
+ "parent": 255,
+ "level": 3,
+ "lft": 130,
+ "tree_id": 90,
+ "bbox_x0": -63.434872,
+ "bbox_x1": -62.916199,
+ "bbox_y0": 18.149549,
+ "bbox_y1": 18.61278
+ }
+ },
+ {
+ "pk": 25,
+ "model": "base.region",
+ "fields": {
+ "rght": 133,
+ "code": "ATG",
+ "name": "Antigua and Barbuda",
+ "parent": 255,
+ "level": 3,
+ "lft": 132,
+ "tree_id": 90,
+ "bbox_x0": -62.352402,
+ "bbox_x1": -61.659081,
+ "bbox_y0": 16.927219,
+ "bbox_y1": 17.72938
+ }
+ },
+ {
+ "pk": 26,
+ "model": "base.region",
+ "fields": {
+ "rght": 215,
+ "code": "ARG",
+ "name": "Argentina",
+ "parent": 4,
+ "level": 3,
+ "lft": 214,
+ "tree_id": 90,
+ "bbox_x0": -73.577782,
+ "bbox_x1": -53.637539,
+ "bbox_y0": -55.057362,
+ "bbox_y1": -21.78126
+ }
+ },
+ {
+ "pk": 27,
+ "model": "base.region",
+ "fields": {
+ "rght": 326,
+ "code": "ARM",
+ "name": "Armenia",
+ "parent": 5,
+ "level": 2,
+ "lft": 325,
+ "tree_id": 90,
+ "bbox_x0": 43.449749,
+ "bbox_x1": 46.630039,
+ "bbox_y0": 38.830521,
+ "bbox_y1": 41.30183
+ }
+ },
+ {
+ "pk": 28,
+ "model": "base.region",
+ "fields": {
+ "rght": 135,
+ "code": "ABW",
+ "name": "Aruba",
+ "parent": 255,
+ "level": 3,
+ "lft": 134,
+ "tree_id": 90,
+ "bbox_x0": -70.0611,
+ "bbox_x1": -69.8669,
+ "bbox_y0": 12.4061,
+ "bbox_y1": 12.6306
+ }
+ },
+ {
+ "pk": 29,
+ "model": "base.region",
+ "fields": {
+ "rght": 468,
+ "code": "AUS",
+ "name": "Australia",
+ "parent": 256,
+ "level": 2,
+ "lft": 467,
+ "tree_id": 90,
+ "bbox_x0": 112.921112,
+ "bbox_x1": 159.278717,
+ "bbox_y0": -54.640301,
+ "bbox_y1": -9.22882
+ }
+ },
+ {
+ "pk": 30,
+ "model": "base.region",
+ "fields": {
+ "rght": 328,
+ "code": "AUT",
+ "name": "Austria",
+ "parent": 5,
+ "level": 2,
+ "lft": 327,
+ "tree_id": 90,
+ "bbox_x0": 9.53079,
+ "bbox_x1": 17.160749,
+ "bbox_y0": 46.372299,
+ "bbox_y1": 49.02071
+ }
+ },
+ {
+ "pk": 31,
+ "model": "base.region",
+ "fields": {
+ "rght": 330,
+ "code": "AZE",
+ "name": "Azerbaijan",
+ "parent": 5,
+ "level": 2,
+ "lft": 329,
+ "tree_id": 90,
+ "bbox_x0": 44.7719,
+ "bbox_x1": 50.6078,
+ "bbox_y0": 38.3970,
+ "bbox_y1": 41.9056
+ }
+ },
+ {
+ "pk": 32,
+ "model": "base.region",
+ "fields": {
+ "rght": 137,
+ "code": "BHS",
+ "name": "Bahamas",
+ "parent": 255,
+ "level": 3,
+ "lft": 136,
+ "tree_id": 90,
+ "bbox_x0": -80.499229,
+ "bbox_x1": -72.649513,
+ "bbox_y0": 20.916059,
+ "bbox_y1": 27.933781
+ }
+ },
+ {
+ "pk": 33,
+ "model": "base.region",
+ "fields": {
+ "rght": 436,
+ "code": "BHR",
+ "name": "Bahrain",
+ "parent": 15,
+ "level": 2,
+ "lft": 435,
+ "tree_id": 90,
+ "bbox_x0": 50.385799,
+ "bbox_x1": 50.828499,
+ "bbox_y0": 25.5422,
+ "bbox_y1": 26.292391
+ }
+ },
+ {
+ "pk": 34,
+ "model": "base.region",
+ "fields": {
+ "rght": 279,
+ "code": "BGD",
+ "name": "Bangladesh",
+ "parent": 9,
+ "level": 3,
+ "lft": 278,
+ "tree_id": 90,
+ "bbox_x0": 88.028198,
+ "bbox_x1": 92.673599,
+ "bbox_y0": 20.585199,
+ "bbox_y1": 26.631701
+ }
+ },
+ {
+ "pk": 35,
+ "model": "base.region",
+ "fields": {
+ "rght": 139,
+ "code": "BRB",
+ "name": "Barbados",
+ "parent": 255,
+ "level": 3,
+ "lft": 138,
+ "tree_id": 90,
+ "bbox_x0": -59.648918,
+ "bbox_x1": -59.420368,
+ "bbox_y0": 13.03984,
+ "bbox_y1": 13.32725
+ }
+ },
+ {
+ "pk": 36,
+ "model": "base.region",
+ "fields": {
+ "rght": 332,
+ "code": "BLR",
+ "name": "Belarus",
+ "parent": 5,
+ "level": 2,
+ "lft": 331,
+ "tree_id": 90,
+ "bbox_x0": 23.17679,
+ "bbox_x1": 32.77071,
+ "bbox_y0": 51.256401,
+ "bbox_y1": 56.16571
+ }
+ },
+ {
+ "pk": 37,
+ "model": "base.region",
+ "fields": {
+ "rght": 334,
+ "code": "BEL",
+ "name": "Belgium",
+ "parent": 5,
+ "level": 2,
+ "lft": 333,
+ "tree_id": 90,
+ "bbox_x0": 2.54563,
+ "bbox_x1": 6.40791,
+ "bbox_y0": 49.496899,
+ "bbox_y1": 51.505081
+ }
+ },
+ {
+ "pk": 38,
+ "model": "base.region",
+ "fields": {
+ "rght": 189,
+ "code": "BLZ",
+ "name": "Belize",
+ "parent": 3,
+ "level": 3,
+ "lft": 188,
+ "tree_id": 90,
+ "bbox_x0": -89.224823,
+ "bbox_x1": -87.468132,
+ "bbox_y0": 15.8893,
+ "bbox_y1": 18.49655
+ }
+ },
+ {
+ "pk": 39,
+ "model": "base.region",
+ "fields": {
+ "rght": 87,
+ "code": "BEN",
+ "name": "Benin",
+ "parent": 13,
+ "level": 3,
+ "lft": 86,
+ "tree_id": 90,
+ "bbox_x0": 0.77456,
+ "bbox_x1": 3.8517,
+ "bbox_y0": 6.22574,
+ "bbox_y1": 12.41834
+ }
+ },
+ {
+ "pk": 40,
+ "model": "base.region",
+ "fields": {
+ "rght": 141,
+ "code": "BMU",
+ "name": "Bermuda",
+ "parent": 255,
+ "level": 3,
+ "lft": 140,
+ "tree_id": 90,
+ "bbox_x0": -64.896042,
+ "bbox_x1": -64.642952,
+ "bbox_y0": 32.230709,
+ "bbox_y1": 32.393829
+ }
+ },
+ {
+ "pk": 41,
+ "model": "base.region",
+ "fields": {
+ "rght": 281,
+ "code": "BTN",
+ "name": "Bhutan",
+ "parent": 9,
+ "level": 3,
+ "lft": 280,
+ "tree_id": 90,
+ "bbox_x0": 88.759521,
+ "bbox_x1": 92.125023,
+ "bbox_y0": 26.7075,
+ "bbox_y1": 28.3235
+ }
+ },
+ {
+ "pk": 42,
+ "model": "base.region",
+ "fields": {
+ "rght": 217,
+ "code": "BOL",
+ "name": "Bolivia",
+ "parent": 4,
+ "level": 3,
+ "lft": 216,
+ "tree_id": 90,
+ "bbox_x0": -69.640762,
+ "bbox_x1": -57.458092,
+ "bbox_y0": -22.89613,
+ "bbox_y1": -9.68056
+ }
+ },
+ {
+ "pk": 43,
+ "model": "base.region",
+ "fields": {
+ "rght": 336,
+ "code": "BIH",
+ "name": "Bosnia and Herzegovina",
+ "parent": 5,
+ "level": 2,
+ "lft": 335,
+ "tree_id": 90,
+ "bbox_x0": 15.74909,
+ "bbox_x1": 19.62907,
+ "bbox_y0": 42.56451,
+ "bbox_y1": 45.276001
+ }
+ },
+ {
+ "pk": 44,
+ "model": "base.region",
+ "fields": {
+ "rght": 67,
+ "code": "BWA",
+ "name": "Botswana",
+ "parent": 14,
+ "level": 3,
+ "lft": 66,
+ "tree_id": 90,
+ "bbox_x0": 19.999531,
+ "bbox_x1": 29.360781,
+ "bbox_y0": -26.90724,
+ "bbox_y1": -17.780809
+ }
+ },
+ {
+ "pk": 45,
+ "model": "base.region",
+ "fields": {
+ "rght": 219,
+ "code": "BRA",
+ "name": "Brazil",
+ "parent": 4,
+ "level": 3,
+ "lft": 218,
+ "tree_id": 90,
+ "bbox_x0": -73.985527,
+ "bbox_x1": -28.839041,
+ "bbox_y0": -33.750702,
+ "bbox_y1": 5.26486
+ }
+ },
+ {
+ "pk": 46,
+ "model": "base.region",
+ "fields": {
+ "rght": 143,
+ "code": "VGB",
+ "name": "British Virgin Islands",
+ "parent": 255,
+ "level": 3,
+ "lft": 142,
+ "tree_id": 90,
+ "bbox_x0": -64.783012,
+ "bbox_x1": -64.268761,
+ "bbox_y0": 18.312731,
+ "bbox_y1": 18.757219
+ }
+ },
+ {
+ "pk": 47,
+ "model": "base.region",
+ "fields": {
+ "rght": 295,
+ "code": "BRN",
+ "name": "Brunei Darussalam",
+ "parent": 7,
+ "level": 3,
+ "lft": 294,
+ "tree_id": 90,
+ "bbox_x0": 114.071457,
+ "bbox_x1": 115.359451,
+ "bbox_y0": 4.00309,
+ "bbox_y1": 5.04717
+ }
+ },
+ {
+ "pk": 48,
+ "model": "base.region",
+ "fields": {
+ "rght": 338,
+ "code": "BGR",
+ "name": "Bulgaria",
+ "parent": 5,
+ "level": 2,
+ "lft": 337,
+ "tree_id": 90,
+ "bbox_x0": 22.35741,
+ "bbox_x1": 28.60882,
+ "bbox_y0": 41.235931,
+ "bbox_y1": 44.227261
+ }
+ },
+ {
+ "pk": 49,
+ "model": "base.region",
+ "fields": {
+ "rght": 89,
+ "code": "BFA",
+ "name": "Burkina Faso",
+ "parent": 13,
+ "level": 3,
+ "lft": 88,
+ "tree_id": 90,
+ "bbox_x0": -5.51891,
+ "bbox_x1": 2.40539,
+ "bbox_y0": 9.4011,
+ "bbox_y1": 15.08259
+ }
+ },
+ {
+ "pk": 50,
+ "model": "base.region",
+ "fields": {
+ "rght": 15,
+ "code": "BDI",
+ "name": "Burundi",
+ "parent": 12,
+ "level": 3,
+ "lft": 14,
+ "tree_id": 90,
+ "bbox_x0": 28.993071,
+ "bbox_x1": 30.847719,
+ "bbox_y0": -4.46571,
+ "bbox_y1": -2.31012
+ }
+ },
+ {
+ "pk": 51,
+ "model": "base.region",
+ "fields": {
+ "rght": 297,
+ "code": "KHM",
+ "name": "Cambodia",
+ "parent": 7,
+ "level": 3,
+ "lft": 296,
+ "tree_id": 90,
+ "bbox_x0": 102.340012,
+ "bbox_x1": 107.627724,
+ "bbox_y0": 9.28325,
+ "bbox_y1": 14.6864
+ }
+ },
+ {
+ "pk": 52,
+ "model": "base.region",
+ "fields": {
+ "rght": 91,
+ "code": "CMR",
+ "name": "Cameroon",
+ "parent": 13,
+ "level": 3,
+ "lft": 90,
+ "tree_id": 90,
+ "bbox_x0": 8.49477,
+ "bbox_x1": 16.19211,
+ "bbox_y0": 1.65254,
+ "bbox_y1": 13.07805
+ }
+ },
+ {
+ "pk": 53,
+ "model": "base.region",
+ "fields": {
+ "rght": 205,
+ "code": "CAN",
+ "name": "Canada",
+ "parent": 2,
+ "level": 3,
+ "lft": 204,
+ "tree_id": 90,
+ "bbox_x0": -141.002701,
+ "bbox_x1": -52.620201,
+ "bbox_y0": 41.681019,
+ "bbox_y1": 83.110619
+ }
+ },
+ {
+ "pk": 54,
+ "model": "base.region",
+ "fields": {
+ "rght": 93,
+ "code": "CPV",
+ "name": "Cape Verde",
+ "parent": 13,
+ "level": 3,
+ "lft": 92,
+ "tree_id": 90,
+ "bbox_x0": -25.35874,
+ "bbox_x1": -22.666201,
+ "bbox_y0": 14.80221,
+ "bbox_y1": 17.19717
+ }
+ },
+ {
+ "pk": 55,
+ "model": "base.region",
+ "fields": {
+ "rght": 145,
+ "code": "CYM",
+ "name": "Cayman Islands",
+ "parent": 255,
+ "level": 3,
+ "lft": 144,
+ "tree_id": 90,
+ "bbox_x0": -81.420593,
+ "bbox_x1": -79.722321,
+ "bbox_y0": 19.262659,
+ "bbox_y1": 19.75738
+ }
+ },
+ {
+ "pk": 56,
+ "model": "base.region",
+ "fields": {
+ "rght": 5,
+ "code": "CAF",
+ "name": "Central African Republic",
+ "parent": 257,
+ "level": 3,
+ "lft": 4,
+ "tree_id": 90,
+ "bbox_x0": 14.42009,
+ "bbox_x1": 27.463421,
+ "bbox_y0": 2.22051,
+ "bbox_y1": 11.00756
+ }
+ },
+ {
+ "pk": 57,
+ "model": "base.region",
+ "fields": {
+ "rght": 7,
+ "code": "TCD",
+ "name": "Chad",
+ "parent": 257,
+ "level": 3,
+ "lft": 6,
+ "tree_id": 90,
+ "bbox_x0": 13.47592,
+ "bbox_x1": 24.00161,
+ "bbox_y0": 7.44237,
+ "bbox_y1": 23.478239
+ }
+ },
+ {
+ "pk": 58,
+ "model": "base.region",
+ "fields": {
+ "rght": 340,
+ "code": "CIL",
+ "name": "Channel Islands",
+ "parent": 5,
+ "level": 2,
+ "lft": 339,
+ "tree_id": 90,
+ "bbox_x0": -2.67545,
+ "bbox_x1": -2.01129,
+ "bbox_y0": 49.16209,
+ "bbox_y1": 49.7393
+ }
+ },
+ {
+ "pk": 59,
+ "model": "base.region",
+ "fields": {
+ "rght": 221,
+ "code": "CHL",
+ "name": "Chile",
+ "parent": 4,
+ "level": 3,
+ "lft": 220,
+ "tree_id": 90,
+ "bbox_x0": -109.47493,
+ "bbox_x1": -66.417549,
+ "bbox_y0": -56.533779,
+ "bbox_y1": -17.507549
+ }
+ },
+ {
+ "pk": 60,
+ "model": "base.region",
+ "fields": {
+ "rght": 263,
+ "code": "CHN",
+ "name": "China",
+ "parent": 258,
+ "level": 3,
+ "lft": 262,
+ "tree_id": 90,
+ "bbox_x0": 73.557701,
+ "bbox_x1": 134.773605,
+ "bbox_y0": 15.77539,
+ "bbox_y1": 53.5606
+ }
+ },
+ {
+ "pk": 61,
+ "model": "base.region",
+ "fields": {
+ "rght": 265,
+ "code": "HKG",
+ "name": "China - Hong Kong",
+ "parent": 258,
+ "level": 3,
+ "lft": 264,
+ "tree_id": 90,
+ "bbox_x0": 113.835083,
+ "bbox_x1": 114.441788,
+ "bbox_y0": 22.153549,
+ "bbox_y1": 22.56204
+ }
+ },
+ {
+ "pk": 62,
+ "model": "base.region",
+ "fields": {
+ "rght": 267,
+ "code": "MAC",
+ "name": "China - Macao",
+ "parent": 258,
+ "level": 3,
+ "lft": 266,
+ "tree_id": 90,
+ "bbox_x0": 113.528351,
+ "bbox_x1": 113.598297,
+ "bbox_y0": 22.10977,
+ "bbox_y1": 22.21697
+ }
+ },
+ {
+ "pk": 63,
+ "model": "base.region",
+ "fields": {
+ "rght": 223,
+ "code": "COL",
+ "name": "Colombia",
+ "parent": 4,
+ "level": 3,
+ "lft": 222,
+ "tree_id": 90,
+ "bbox_x0": -81.728111,
+ "bbox_x1": -66.869827,
+ "bbox_y0": -4.23048,
+ "bbox_y1": 13.39029
+ }
+ },
+ {
+ "pk": 64,
+ "model": "base.region",
+ "fields": {
+ "rght": 17,
+ "code": "COM",
+ "name": "Comoros",
+ "parent": 12,
+ "level": 3,
+ "lft": 16,
+ "tree_id": 90,
+ "bbox_x0": 43.215778,
+ "bbox_x1": 44.538219,
+ "bbox_y0": -12.41382,
+ "bbox_y1": -11.36238
+ }
+ },
+ {
+ "pk": 65,
+ "model": "base.region",
+ "fields": {
+ "rght": 9,
+ "code": "COG",
+ "name": "Congo",
+ "parent": 257,
+ "level": 3,
+ "lft": 8,
+ "tree_id": 90,
+ "bbox_x0": 11.205,
+ "bbox_x1": 18.64983,
+ "bbox_y0": -5.02831,
+ "bbox_y1": 3.70308
+ }
+ },
+ {
+ "pk": 66,
+ "model": "base.region",
+ "fields": {
+ "rght": 470,
+ "code": "COK",
+ "name": "Cook Islands",
+ "parent": 256,
+ "level": 2,
+ "lft": 469,
+ "tree_id": 90,
+ "bbox_x0": -165.858093,
+ "bbox_x1": -157.312119,
+ "bbox_y0": -21.94416,
+ "bbox_y1": -8.94402
+ }
+ },
+ {
+ "pk": 67,
+ "model": "base.region",
+ "fields": {
+ "rght": 191,
+ "code": "CRI",
+ "name": "Costa Rica",
+ "parent": 3,
+ "level": 3,
+ "lft": 190,
+ "tree_id": 90,
+ "bbox_x0": -87.083778,
+ "bbox_x1": -82.556,
+ "bbox_y0": 5.49955,
+ "bbox_y1": 11.21681
+ }
+ },
+ {
+ "pk": 68,
+ "model": "base.region",
+ "fields": {
+ "rght": 95,
+ "code": "CIV",
+ "name": "Cote d'Ivoire",
+ "parent": 13,
+ "level": 3,
+ "lft": 94,
+ "tree_id": 90,
+ "bbox_x0": -8.6017249,
+ "bbox_x1": -2.4930309,
+ "bbox_y0": 4.1642077,
+ "bbox_y1": 10.740015
+ }
+ },
+ {
+ "pk": 69,
+ "model": "base.region",
+ "fields": {
+ "rght": 342,
+ "code": "HRV",
+ "name": "Croatia",
+ "parent": 5,
+ "level": 2,
+ "lft": 341,
+ "tree_id": 90,
+ "bbox_x0": 13.48972,
+ "bbox_x1": 19.44722,
+ "bbox_y0": 42.392208,
+ "bbox_y1": 46.554981
+ }
+ },
+ {
+ "pk": 70,
+ "model": "base.region",
+ "fields": {
+ "rght": 147,
+ "code": "CUB",
+ "name": "Cuba",
+ "parent": 255,
+ "level": 3,
+ "lft": 146,
+ "tree_id": 90,
+ "bbox_x0": -84.957428,
+ "bbox_x1": -74.131783,
+ "bbox_y0": 19.828079,
+ "bbox_y1": 23.283779
+ }
+ },
+ {
+ "pk": 71,
+ "model": "base.region",
+ "fields": {
+ "rght": 344,
+ "code": "CYP",
+ "name": "Cyprus",
+ "parent": 5,
+ "level": 2,
+ "lft": 343,
+ "tree_id": 90,
+ "bbox_x0": 32.27309,
+ "bbox_x1": 34.597919,
+ "bbox_y0": 34.563511,
+ "bbox_y1": 35.701542
+ }
+ },
+ {
+ "pk": 72,
+ "model": "base.region",
+ "fields": {
+ "rght": 346,
+ "code": "CZE",
+ "name": "Czech Republic",
+ "parent": 5,
+ "level": 2,
+ "lft": 345,
+ "tree_id": 90,
+ "bbox_x0": 12.0905901,
+ "bbox_x1": 18.859216,
+ "bbox_y0": 48.5518144,
+ "bbox_y1": 51.0557036
+ }
+ },
+ {
+ "pk": 73,
+ "model": "base.region",
+ "fields": {
+ "rght": 269,
+ "code": "PRK",
+ "name": "Democratic People's Republic of Korea",
+ "parent": 258,
+ "level": 3,
+ "lft": 268,
+ "tree_id": 90,
+ "bbox_x0": 124.182739,
+ "bbox_x1": 130.674713,
+ "bbox_y0": 37.632881,
+ "bbox_y1": 43.006001
+ }
+ },
+ {
+ "pk": 74,
+ "model": "base.region",
+ "fields": {
+ "rght": 11,
+ "code": "COD",
+ "name": "Democratic Republic of the Congo",
+ "parent": 257,
+ "level": 3,
+ "lft": 10,
+ "tree_id": 90,
+ "bbox_x0": 12.20663,
+ "bbox_x1": 31.30591,
+ "bbox_y0": -13.45567,
+ "bbox_y1": 5.38609
+ }
+ },
+ {
+ "pk": 75,
+ "model": "base.region",
+ "fields": {
+ "rght": 348,
+ "code": "DNK",
+ "name": "Denmark",
+ "parent": 5,
+ "level": 2,
+ "lft": 347,
+ "tree_id": 90,
+ "bbox_x0": 8.07472,
+ "bbox_x1": 15.19324,
+ "bbox_y0": 54.559132,
+ "bbox_y1": 57.751949
+ }
+ },
+ {
+ "pk": 76,
+ "model": "base.region",
+ "fields": {
+ "rght": 19,
+ "code": "DJI",
+ "name": "Djibouti",
+ "parent": 12,
+ "level": 3,
+ "lft": 18,
+ "tree_id": 90,
+ "bbox_x0": 41.773441,
+ "bbox_x1": 43.450459,
+ "bbox_y0": 10.90991,
+ "bbox_y1": 12.70683
+ }
+ },
+ {
+ "pk": 77,
+ "model": "base.region",
+ "fields": {
+ "rght": 149,
+ "code": "DMA",
+ "name": "Dominica",
+ "parent": 255,
+ "level": 3,
+ "lft": 148,
+ "tree_id": 90,
+ "bbox_x0": -61.4841,
+ "bbox_x1": -61.244148,
+ "bbox_y0": 15.20168,
+ "bbox_y1": 15.6318
+ }
+ },
+ {
+ "pk": 78,
+ "model": "base.region",
+ "fields": {
+ "rght": 151,
+ "code": "DOM",
+ "name": "Dominican Republic",
+ "parent": 255,
+ "level": 3,
+ "lft": 150,
+ "tree_id": 90,
+ "bbox_x0": -72.003479,
+ "bbox_x1": -68.319992,
+ "bbox_y0": 17.469299,
+ "bbox_y1": 19.92985
+ }
+ },
+ {
+ "pk": 79,
+ "model": "base.region",
+ "fields": {
+ "rght": 225,
+ "code": "ECU",
+ "name": "Ecuador",
+ "parent": 4,
+ "level": 3,
+ "lft": 224,
+ "tree_id": 90,
+ "bbox_x0": -91.66124,
+ "bbox_x1": -75.200073,
+ "bbox_y0": -5.01734,
+ "bbox_y1": 1.45421
+ }
+ },
+ {
+ "pk": 80,
+ "model": "base.region",
+ "fields": {
+ "rght": 53,
+ "code": "EGY",
+ "name": "Egypt",
+ "parent": 11,
+ "level": 3,
+ "lft": 52,
+ "tree_id": 90,
+ "bbox_x0": 24.698099,
+ "bbox_x1": 36.89468,
+ "bbox_y0": 22,
+ "bbox_y1": 31.674179
+ }
+ },
+ {
+ "pk": 81,
+ "model": "base.region",
+ "fields": {
+ "rght": 193,
+ "code": "SLV",
+ "name": "El Salvador",
+ "parent": 3,
+ "level": 3,
+ "lft": 192,
+ "tree_id": 90,
+ "bbox_x0": -90.12867,
+ "bbox_x1": -87.682869,
+ "bbox_y0": 13.14867,
+ "bbox_y1": 14.44506
+ }
+ },
+ {
+ "pk": 82,
+ "model": "base.region",
+ "fields": {
+ "rght": 97,
+ "code": "GNQ",
+ "name": "Equatorial Guinea",
+ "parent": 13,
+ "level": 3,
+ "lft": 96,
+ "tree_id": 90,
+ "bbox_x0": 5.60236,
+ "bbox_x1": 11.33572,
+ "bbox_y0": -1.48378,
+ "bbox_y1": 3.78597
+ }
+ },
+ {
+ "pk": 83,
+ "model": "base.region",
+ "fields": {
+ "rght": 21,
+ "code": "ERI",
+ "name": "Eritrea",
+ "parent": 12,
+ "level": 3,
+ "lft": 20,
+ "tree_id": 90,
+ "bbox_x0": 36.43877,
+ "bbox_x1": 43.14864,
+ "bbox_y0": 12.35956,
+ "bbox_y1": 18.00308
+ }
+ },
+ {
+ "pk": 84,
+ "model": "base.region",
+ "fields": {
+ "rght": 350,
+ "code": "EST",
+ "name": "Estonia",
+ "parent": 5,
+ "level": 2,
+ "lft": 349,
+ "tree_id": 90,
+ "bbox_x0": 21.771851,
+ "bbox_x1": 28.20989,
+ "bbox_y0": 57.509312,
+ "bbox_y1": 59.685749
+ }
+ },
+ {
+ "pk": 85,
+ "model": "base.region",
+ "fields": {
+ "rght": 23,
+ "code": "ETH",
+ "name": "Ethiopia",
+ "parent": 12,
+ "level": 3,
+ "lft": 22,
+ "tree_id": 90,
+ "bbox_x0": 32.99992,
+ "bbox_x1": 47.986172,
+ "bbox_y0": 3.40242,
+ "bbox_y1": 14.89218
+ }
+ },
+ {
+ "pk": 86,
+ "model": "base.region",
+ "fields": {
+ "rght": 352,
+ "code": "FRO",
+ "name": "Faeroe Islands",
+ "parent": 5,
+ "level": 2,
+ "lft": 351,
+ "tree_id": 90,
+ "bbox_x0": -7.68124,
+ "bbox_x1": -6.25861,
+ "bbox_y0": 61.394932,
+ "bbox_y1": 62.400742
+ }
+ },
+ {
+ "pk": 87,
+ "model": "base.region",
+ "fields": {
+ "rght": 227,
+ "code": "FLK",
+ "name": "Falkland Islands (Malvinas)",
+ "parent": 4,
+ "level": 3,
+ "lft": 226,
+ "tree_id": 90,
+ "bbox_x0": -61.43404,
+ "bbox_x1": -57.712479,
+ "bbox_y0": -52.900581,
+ "bbox_y1": -50.966221
+ }
+ },
+ {
+ "pk": 88,
+ "model": "base.region",
+ "fields": {
+ "rght": 472,
+ "code": "FJI",
+ "name": "Fiji",
+ "parent": 256,
+ "level": 2,
+ "lft": 471,
+ "tree_id": 90,
+ "bbox_x0": 174.866196,
+ "bbox_x1": -178.203156,
+ "bbox_y0": -21.01712,
+ "bbox_y1": -12.46622
+ }
+ },
+ {
+ "pk": 89,
+ "model": "base.region",
+ "fields": {
+ "rght": 354,
+ "code": "FIN",
+ "name": "Finland",
+ "parent": 5,
+ "level": 2,
+ "lft": 353,
+ "tree_id": 90,
+ "bbox_x0": 20.548571,
+ "bbox_x1": 31.586201,
+ "bbox_y0": 59.764881,
+ "bbox_y1": 70.092308
+ }
+ },
+ {
+ "pk": 90,
+ "model": "base.region",
+ "fields": {
+ "rght": 356,
+ "code": "FRA",
+ "name": "France",
+ "parent": 5,
+ "level": 2,
+ "lft": 355,
+ "tree_id": 90,
+ "bbox_x0": -5.1406,
+ "bbox_x1": 9.55932,
+ "bbox_y0": 41.33374,
+ "bbox_y1": 51.089062
+ }
+ },
+ {
+ "pk": 91,
+ "model": "base.region",
+ "fields": {
+ "rght": 229,
+ "code": "GUF",
+ "name": "French Guiana",
+ "parent": 4,
+ "level": 3,
+ "lft": 228,
+ "tree_id": 90,
+ "bbox_x0": -54.542511,
+ "bbox_x1": -51.613941,
+ "bbox_y0": 2.12709,
+ "bbox_y1": 5.77649
+ }
+ },
+ {
+ "pk": 92,
+ "model": "base.region",
+ "fields": {
+ "rght": 474,
+ "code": "PYF",
+ "name": "French Polynesia",
+ "parent": 256,
+ "level": 2,
+ "lft": 473,
+ "tree_id": 90,
+ "bbox_x0": -154.700485,
+ "bbox_x1": -108.87291,
+ "bbox_y0": -27.65357,
+ "bbox_y1": 10.35983
+ }
+ },
+ {
+ "pk": 93,
+ "model": "base.region",
+ "fields": {
+ "rght": 99,
+ "code": "GAB",
+ "name": "Gabon",
+ "parent": 13,
+ "level": 3,
+ "lft": 98,
+ "tree_id": 90,
+ "bbox_x0": 8.69547,
+ "bbox_x1": 14.50234,
+ "bbox_y0": -3.9788,
+ "bbox_y1": 2.32261
+ }
+ },
+ {
+ "pk": 94,
+ "model": "base.region",
+ "fields": {
+ "rght": 101,
+ "code": "GMB",
+ "name": "Gambia",
+ "parent": 13,
+ "level": 3,
+ "lft": 100,
+ "tree_id": 90,
+ "bbox_x0": -16.82506,
+ "bbox_x1": -13.7978,
+ "bbox_y0": 13.06425,
+ "bbox_y1": 13.82657
+ }
+ },
+ {
+ "pk": 95,
+ "model": "base.region",
+ "fields": {
+ "rght": 358,
+ "code": "GEO",
+ "name": "Georgia",
+ "parent": 5,
+ "level": 2,
+ "lft": 357,
+ "tree_id": 90,
+ "bbox_x0": 40.01022,
+ "bbox_x1": 46.721359,
+ "bbox_y0": 41.038502,
+ "bbox_y1": 43.584549
+ }
+ },
+ {
+ "pk": 96,
+ "model": "base.region",
+ "fields": {
+ "rght": 360,
+ "code": "DEU",
+ "name": "Germany",
+ "parent": 5,
+ "level": 2,
+ "lft": 359,
+ "tree_id": 90,
+ "bbox_x0": 5.86624,
+ "bbox_x1": 15.04205,
+ "bbox_y0": 47.27021,
+ "bbox_y1": 55.05814
+ }
+ },
+ {
+ "pk": 97,
+ "model": "base.region",
+ "fields": {
+ "rght": 103,
+ "code": "GHA",
+ "name": "Ghana",
+ "parent": 13,
+ "level": 3,
+ "lft": 102,
+ "tree_id": 90,
+ "bbox_x0": -3.25542,
+ "bbox_x1": 1.19178,
+ "bbox_y0": 4.73672,
+ "bbox_y1": 11.1733
+ }
+ },
+ {
+ "pk": 98,
+ "model": "base.region",
+ "fields": {
+ "rght": 362,
+ "code": "GIB",
+ "name": "Gibraltar",
+ "parent": 5,
+ "level": 2,
+ "lft": 361,
+ "tree_id": 90,
+ "bbox_x0": -5.3579,
+ "bbox_x1": -5.33867,
+ "bbox_y0": 36.108219,
+ "bbox_y1": 36.15593
+ }
+ },
+ {
+ "pk": 99,
+ "model": "base.region",
+ "fields": {
+ "rght": 364,
+ "code": "GRC",
+ "name": "Greece",
+ "parent": 5,
+ "level": 2,
+ "lft": 363,
+ "tree_id": 90,
+ "bbox_x0": 19.37431,
+ "bbox_x1": 29.70056,
+ "bbox_y0": 34.809502,
+ "bbox_y1": 41.757111
+ }
+ },
+ {
+ "pk": 100,
+ "model": "base.region",
+ "fields": {
+ "rght": 207,
+ "code": "GRL",
+ "name": "Greenland",
+ "parent": 2,
+ "level": 3,
+ "lft": 206,
+ "tree_id": 90,
+ "bbox_x0": -73.263474,
+ "bbox_x1": -11.31232,
+ "bbox_y0": 59.777271,
+ "bbox_y1": 83.627419
+ }
+ },
+ {
+ "pk": 101,
+ "model": "base.region",
+ "fields": {
+ "rght": 153,
+ "code": "GRD",
+ "name": "Grenada",
+ "parent": 255,
+ "level": 3,
+ "lft": 152,
+ "tree_id": 90,
+ "bbox_x0": -61.79998,
+ "bbox_x1": -61.376362,
+ "bbox_y0": 11.98288,
+ "bbox_y1": 12.5415
+ }
+ },
+ {
+ "pk": 102,
+ "model": "base.region",
+ "fields": {
+ "rght": 155,
+ "code": "GLP",
+ "name": "Guadeloupe",
+ "parent": 255,
+ "level": 3,
+ "lft": 154,
+ "tree_id": 90,
+ "bbox_x0": -61.807159,
+ "bbox_x1": -61,
+ "bbox_y0": 15.83097,
+ "bbox_y1": 16.51684
+ }
+ },
+ {
+ "pk": 103,
+ "model": "base.region",
+ "fields": {
+ "rght": 476,
+ "code": "GUM",
+ "name": "Guam",
+ "parent": 256,
+ "level": 2,
+ "lft": 475,
+ "tree_id": 90,
+ "bbox_x0": 144.619263,
+ "bbox_x1": 144.953995,
+ "bbox_y0": 13.24059,
+ "bbox_y1": 13.65232
+ }
+ },
+ {
+ "pk": 104,
+ "model": "base.region",
+ "fields": {
+ "rght": 195,
+ "code": "GTM",
+ "name": "Guatemala",
+ "parent": 3,
+ "level": 3,
+ "lft": 194,
+ "tree_id": 90,
+ "bbox_x0": -92.241432,
+ "bbox_x1": -88.22319,
+ "bbox_y0": 13.7373,
+ "bbox_y1": 17.815201
+ }
+ },
+ {
+ "pk": 105,
+ "model": "base.region",
+ "fields": {
+ "rght": 366,
+ "code": "GGY",
+ "name": "Guernsey",
+ "parent": 5,
+ "level": 2,
+ "lft": 365,
+ "tree_id": 90,
+ "bbox_x0": -2.67545,
+ "bbox_x1": -2.16382,
+ "bbox_y0": 49.405762,
+ "bbox_y1": 49.7393
+ }
+ },
+ {
+ "pk": 106,
+ "model": "base.region",
+ "fields": {
+ "rght": 105,
+ "code": "GIN",
+ "name": "Guinea",
+ "parent": 13,
+ "level": 3,
+ "lft": 104,
+ "tree_id": 90,
+ "bbox_x0": -15.08625,
+ "bbox_x1": -7.64106,
+ "bbox_y0": 7.19355,
+ "bbox_y1": 12.67621
+ }
+ },
+ {
+ "pk": 107,
+ "model": "base.region",
+ "fields": {
+ "rght": 107,
+ "code": "GNB",
+ "name": "Guinea-Bissau",
+ "parent": 13,
+ "level": 3,
+ "lft": 106,
+ "tree_id": 90,
+ "bbox_x0": -16.717529,
+ "bbox_x1": -13.63652,
+ "bbox_y0": 10.85997,
+ "bbox_y1": 12.68078
+ }
+ },
+ {
+ "pk": 108,
+ "model": "base.region",
+ "fields": {
+ "rght": 231,
+ "code": "GUY",
+ "name": "Guyana",
+ "parent": 4,
+ "level": 3,
+ "lft": 230,
+ "tree_id": 90,
+ "bbox_x0": -61.396271,
+ "bbox_x1": -56.480251,
+ "bbox_y0": 1.17508,
+ "bbox_y1": 8.55756
+ }
+ },
+ {
+ "pk": 109,
+ "model": "base.region",
+ "fields": {
+ "rght": 157,
+ "code": "HTI",
+ "name": "Haiti",
+ "parent": 255,
+ "level": 3,
+ "lft": 156,
+ "tree_id": 90,
+ "bbox_x0": -74.478592,
+ "bbox_x1": -71.61335,
+ "bbox_y0": 18.02103,
+ "bbox_y1": 20.08782
+ }
+ },
+ {
+ "pk": 110,
+ "model": "base.region",
+ "fields": {
+ "rght": 368,
+ "code": "VAT",
+ "name": "Holy See (Vatican City)",
+ "parent": 5,
+ "level": 2,
+ "lft": 367,
+ "tree_id": 90,
+ "bbox_x0": 12.44584,
+ "bbox_x1": 12.45842,
+ "bbox_y0": 41.900211,
+ "bbox_y1": 41.907459
+ }
+ },
+ {
+ "pk": 111,
+ "model": "base.region",
+ "fields": {
+ "rght": 197,
+ "code": "HND",
+ "name": "Honduras",
+ "parent": 3,
+ "level": 3,
+ "lft": 196,
+ "tree_id": 90,
+ "bbox_x0": -89.350792,
+ "bbox_x1": -82.499527,
+ "bbox_y0": 12.98241,
+ "bbox_y1": 17.450451
+ }
+ },
+ {
+ "pk": 112,
+ "model": "base.region",
+ "fields": {
+ "rght": 370,
+ "code": "HUN",
+ "name": "Hungary",
+ "parent": 5,
+ "level": 2,
+ "lft": 369,
+ "tree_id": 90,
+ "bbox_x0": 16.11335,
+ "bbox_x1": 22.89657,
+ "bbox_y0": 45.737061,
+ "bbox_y1": 48.585258
+ }
+ },
+ {
+ "pk": 113,
+ "model": "base.region",
+ "fields": {
+ "rght": 372,
+ "code": "ISL",
+ "name": "Iceland",
+ "parent": 5,
+ "level": 2,
+ "lft": 371,
+ "tree_id": 90,
+ "bbox_x0": -24.54652,
+ "bbox_x1": -13.49416,
+ "bbox_y0": 63.295952,
+ "bbox_y1": 66.566193
+ }
+ },
+ {
+ "pk": 114,
+ "model": "base.region",
+ "fields": {
+ "rght": 283,
+ "code": "IND",
+ "name": "India",
+ "parent": 9,
+ "level": 3,
+ "lft": 282,
+ "tree_id": 90,
+ "bbox_x0": 68.032318,
+ "bbox_x1": 97.403023,
+ "bbox_y0": 6.7471,
+ "bbox_y1": 36.261688
+ }
+ },
+ {
+ "pk": 115,
+ "model": "base.region",
+ "fields": {
+ "rght": 299,
+ "code": "IDN",
+ "name": "Indonesia",
+ "parent": 7,
+ "level": 3,
+ "lft": 298,
+ "tree_id": 90,
+ "bbox_x0": 94.969833,
+ "bbox_x1": 141.021805,
+ "bbox_y0": -11.00485,
+ "bbox_y1": 6.07573
+ }
+ },
+ {
+ "pk": 116,
+ "model": "base.region",
+ "fields": {
+ "rght": 438,
+ "code": "IRN",
+ "name": "Iran",
+ "parent": 15,
+ "level": 2,
+ "lft": 437,
+ "tree_id": 90,
+ "bbox_x0": 44.047249,
+ "bbox_x1": 63.317459,
+ "bbox_y0": 25.064079,
+ "bbox_y1": 39.777222
+ }
+ },
+ {
+ "pk": 117,
+ "model": "base.region",
+ "fields": {
+ "rght": 440,
+ "code": "IRQ",
+ "name": "Iraq",
+ "parent": 15,
+ "level": 2,
+ "lft": 439,
+ "tree_id": 90,
+ "bbox_x0": 38.804001,
+ "bbox_x1": 48.575699,
+ "bbox_y0": 29.103001,
+ "bbox_y1": 37.378052
+ }
+ },
+ {
+ "pk": 118,
+ "model": "base.region",
+ "fields": {
+ "rght": 374,
+ "code": "IRL",
+ "name": "Ireland",
+ "parent": 5,
+ "level": 2,
+ "lft": 373,
+ "tree_id": 90,
+ "bbox_x0": -10.61834,
+ "bbox_x1": -5.9975,
+ "bbox_y0": 51.424511,
+ "bbox_y1": 55.436211
+ }
+ },
+ {
+ "pk": 119,
+ "model": "base.region",
+ "fields": {
+ "rght": 376,
+ "code": "IMN",
+ "name": "Isle of Man",
+ "parent": 5,
+ "level": 2,
+ "lft": 375,
+ "tree_id": 90,
+ "bbox_x0": -4.83018,
+ "bbox_x1": -4.31007,
+ "bbox_y0": 54.04464,
+ "bbox_y1": 54.418839
+ }
+ },
+ {
+ "pk": 120,
+ "model": "base.region",
+ "fields": {
+ "rght": 442,
+ "code": "ISR",
+ "name": "Israel",
+ "parent": 15,
+ "level": 2,
+ "lft": 441,
+ "tree_id": 90,
+ "bbox_x0": 34.2677,
+ "bbox_x1": 35.940941,
+ "bbox_y0": 29.4965,
+ "bbox_y1": 33.43338
+ }
+ },
+ {
+ "pk": 121,
+ "model": "base.region",
+ "fields": {
+ "rght": 378,
+ "code": "ITA",
+ "name": "Italy",
+ "parent": 5,
+ "level": 2,
+ "lft": 377,
+ "tree_id": 90,
+ "bbox_x0": 6.62665,
+ "bbox_x1": 18.520281,
+ "bbox_y0": 35.49308,
+ "bbox_y1": 47.091999
+ }
+ },
+ {
+ "pk": 122,
+ "model": "base.region",
+ "fields": {
+ "rght": 159,
+ "code": "JAM",
+ "name": "Jamaica",
+ "parent": 255,
+ "level": 3,
+ "lft": 158,
+ "tree_id": 90,
+ "bbox_x0": -78.366638,
+ "bbox_x1": -75.982857,
+ "bbox_y0": 16.949551,
+ "bbox_y1": 18.52697
+ }
+ },
+ {
+ "pk": 123,
+ "model": "base.region",
+ "fields": {
+ "rght": 271,
+ "code": "JPN",
+ "name": "Japan",
+ "parent": 258,
+ "level": 3,
+ "lft": 270,
+ "tree_id": 90,
+ "bbox_x0": 122.933647,
+ "bbox_x1": 153.986847,
+ "bbox_y0": 20.4251,
+ "bbox_y1": 45.557709
+ }
+ },
+ {
+ "pk": 124,
+ "model": "base.region",
+ "fields": {
+ "rght": 380,
+ "code": "JEY",
+ "name": "Jersey",
+ "parent": 5,
+ "level": 2,
+ "lft": 379,
+ "tree_id": 90,
+ "bbox_x0": -2.25505,
+ "bbox_x1": -2.01129,
+ "bbox_y0": 49.16209,
+ "bbox_y1": 49.26231
+ }
+ },
+ {
+ "pk": 125,
+ "model": "base.region",
+ "fields": {
+ "rght": 444,
+ "code": "JOR",
+ "name": "Jordan",
+ "parent": 15,
+ "level": 2,
+ "lft": 443,
+ "tree_id": 90,
+ "bbox_x0": 34.960232,
+ "bbox_x1": 39.301128,
+ "bbox_y0": 29.18409,
+ "bbox_y1": 33.374828
+ }
+ },
+ {
+ "pk": 126,
+ "model": "base.region",
+ "fields": {
+ "rght": 251,
+ "code": "KAZ",
+ "name": "Kazakhstan",
+ "parent": 8,
+ "level": 3,
+ "lft": 250,
+ "tree_id": 90,
+ "bbox_x0": 46.491859,
+ "bbox_x1": 87.312737,
+ "bbox_y0": 40.566689,
+ "bbox_y1": 55.431808
+ }
+ },
+ {
+ "pk": 127,
+ "model": "base.region",
+ "fields": {
+ "rght": 25,
+ "code": "KEN",
+ "name": "Kenya",
+ "parent": 12,
+ "level": 3,
+ "lft": 24,
+ "tree_id": 90,
+ "bbox_x0": 33.90884,
+ "bbox_x1": 41.899059,
+ "bbox_y0": -4.71712,
+ "bbox_y1": 4.62933
+ }
+ },
+ {
+ "pk": 128,
+ "model": "base.region",
+ "fields": {
+ "rght": 478,
+ "code": "KIR",
+ "name": "Kiribati",
+ "parent": 256,
+ "level": 2,
+ "lft": 477,
+ "tree_id": 90,
+ "bbox_x0": 158.418335,
+ "bbox_x1": -150.208359,
+ "bbox_y0": -11.43703,
+ "bbox_y1": 4.71956
+ }
+ },
+ {
+ "pk": 129,
+ "model": "base.region",
+ "fields": {
+ "rght": 446,
+ "code": "KWT",
+ "name": "Kuwait",
+ "parent": 15,
+ "level": 2,
+ "lft": 445,
+ "tree_id": 90,
+ "bbox_x0": 46.55751,
+ "bbox_x1": 48.78384,
+ "bbox_y0": 28.5245,
+ "bbox_y1": 30.0958
+ }
+ },
+ {
+ "pk": 130,
+ "model": "base.region",
+ "fields": {
+ "rght": 253,
+ "code": "KGZ",
+ "name": "Kyrgyzstan",
+ "parent": 8,
+ "level": 3,
+ "lft": 252,
+ "tree_id": 90,
+ "bbox_x0": 69.276619,
+ "bbox_x1": 80.28318,
+ "bbox_y0": 39.17284,
+ "bbox_y1": 43.238239
+ }
+ },
+ {
+ "pk": 131,
+ "model": "base.region",
+ "fields": {
+ "rght": 301,
+ "code": "LAO",
+ "name": "Lao People's Democratic Republic",
+ "parent": 7,
+ "level": 3,
+ "lft": 300,
+ "tree_id": 90,
+ "bbox_x0": 100.093048,
+ "bbox_x1": 107.697021,
+ "bbox_y0": 13.91002,
+ "bbox_y1": 22.500389
+ }
+ },
+ {
+ "pk": 132,
+ "model": "base.region",
+ "fields": {
+ "rght": 382,
+ "code": "LVA",
+ "name": "Latvia",
+ "parent": 5,
+ "level": 2,
+ "lft": 381,
+ "tree_id": 90,
+ "bbox_x0": 20.966061,
+ "bbox_x1": 28.244431,
+ "bbox_y0": 55.67276,
+ "bbox_y1": 58.087448
+ }
+ },
+ {
+ "pk": 133,
+ "model": "base.region",
+ "fields": {
+ "rght": 448,
+ "code": "LBN",
+ "name": "Lebanon",
+ "parent": 15,
+ "level": 2,
+ "lft": 447,
+ "tree_id": 90,
+ "bbox_x0": 35.10368,
+ "bbox_x1": 36.622791,
+ "bbox_y0": 33.048908,
+ "bbox_y1": 34.69268
+ }
+ },
+ {
+ "pk": 134,
+ "model": "base.region",
+ "fields": {
+ "rght": 69,
+ "code": "LSO",
+ "name": "Lesotho",
+ "parent": 14,
+ "level": 3,
+ "lft": 68,
+ "tree_id": 90,
+ "bbox_x0": 27.02906,
+ "bbox_x1": 29.465771,
+ "bbox_y0": -30.668961,
+ "bbox_y1": -28.57205
+ }
+ },
+ {
+ "pk": 135,
+ "model": "base.region",
+ "fields": {
+ "rght": 109,
+ "code": "LBR",
+ "name": "Liberia",
+ "parent": 13,
+ "level": 3,
+ "lft": 108,
+ "tree_id": 90,
+ "bbox_x0": -11.49208,
+ "bbox_x1": -7.36511,
+ "bbox_y0": 4.35305,
+ "bbox_y1": 8.55179
+ }
+ },
+ {
+ "pk": 136,
+ "model": "base.region",
+ "fields": {
+ "rght": 55,
+ "code": "LBY",
+ "name": "Libyan Arab Jamahiriya",
+ "parent": 11,
+ "level": 3,
+ "lft": 54,
+ "tree_id": 90,
+ "bbox_x0": 9.38702,
+ "bbox_x1": 25.15061,
+ "bbox_y0": 19.508039,
+ "bbox_y1": 33.168999
+ }
+ },
+ {
+ "pk": 137,
+ "model": "base.region",
+ "fields": {
+ "rght": 384,
+ "code": "LIE",
+ "name": "Liechtenstein",
+ "parent": 5,
+ "level": 2,
+ "lft": 383,
+ "tree_id": 90,
+ "bbox_x0": 9.47181,
+ "bbox_x1": 9.63578,
+ "bbox_y0": 47.04834,
+ "bbox_y1": 47.270649
+ }
+ },
+ {
+ "pk": 138,
+ "model": "base.region",
+ "fields": {
+ "rght": 386,
+ "code": "LTU",
+ "name": "Lithuania",
+ "parent": 5,
+ "level": 2,
+ "lft": 385,
+ "tree_id": 90,
+ "bbox_x0": 20.953199,
+ "bbox_x1": 26.835581,
+ "bbox_y0": 53.89748,
+ "bbox_y1": 56.450432
+ }
+ },
+ {
+ "pk": 139,
+ "model": "base.region",
+ "fields": {
+ "rght": 388,
+ "code": "LUX",
+ "name": "Luxembourg",
+ "parent": 5,
+ "level": 2,
+ "lft": 387,
+ "tree_id": 90,
+ "bbox_x0": 5.73579,
+ "bbox_x1": 6.53117,
+ "bbox_y0": 49.447689,
+ "bbox_y1": 50.182751
+ }
+ },
+ {
+ "pk": 140,
+ "model": "base.region",
+ "fields": {
+ "rght": 390,
+ "code": "MKD",
+ "name": "Macedonia",
+ "parent": 5,
+ "level": 2,
+ "lft": 389,
+ "tree_id": 90,
+ "bbox_x0": 20.4645,
+ "bbox_x1": 23.038071,
+ "bbox_y0": 40.860111,
+ "bbox_y1": 42.345501
+ }
+ },
+ {
+ "pk": 141,
+ "model": "base.region",
+ "fields": {
+ "rght": 27,
+ "code": "MDG",
+ "name": "Madagascar",
+ "parent": 12,
+ "level": 3,
+ "lft": 26,
+ "tree_id": 90,
+ "bbox_x0": 43.19138,
+ "bbox_x1": 50.483799,
+ "bbox_y0": -25.60894,
+ "bbox_y1": -11.94543
+ }
+ },
+ {
+ "pk": 142,
+ "model": "base.region",
+ "fields": {
+ "rght": 29,
+ "code": "MWI",
+ "name": "Malawi",
+ "parent": 12,
+ "level": 3,
+ "lft": 28,
+ "tree_id": 90,
+ "bbox_x0": 32.668991,
+ "bbox_x1": 35.920441,
+ "bbox_y0": -17.129459,
+ "bbox_y1": -9.36468
+ }
+ },
+ {
+ "pk": 143,
+ "model": "base.region",
+ "fields": {
+ "rght": 303,
+ "code": "MYS",
+ "name": "Malaysia",
+ "parent": 7,
+ "level": 3,
+ "lft": 302,
+ "tree_id": 90,
+ "bbox_x0": 98.935059,
+ "bbox_x1": 119.448433,
+ "bbox_y0": 0.66364,
+ "bbox_y1": 7.58378
+ }
+ },
+ {
+ "pk": 144,
+ "model": "base.region",
+ "fields": {
+ "rght": 285,
+ "code": "MDV",
+ "name": "Maldives",
+ "parent": 9,
+ "level": 3,
+ "lft": 284,
+ "tree_id": 90,
+ "bbox_x0": 72.616219,
+ "bbox_x1": 73.76712,
+ "bbox_y0": -2.90045,
+ "bbox_y1": 7.11712
+ }
+ },
+ {
+ "pk": 145,
+ "model": "base.region",
+ "fields": {
+ "rght": 111,
+ "code": "MLI",
+ "name": "Mali",
+ "parent": 13,
+ "level": 3,
+ "lft": 110,
+ "tree_id": 90,
+ "bbox_x0": -12.24261,
+ "bbox_x1": 4.24495,
+ "bbox_y0": 10.15951,
+ "bbox_y1": 25
+ }
+ },
+ {
+ "pk": 146,
+ "model": "base.region",
+ "fields": {
+ "rght": 392,
+ "code": "MLT",
+ "name": "Malta",
+ "parent": 5,
+ "level": 2,
+ "lft": 391,
+ "tree_id": 90,
+ "bbox_x0": 14.18341,
+ "bbox_x1": 14.5766,
+ "bbox_y0": 35.786282,
+ "bbox_y1": 36.081821
+ }
+ },
+ {
+ "pk": 147,
+ "model": "base.region",
+ "fields": {
+ "rght": 480,
+ "code": "MHL",
+ "name": "Marshall Islands",
+ "parent": 256,
+ "level": 2,
+ "lft": 479,
+ "tree_id": 90,
+ "bbox_x0": 162.143265,
+ "bbox_x1": 172.161987,
+ "bbox_y0": 4.57487,
+ "bbox_y1": 14.65516
+ }
+ },
+ {
+ "pk": 148,
+ "model": "base.region",
+ "fields": {
+ "rght": 161,
+ "code": "MTQ",
+ "name": "Martinique",
+ "parent": 255,
+ "level": 3,
+ "lft": 160,
+ "tree_id": 90,
+ "bbox_x0": -61.23011,
+ "bbox_x1": -60.81551,
+ "bbox_y0": 14.38244,
+ "bbox_y1": 14.87881
+ }
+ },
+ {
+ "pk": 149,
+ "model": "base.region",
+ "fields": {
+ "rght": 113,
+ "code": "MRT",
+ "name": "Mauritania",
+ "parent": 13,
+ "level": 3,
+ "lft": 112,
+ "tree_id": 90,
+ "bbox_x0": -17.066521,
+ "bbox_x1": -4.8352,
+ "bbox_y0": 14.71554,
+ "bbox_y1": 27.298071
+ }
+ },
+ {
+ "pk": 150,
+ "model": "base.region",
+ "fields": {
+ "rght": 31,
+ "code": "MUS",
+ "name": "Mauritius",
+ "parent": 12,
+ "level": 3,
+ "lft": 30,
+ "tree_id": 90,
+ "bbox_x0": 56.512711,
+ "bbox_x1": 63.525379,
+ "bbox_y0": -20.525709,
+ "bbox_y1": -10.31925
+ }
+ },
+ {
+ "pk": 151,
+ "model": "base.region",
+ "fields": {
+ "rght": 33,
+ "code": "MYT",
+ "name": "Mayotte",
+ "parent": 12,
+ "level": 3,
+ "lft": 32,
+ "tree_id": 90,
+ "bbox_x0": 45.01461,
+ "bbox_x1": 45.317131,
+ "bbox_y0": -13.00045,
+ "bbox_y1": -12.63383
+ }
+ },
+ {
+ "pk": 152,
+ "model": "base.region",
+ "fields": {
+ "rght": 209,
+ "code": "MEX",
+ "name": "Mexico",
+ "parent": 2,
+ "level": 3,
+ "lft": 208,
+ "tree_id": 90,
+ "bbox_x0": -118.867172,
+ "bbox_x1": -86.703392,
+ "bbox_y0": 14.53285,
+ "bbox_y1": 32.71862
+ }
+ },
+ {
+ "pk": 153,
+ "model": "base.region",
+ "fields": {
+ "rght": 482,
+ "code": "FSM",
+ "name": "Micronesia, Federated States of",
+ "parent": 256,
+ "level": 2,
+ "lft": 481,
+ "tree_id": 90,
+ "bbox_x0": 138.052856,
+ "bbox_x1": 163.034912,
+ "bbox_y0": 5.25984,
+ "bbox_y1": 10.02222
+ }
+ },
+ {
+ "pk": 154,
+ "model": "base.region",
+ "fields": {
+ "rght": 394,
+ "code": "MCO",
+ "name": "Monaco",
+ "parent": 5,
+ "level": 2,
+ "lft": 393,
+ "tree_id": 90,
+ "bbox_x0": 7.4091,
+ "bbox_x1": 7.43948,
+ "bbox_y0": 43.724789,
+ "bbox_y1": 43.7519
+ }
+ },
+ {
+ "pk": 155,
+ "model": "base.region",
+ "fields": {
+ "rght": 273,
+ "code": "MNG",
+ "name": "Mongolia",
+ "parent": 258,
+ "level": 3,
+ "lft": 272,
+ "tree_id": 90,
+ "bbox_x0": 87.749496,
+ "bbox_x1": 119.92411,
+ "bbox_y0": 41.567501,
+ "bbox_y1": 52.154099
+ }
+ },
+ {
+ "pk": 156,
+ "model": "base.region",
+ "fields": {
+ "rght": 396,
+ "code": "MNE",
+ "name": "Montenegro",
+ "parent": 5,
+ "level": 2,
+ "lft": 395,
+ "tree_id": 90,
+ "bbox_x0": 18.43705,
+ "bbox_x1": 20.41608,
+ "bbox_y0": 41.84808,
+ "bbox_y1": 43.542912
+ }
+ },
+ {
+ "pk": 157,
+ "model": "base.region",
+ "fields": {
+ "rght": 163,
+ "code": "MSR",
+ "name": "Montserrat",
+ "parent": 255,
+ "level": 3,
+ "lft": 162,
+ "tree_id": 90,
+ "bbox_x0": -62.24258,
+ "bbox_x1": -62.14642,
+ "bbox_y0": 16.671,
+ "bbox_y1": 16.81732
+ }
+ },
+ {
+ "pk": 158,
+ "model": "base.region",
+ "fields": {
+ "rght": 57,
+ "code": "MAR",
+ "name": "Morocco",
+ "parent": 11,
+ "level": 3,
+ "lft": 56,
+ "tree_id": 90,
+ "bbox_x0": -11.7805,
+ "bbox_x1": -1.02441,
+ "bbox_y0": 26.946489,
+ "bbox_y1": 35.921909
+ }
+ },
+ {
+ "pk": 159,
+ "model": "base.region",
+ "fields": {
+ "rght": 35,
+ "code": "MOZ",
+ "name": "Mozambique",
+ "parent": 12,
+ "level": 3,
+ "lft": 34,
+ "tree_id": 90,
+ "bbox_x0": 30.21731,
+ "bbox_x1": 40.844471,
+ "bbox_y0": -26.868679,
+ "bbox_y1": -10.47188
+ }
+ },
+ {
+ "pk": 160,
+ "model": "base.region",
+ "fields": {
+ "rght": 305,
+ "code": "MMR",
+ "name": "Myanmar",
+ "parent": 7,
+ "level": 3,
+ "lft": 304,
+ "tree_id": 90,
+ "bbox_x0": 92.189209,
+ "bbox_x1": 101.176788,
+ "bbox_y0": 9.60035,
+ "bbox_y1": 28.543249
+ }
+ },
+ {
+ "pk": 161,
+ "model": "base.region",
+ "fields": {
+ "rght": 71,
+ "code": "NMB",
+ "name": "Namibia",
+ "parent": 14,
+ "level": 3,
+ "lft": 70,
+ "tree_id": 90,
+ "bbox_x0": 11.71563,
+ "bbox_x1": 25.256701,
+ "bbox_y0": -28.97142,
+ "bbox_y1": -16.95989
+ }
+ },
+ {
+ "pk": 162,
+ "model": "base.region",
+ "fields": {
+ "rght": 484,
+ "code": "NRU",
+ "name": "Nauru",
+ "parent": 256,
+ "level": 2,
+ "lft": 483,
+ "tree_id": 90,
+ "bbox_x0": 166.899017,
+ "bbox_x1": 166.945267,
+ "bbox_y0": -0.55232,
+ "bbox_y1": -0.50429
+ }
+ },
+ {
+ "pk": 163,
+ "model": "base.region",
+ "fields": {
+ "rght": 287,
+ "code": "NPL",
+ "name": "Nepal",
+ "parent": 9,
+ "level": 3,
+ "lft": 286,
+ "tree_id": 90,
+ "bbox_x0": 80.056221,
+ "bbox_x1": 88.199318,
+ "bbox_y0": 26.356501,
+ "bbox_y1": 30.433001
+ }
+ },
+ {
+ "pk": 164,
+ "model": "base.region",
+ "fields": {
+ "rght": 398,
+ "code": "NLD",
+ "name": "Netherlands",
+ "parent": 5,
+ "level": 2,
+ "lft": 397,
+ "tree_id": 90,
+ "bbox_x0": 3.35794,
+ "bbox_x1": 7.2267,
+ "bbox_y0": 50.750401,
+ "bbox_y1": 53.554241
+ }
+ },
+ {
+ "pk": 165,
+ "model": "base.region",
+ "fields": {
+ "rght": 165,
+ "code": "NAN",
+ "name": "Netherlands Antilles",
+ "parent": 255,
+ "level": 3,
+ "lft": 164,
+ "tree_id": 90,
+ "bbox_x0": -69.157188,
+ "bbox_x1": -62.943661,
+ "bbox_y0": 11.97318,
+ "bbox_y1": 18.07024
+ }
+ },
+ {
+ "pk": 166,
+ "model": "base.region",
+ "fields": {
+ "rght": 486,
+ "code": "NCL",
+ "name": "New Caledonia",
+ "parent": 256,
+ "level": 2,
+ "lft": 485,
+ "tree_id": 90,
+ "bbox_x0": 158.332855,
+ "bbox_x1": 172.061417,
+ "bbox_y0": -22.90045,
+ "bbox_y1": -18.01622
+ }
+ },
+ {
+ "pk": 167,
+ "model": "base.region",
+ "fields": {
+ "rght": 488,
+ "code": "NZL",
+ "name": "New Zealand",
+ "parent": 256,
+ "level": 2,
+ "lft": 487,
+ "tree_id": 90,
+ "bbox_x0": 165.883804,
+ "bbox_x1": -175.987198,
+ "bbox_y0": -52.618591,
+ "bbox_y1": -29.20997
+ }
+ },
+ {
+ "pk": 168,
+ "model": "base.region",
+ "fields": {
+ "rght": 199,
+ "code": "NIC",
+ "name": "Nicaragua",
+ "parent": 3,
+ "level": 3,
+ "lft": 198,
+ "tree_id": 90,
+ "bbox_x0": -87.6903,
+ "bbox_x1": -82.592072,
+ "bbox_y0": 10.70754,
+ "bbox_y1": 15.0259
+ }
+ },
+ {
+ "pk": 169,
+ "model": "base.region",
+ "fields": {
+ "rght": 115,
+ "code": "NER",
+ "name": "Niger",
+ "parent": 13,
+ "level": 3,
+ "lft": 114,
+ "tree_id": 90,
+ "bbox_x0": 0.16625,
+ "bbox_x1": 15.99564,
+ "bbox_y0": 11.69697,
+ "bbox_y1": 23.525021
+ }
+ },
+ {
+ "pk": 170,
+ "model": "base.region",
+ "fields": {
+ "rght": 117,
+ "code": "NGA",
+ "name": "Nigeria",
+ "parent": 13,
+ "level": 3,
+ "lft": 116,
+ "tree_id": 90,
+ "bbox_x0": 2.66844,
+ "bbox_x1": 14.68006,
+ "bbox_y0": 4.27714,
+ "bbox_y1": 13.892
+ }
+ },
+ {
+ "pk": 171,
+ "model": "base.region",
+ "fields": {
+ "rght": 490,
+ "code": "NIU",
+ "name": "Niue",
+ "parent": 256,
+ "level": 2,
+ "lft": 489,
+ "tree_id": 90,
+ "bbox_x0": -169.951004,
+ "bbox_x1": -169.775177,
+ "bbox_y0": -19.152189,
+ "bbox_y1": -18.951059
+ }
+ },
+ {
+ "pk": 172,
+ "model": "base.region",
+ "fields": {
+ "rght": 492,
+ "code": "NFK",
+ "name": "Norfolk Island",
+ "parent": 256,
+ "level": 2,
+ "lft": 491,
+ "tree_id": 90,
+ "bbox_x0": 167.949493,
+ "bbox_x1": 168.091614,
+ "bbox_y0": -29.11937,
+ "bbox_y1": -28.99493
+ }
+ },
+ {
+ "pk": 173,
+ "model": "base.region",
+ "fields": {
+ "rght": 494,
+ "code": "MNP",
+ "name": "Northern Mariana Islands",
+ "parent": 256,
+ "level": 2,
+ "lft": 493,
+ "tree_id": 90,
+ "bbox_x0": 136.082855,
+ "bbox_x1": 146.081223,
+ "bbox_y0": 14.10735,
+ "bbox_y1": 20.41712
+ }
+ },
+ {
+ "pk": 174,
+ "model": "base.region",
+ "fields": {
+ "rght": 400,
+ "code": "NOR",
+ "name": "Norway",
+ "parent": 5,
+ "level": 2,
+ "lft": 399,
+ "tree_id": 90,
+ "bbox_x0": 4.43292,
+ "bbox_x1": 31.168409,
+ "bbox_y0": 57.962582,
+ "bbox_y1": 71.185509
+ }
+ },
+ {
+ "pk": 175,
+ "model": "base.region",
+ "fields": {
+ "rght": 450,
+ "code": "PSE",
+ "name": "Occupied Palestinian Territory",
+ "parent": 15,
+ "level": 2,
+ "lft": 449,
+ "tree_id": 90,
+ "bbox_x0": 34.230461,
+ "bbox_x1": 35.876499,
+ "bbox_y0": 31.223499,
+ "bbox_y1": 33.340099
+ }
+ },
+ {
+ "pk": 176,
+ "model": "base.region",
+ "fields": {
+ "rght": 452,
+ "code": "OMN",
+ "name": "Oman",
+ "parent": 15,
+ "level": 2,
+ "lft": 451,
+ "tree_id": 90,
+ "bbox_x0": 51.882011,
+ "bbox_x1": 59.83651,
+ "bbox_y0": 16.6457,
+ "bbox_y1": 26.50045
+ }
+ },
+ {
+ "pk": 177,
+ "model": "base.region",
+ "fields": {
+ "rght": 289,
+ "code": "PAK",
+ "name": "Pakistan",
+ "parent": 9,
+ "level": 3,
+ "lft": 288,
+ "tree_id": 90,
+ "bbox_x0": 60.87859,
+ "bbox_x1": 77.840813,
+ "bbox_y0": 23.786699,
+ "bbox_y1": 37.097
+ }
+ },
+ {
+ "pk": 178,
+ "model": "base.region",
+ "fields": {
+ "rght": 496,
+ "code": "PLW",
+ "name": "Palau",
+ "parent": 256,
+ "level": 2,
+ "lft": 495,
+ "tree_id": 90,
+ "bbox_x0": 131.169235,
+ "bbox_x1": 134.723724,
+ "bbox_y0": 3.00114,
+ "bbox_y1": 8.09291
+ }
+ },
+ {
+ "pk": 179,
+ "model": "base.region",
+ "fields": {
+ "rght": 201,
+ "code": "PAN",
+ "name": "Panama",
+ "parent": 3,
+ "level": 3,
+ "lft": 200,
+ "tree_id": 90,
+ "bbox_x0": -83.051453,
+ "bbox_x1": -77.17411,
+ "bbox_y0": 7.1979,
+ "bbox_y1": 9.65045
+ }
+ },
+ {
+ "pk": 180,
+ "model": "base.region",
+ "fields": {
+ "rght": 498,
+ "code": "PNG",
+ "name": "Papua New Guinea",
+ "parent": 256,
+ "level": 2,
+ "lft": 497,
+ "tree_id": 90,
+ "bbox_x0": 140.842865,
+ "bbox_x1": 159.48378,
+ "bbox_y0": -11.65785,
+ "bbox_y1": -0.86622
+ }
+ },
+ {
+ "pk": 181,
+ "model": "base.region",
+ "fields": {
+ "rght": 233,
+ "code": "PRY",
+ "name": "Paraguay",
+ "parent": 4,
+ "level": 3,
+ "lft": 232,
+ "tree_id": 90,
+ "bbox_x0": -62.647072,
+ "bbox_x1": -54.25935,
+ "bbox_y0": -27.60873,
+ "bbox_y1": -19.294041
+ }
+ },
+ {
+ "pk": 182,
+ "model": "base.region",
+ "fields": {
+ "rght": 235,
+ "code": "PER",
+ "name": "Peru",
+ "parent": 4,
+ "level": 3,
+ "lft": 234,
+ "tree_id": 90,
+ "bbox_x0": -81.326736,
+ "bbox_x1": -68.677979,
+ "bbox_y0": -18.34972,
+ "bbox_y1": -0.01297
+ }
+ },
+ {
+ "pk": 183,
+ "model": "base.region",
+ "fields": {
+ "rght": 307,
+ "code": "PHL",
+ "name": "Philippines",
+ "parent": 7,
+ "level": 3,
+ "lft": 306,
+ "tree_id": 90,
+ "bbox_x0": 116.812721,
+ "bbox_x1": 126.856628,
+ "bbox_y0": 4.46811,
+ "bbox_y1": 21.23415
+ }
+ },
+ {
+ "pk": 184,
+ "model": "base.region",
+ "fields": {
+ "rght": 500,
+ "code": "PCN",
+ "name": "Pitcairn",
+ "parent": 256,
+ "level": 2,
+ "lft": 499,
+ "tree_id": 90,
+ "bbox_x0": -130.746033,
+ "bbox_x1": -124.772842,
+ "bbox_y0": -25.07752,
+ "bbox_y1": -23.917271
+ }
+ },
+ {
+ "pk": 185,
+ "model": "base.region",
+ "fields": {
+ "rght": 402,
+ "code": "POL",
+ "name": "Poland",
+ "parent": 5,
+ "level": 2,
+ "lft": 401,
+ "tree_id": 90,
+ "bbox_x0": 14.12281,
+ "bbox_x1": 24.145781,
+ "bbox_y0": 49.002022,
+ "bbox_y1": 54.835812
+ }
+ },
+ {
+ "pk": 186,
+ "model": "base.region",
+ "fields": {
+ "rght": 404,
+ "code": "PRT",
+ "name": "Portugal",
+ "parent": 5,
+ "level": 2,
+ "lft": 403,
+ "tree_id": 90,
+ "bbox_x0": -31.266001,
+ "bbox_x1": -6.18931,
+ "bbox_y0": 30.028061,
+ "bbox_y1": 42.154121
+ }
+ },
+ {
+ "pk": 187,
+ "model": "base.region",
+ "fields": {
+ "rght": 167,
+ "code": "PRI",
+ "name": "Puerto Rico",
+ "parent": 255,
+ "level": 3,
+ "lft": 166,
+ "tree_id": 90,
+ "bbox_x0": -67.942719,
+ "bbox_x1": -65.219978,
+ "bbox_y0": 17.883039,
+ "bbox_y1": 18.520161
+ }
+ },
+ {
+ "pk": 188,
+ "model": "base.region",
+ "fields": {
+ "rght": 454,
+ "code": "QAT",
+ "name": "Qatar",
+ "parent": 15,
+ "level": 2,
+ "lft": 453,
+ "tree_id": 90,
+ "bbox_x0": 50.757011,
+ "bbox_x1": 52.427509,
+ "bbox_y0": 24.482901,
+ "bbox_y1": 26.177509
+ }
+ },
+ {
+ "pk": 189,
+ "model": "base.region",
+ "fields": {
+ "rght": 275,
+ "code": "KOR",
+ "name": "Republic of Korea",
+ "parent": 258,
+ "level": 3,
+ "lft": 274,
+ "tree_id": 90,
+ "bbox_x0": 124.608147,
+ "bbox_x1": 130.933899,
+ "bbox_y0": 33.10611,
+ "bbox_y1": 38.612301
+ }
+ },
+ {
+ "pk": 190,
+ "model": "base.region",
+ "fields": {
+ "rght": 406,
+ "code": "MDA",
+ "name": "Republic of Moldova",
+ "parent": 5,
+ "level": 2,
+ "lft": 405,
+ "tree_id": 90,
+ "bbox_x0": 26.618879,
+ "bbox_x1": 30.16374,
+ "bbox_y0": 45.468498,
+ "bbox_y1": 48.490162
+ }
+ },
+ {
+ "pk": 191,
+ "model": "base.region",
+ "fields": {
+ "rght": 37,
+ "code": "REU",
+ "name": "Reunion",
+ "parent": 12,
+ "level": 3,
+ "lft": 36,
+ "tree_id": 90,
+ "bbox_x0": 55.219082,
+ "bbox_x1": 55.845039,
+ "bbox_y0": -21.37221,
+ "bbox_y1": -20.85685
+ }
+ },
+ {
+ "pk": 192,
+ "model": "base.region",
+ "fields": {
+ "rght": 408,
+ "code": "ROU",
+ "name": "Romania",
+ "parent": 5,
+ "level": 2,
+ "lft": 407,
+ "tree_id": 90,
+ "bbox_x0": 20.269791,
+ "bbox_x1": 29.691,
+ "bbox_y0": 43.626999,
+ "bbox_y1": 48.266891
+ }
+ },
+ {
+ "pk": 193,
+ "model": "base.region",
+ "fields": {
+ "rght": 410,
+ "code": "RUS",
+ "name": "Russian Federation",
+ "parent": 5,
+ "level": 2,
+ "lft": 409,
+ "tree_id": 90,
+ "bbox_x0": 19.638861,
+ "bbox_x1": 180,
+ "bbox_y0": 41.185902,
+ "bbox_y1": 81.856903
+ }
+ },
+ {
+ "pk": 194,
+ "model": "base.region",
+ "fields": {
+ "rght": 39,
+ "code": "RWA",
+ "name": "Rwanda",
+ "parent": 12,
+ "level": 3,
+ "lft": 38,
+ "tree_id": 90,
+ "bbox_x0": 28.8568,
+ "bbox_x1": 30.89596,
+ "bbox_y0": -2.84067,
+ "bbox_y1": -1.05348
+ }
+ },
+ {
+ "pk": 195,
+ "model": "base.region",
+ "fields": {
+ "rght": 73,
+ "code": "SHN",
+ "name": "Saint Helena",
+ "parent": 14,
+ "level": 3,
+ "lft": 72,
+ "tree_id": 90,
+ "bbox_x0": -14.44153,
+ "bbox_x1": -5.63286,
+ "bbox_y0": -40.400452,
+ "bbox_y1": -7.87757
+ }
+ },
+ {
+ "pk": 196,
+ "model": "base.region",
+ "fields": {
+ "rght": 169,
+ "code": "KNA",
+ "name": "Saint Kitts and Nevis",
+ "parent": 255,
+ "level": 3,
+ "lft": 168,
+ "tree_id": 90,
+ "bbox_x0": -62.86956,
+ "bbox_x1": -62.543259,
+ "bbox_y0": 17.095341,
+ "bbox_y1": 17.420111
+ }
+ },
+ {
+ "pk": 197,
+ "model": "base.region",
+ "fields": {
+ "rght": 171,
+ "code": "LCA",
+ "name": "Saint Lucia",
+ "parent": 255,
+ "level": 3,
+ "lft": 170,
+ "tree_id": 90,
+ "bbox_x0": -61.07415,
+ "bbox_x1": -60.866051,
+ "bbox_y0": 13.70477,
+ "bbox_y1": 14.10324
+ }
+ },
+ {
+ "pk": 198,
+ "model": "base.region",
+ "fields": {
+ "rght": 173,
+ "code": "SPM",
+ "name": "Saint Pierre and Miquelon",
+ "parent": 255,
+ "level": 3,
+ "lft": 172,
+ "tree_id": 90,
+ "bbox_x0": -56.420658,
+ "bbox_x1": -56.157372,
+ "bbox_y0": 46.753269,
+ "bbox_y1": 47.14629
+ }
+ },
+ {
+ "pk": 199,
+ "model": "base.region",
+ "fields": {
+ "rght": 175,
+ "code": "VCT",
+ "name": "Saint Vincent and the Grenadines",
+ "parent": 255,
+ "level": 3,
+ "lft": 174,
+ "tree_id": 90,
+ "bbox_x0": -61.459251,
+ "bbox_x1": -61.11388,
+ "bbox_y0": 12.58101,
+ "bbox_y1": 13.37783
+ }
+ },
+ {
+ "pk": 200,
+ "model": "base.region",
+ "fields": {
+ "rght": 177,
+ "code": "BLM",
+ "name": "Saint-Barthelemy",
+ "parent": 255,
+ "level": 3,
+ "lft": 176,
+ "tree_id": 90,
+ "bbox_x0": -62.9338,
+ "bbox_x1": -62.78286,
+ "bbox_y0": 17.86622,
+ "bbox_y1": 17.968599
+ }
+ },
+ {
+ "pk": 201,
+ "model": "base.region",
+ "fields": {
+ "rght": 179,
+ "code": "MAF",
+ "name": "Saint-Martin (French part)",
+ "parent": 255,
+ "level": 3,
+ "lft": 178,
+ "tree_id": 90,
+ "bbox_x0": -63.15276,
+ "bbox_x1": -62.972778,
+ "bbox_y0": 18.052231,
+ "bbox_y1": 18.13069
+ }
+ },
+ {
+ "pk": 202,
+ "model": "base.region",
+ "fields": {
+ "rght": 502,
+ "code": "WSM",
+ "name": "Samoa",
+ "parent": 256,
+ "level": 2,
+ "lft": 501,
+ "tree_id": 90,
+ "bbox_x0": -172.798584,
+ "bbox_x1": -171.33287,
+ "bbox_y0": -14.06353,
+ "bbox_y1": -13.4322
+ }
+ },
+ {
+ "pk": 203,
+ "model": "base.region",
+ "fields": {
+ "rght": 412,
+ "code": "SMR",
+ "name": "San Marino",
+ "parent": 5,
+ "level": 2,
+ "lft": 411,
+ "tree_id": 90,
+ "bbox_x0": 12.40306,
+ "bbox_x1": 12.51651,
+ "bbox_y0": 43.893299,
+ "bbox_y1": 43.992168
+ }
+ },
+ {
+ "pk": 204,
+ "model": "base.region",
+ "fields": {
+ "rght": 119,
+ "code": "STP",
+ "name": "Sao Tome and Principe",
+ "parent": 13,
+ "level": 3,
+ "lft": 118,
+ "tree_id": 90,
+ "bbox_x0": 5.59955,
+ "bbox_x1": 7.46637,
+ "bbox_y0": -0.014,
+ "bbox_y1": 1.73378
+ }
+ },
+ {
+ "pk": 205,
+ "model": "base.region",
+ "fields": {
+ "rght": 456,
+ "code": "SAU",
+ "name": "Saudi Arabia",
+ "parent": 15,
+ "level": 2,
+ "lft": 455,
+ "tree_id": 90,
+ "bbox_x0": 34.508282,
+ "bbox_x1": 55.666672,
+ "bbox_y0": 16.261169,
+ "bbox_y1": 32.173481
+ }
+ },
+ {
+ "pk": 206,
+ "model": "base.region",
+ "fields": {
+ "rght": 121,
+ "code": "SEN",
+ "name": "Senegal",
+ "parent": 13,
+ "level": 3,
+ "lft": 120,
+ "tree_id": 90,
+ "bbox_x0": -17.535231,
+ "bbox_x1": -11.35588,
+ "bbox_y0": 12.30727,
+ "bbox_y1": 16.691629
+ }
+ },
+ {
+ "pk": 207,
+ "model": "base.region",
+ "fields": {
+ "rght": 414,
+ "code": "SRB",
+ "name": "Serbia",
+ "parent": 5,
+ "level": 2,
+ "lft": 413,
+ "tree_id": 90,
+ "bbox_x0": 18.814581,
+ "bbox_x1": 23.007,
+ "bbox_y0": 41.908611,
+ "bbox_y1": 46.191002
+ }
+ },
+ {
+ "pk": 208,
+ "model": "base.region",
+ "fields": {
+ "rght": 41,
+ "code": "SYC",
+ "name": "Seychelles",
+ "parent": 12,
+ "level": 3,
+ "lft": 40,
+ "tree_id": 90,
+ "bbox_x0": 46.199211,
+ "bbox_x1": 56.279499,
+ "bbox_y0": -10.21712,
+ "bbox_y1": -3.71151
+ }
+ },
+ {
+ "pk": 209,
+ "model": "base.region",
+ "fields": {
+ "rght": 123,
+ "code": "SLE",
+ "name": "Sierra Leone",
+ "parent": 13,
+ "level": 3,
+ "lft": 122,
+ "tree_id": 90,
+ "bbox_x0": -13.30763,
+ "bbox_x1": -10.28423,
+ "bbox_y0": 6.92868,
+ "bbox_y1": 10.00043
+ }
+ },
+ {
+ "pk": 210,
+ "model": "base.region",
+ "fields": {
+ "rght": 309,
+ "code": "SGP",
+ "name": "Singapore",
+ "parent": 7,
+ "level": 3,
+ "lft": 308,
+ "tree_id": 90,
+ "bbox_x0": 103.618248,
+ "bbox_x1": 104.40847,
+ "bbox_y0": 1.1158,
+ "bbox_y1": 1.47062
+ }
+ },
+ {
+ "pk": 211,
+ "model": "base.region",
+ "fields": {
+ "rght": 416,
+ "code": "SVK",
+ "name": "Slovakia",
+ "parent": 5,
+ "level": 2,
+ "lft": 415,
+ "tree_id": 90,
+ "bbox_x0": 16.833179,
+ "bbox_x1": 22.570299,
+ "bbox_y0": 47.728001,
+ "bbox_y1": 49.603001
+ }
+ },
+ {
+ "pk": 212,
+ "model": "base.region",
+ "fields": {
+ "rght": 418,
+ "code": "SVN",
+ "name": "Slovenia",
+ "parent": 5,
+ "level": 2,
+ "lft": 417,
+ "tree_id": 90,
+ "bbox_x0": 13.37551,
+ "bbox_x1": 16.59656,
+ "bbox_y0": 45.416,
+ "bbox_y1": 46.87788
+ }
+ },
+ {
+ "pk": 213,
+ "model": "base.region",
+ "fields": {
+ "rght": 504,
+ "code": "SLB",
+ "name": "Solomon Islands",
+ "parent": 256,
+ "level": 2,
+ "lft": 503,
+ "tree_id": 90,
+ "bbox_x0": 155.508667,
+ "bbox_x1": 170.200455,
+ "bbox_y0": -12.2919,
+ "bbox_y1": -5.16622
+ }
+ },
+ {
+ "pk": 214,
+ "model": "base.region",
+ "fields": {
+ "rght": 43,
+ "code": "SOM",
+ "name": "Somalia",
+ "parent": 12,
+ "level": 3,
+ "lft": 42,
+ "tree_id": 90,
+ "bbox_x0": 40.988628,
+ "bbox_x1": 51.413029,
+ "bbox_y0": -1.66205,
+ "bbox_y1": 11.9852
+ }
+ },
+ {
+ "pk": 215,
+ "model": "base.region",
+ "fields": {
+ "rght": 75,
+ "code": "ZAF",
+ "name": "South Africa",
+ "parent": 14,
+ "level": 3,
+ "lft": 74,
+ "tree_id": 90,
+ "bbox_x0": 16.46841,
+ "bbox_x1": 37.993172,
+ "bbox_y0": -46.990009,
+ "bbox_y1": -22.12472
+ }
+ },
+ {
+ "pk": 216,
+ "model": "base.region",
+ "fields": {
+ "rght": 420,
+ "code": "ESP",
+ "name": "Spain",
+ "parent": 5,
+ "level": 2,
+ "lft": 419,
+ "tree_id": 90,
+ "bbox_x0": -18.160789,
+ "bbox_x1": 4.32788,
+ "bbox_y0": 27.63546,
+ "bbox_y1": 43.789959
+ }
+ },
+ {
+ "pk": 217,
+ "model": "base.region",
+ "fields": {
+ "rght": 291,
+ "code": "LKA",
+ "name": "Sri Lanka",
+ "parent": 9,
+ "level": 3,
+ "lft": 290,
+ "tree_id": 90,
+ "bbox_x0": 79.516212,
+ "bbox_x1": 81.88121,
+ "bbox_y0": 5.9167,
+ "bbox_y1": 9.8312
+ }
+ },
+ {
+ "pk": 218,
+ "model": "base.region",
+ "fields": {
+ "rght": 59,
+ "code": "SDN",
+ "name": "Sudan",
+ "parent": 11,
+ "level": 3,
+ "lft": 58,
+ "tree_id": 90,
+ "bbox_x0": 21.83894,
+ "bbox_x1": 38.833801,
+ "bbox_y0": 3.48639,
+ "bbox_y1": 23.146891
+ }
+ },
+ {
+ "pk": 219,
+ "model": "base.region",
+ "fields": {
+ "rght": 237,
+ "code": "SUR",
+ "name": "Suriname",
+ "parent": 4,
+ "level": 3,
+ "lft": 236,
+ "tree_id": 90,
+ "bbox_x0": -58.086559,
+ "bbox_x1": -53.977489,
+ "bbox_y0": 1.83114,
+ "bbox_y1": 6.00454
+ }
+ },
+ {
+ "pk": 220,
+ "model": "base.region",
+ "fields": {
+ "rght": 422,
+ "code": "SJM",
+ "name": "Svalbard and Jan Mayen Islands",
+ "parent": 5,
+ "level": 2,
+ "lft": 421,
+ "tree_id": 90,
+ "bbox_x0": -9.07989,
+ "bbox_x1": 36.815269,
+ "bbox_y0": 70.82737,
+ "bbox_y1": 80.834061
+ }
+ },
+ {
+ "pk": 221,
+ "model": "base.region",
+ "fields": {
+ "rght": 77,
+ "code": "SWZ",
+ "name": "Swaziland",
+ "parent": 14,
+ "level": 3,
+ "lft": 76,
+ "tree_id": 90,
+ "bbox_x0": 30.7941,
+ "bbox_x1": 32.137272,
+ "bbox_y0": -27.317101,
+ "bbox_y1": -25.719641
+ }
+ },
+ {
+ "pk": 222,
+ "model": "base.region",
+ "fields": {
+ "rght": 424,
+ "code": "SWE",
+ "name": "Sweden",
+ "parent": 5,
+ "level": 2,
+ "lft": 423,
+ "tree_id": 90,
+ "bbox_x0": 10.9661,
+ "bbox_x1": 24.16634,
+ "bbox_y0": 55.33696,
+ "bbox_y1": 69.059937
+ }
+ },
+ {
+ "pk": 223,
+ "model": "base.region",
+ "fields": {
+ "rght": 426,
+ "code": "CHE",
+ "name": "Switzerland",
+ "parent": 5,
+ "level": 2,
+ "lft": 425,
+ "tree_id": 90,
+ "bbox_x0": 5.95587,
+ "bbox_x1": 10.49203,
+ "bbox_y0": 45.81802,
+ "bbox_y1": 47.80838
+ }
+ },
+ {
+ "pk": 224,
+ "model": "base.region",
+ "fields": {
+ "rght": 458,
+ "code": "SYR",
+ "name": "Syrian Arab Republic",
+ "parent": 15,
+ "level": 2,
+ "lft": 457,
+ "tree_id": 90,
+ "bbox_x0": 35.727001,
+ "bbox_x1": 42.384998,
+ "bbox_y0": 32.3106,
+ "bbox_y1": 37.319
+ }
+ },
+ {
+ "pk": 225,
+ "model": "base.region",
+ "fields": {
+ "rght": 255,
+ "code": "TJK",
+ "name": "Tajikistan",
+ "parent": 8,
+ "level": 3,
+ "lft": 254,
+ "tree_id": 90,
+ "bbox_x0": 67.387131,
+ "bbox_x1": 75.137222,
+ "bbox_y0": 36.674141,
+ "bbox_y1": 41.04224
+ }
+ },
+ {
+ "pk": 226,
+ "model": "base.region",
+ "fields": {
+ "rght": 311,
+ "code": "THA",
+ "name": "Thailand",
+ "parent": 7,
+ "level": 3,
+ "lft": 310,
+ "tree_id": 90,
+ "bbox_x0": 97.343964,
+ "bbox_x1": 105.636917,
+ "bbox_y0": 5.61257,
+ "bbox_y1": 20.464701
+ }
+ },
+ {
+ "pk": 227,
+ "model": "base.region",
+ "fields": {
+ "rght": 313,
+ "code": "TLS",
+ "name": "Timor-Leste",
+ "parent": 7,
+ "level": 3,
+ "lft": 312,
+ "tree_id": 90,
+ "bbox_x0": 124.075439,
+ "bbox_x1": 127.345337,
+ "bbox_y0": -9.51337,
+ "bbox_y1": -8.13741
+ }
+ },
+ {
+ "pk": 228,
+ "model": "base.region",
+ "fields": {
+ "rght": 125,
+ "code": "TGO",
+ "name": "Togo",
+ "parent": 13,
+ "level": 3,
+ "lft": 124,
+ "tree_id": 90,
+ "bbox_x0": -0.14731,
+ "bbox_x1": 1.80669,
+ "bbox_y0": 6.10441,
+ "bbox_y1": 11.13897
+ }
+ },
+ {
+ "pk": 229,
+ "model": "base.region",
+ "fields": {
+ "rght": 506,
+ "code": "TKL",
+ "name": "Tokelau",
+ "parent": 256,
+ "level": 2,
+ "lft": 505,
+ "tree_id": 90,
+ "bbox_x0": -172.517136,
+ "bbox_x1": -171.182083,
+ "bbox_y0": -9.43378,
+ "bbox_y1": -8.53288
+ }
+ },
+ {
+ "pk": 230,
+ "model": "base.region",
+ "fields": {
+ "rght": 508,
+ "code": "TON",
+ "name": "Tonga",
+ "parent": 256,
+ "level": 2,
+ "lft": 507,
+ "tree_id": 90,
+ "bbox_x0": -176.212646,
+ "bbox_x1": -173.702438,
+ "bbox_y0": -22.345711,
+ "bbox_y1": -15.55326
+ }
+ },
+ {
+ "pk": 231,
+ "model": "base.region",
+ "fields": {
+ "rght": 181,
+ "code": "TTO",
+ "name": "Trinidad and Tobago",
+ "parent": 255,
+ "level": 3,
+ "lft": 180,
+ "tree_id": 90,
+ "bbox_x0": -61.927391,
+ "bbox_x1": -60.49144,
+ "bbox_y0": 10.03648,
+ "bbox_y1": 11.36118
+ }
+ },
+ {
+ "pk": 232,
+ "model": "base.region",
+ "fields": {
+ "rght": 61,
+ "code": "TUN",
+ "name": "Tunisia",
+ "parent": 11,
+ "level": 3,
+ "lft": 60,
+ "tree_id": 90,
+ "bbox_x0": 7.52481,
+ "bbox_x1": 11.59827,
+ "bbox_y0": 30.240431,
+ "bbox_y1": 37.56712
+ }
+ },
+ {
+ "pk": 233,
+ "model": "base.region",
+ "fields": {
+ "rght": 428,
+ "code": "TUR",
+ "name": "Turkey",
+ "parent": 5,
+ "level": 2,
+ "lft": 427,
+ "tree_id": 90,
+ "bbox_x0": 25.664101,
+ "bbox_x1": 44.8297,
+ "bbox_y0": 35.809971,
+ "bbox_y1": 42.105499
+ }
+ },
+ {
+ "pk": 234,
+ "model": "base.region",
+ "fields": {
+ "rght": 257,
+ "code": "TKM",
+ "name": "Turkmenistan",
+ "parent": 8,
+ "level": 3,
+ "lft": 256,
+ "tree_id": 90,
+ "bbox_x0": 52.441429,
+ "bbox_x1": 66.684303,
+ "bbox_y0": 35.14109,
+ "bbox_y1": 42.795551
+ }
+ },
+ {
+ "pk": 235,
+ "model": "base.region",
+ "fields": {
+ "rght": 183,
+ "code": "TCA",
+ "name": "Turks and Caicos Islands",
+ "parent": 255,
+ "level": 3,
+ "lft": 182,
+ "tree_id": 90,
+ "bbox_x0": -72.483879,
+ "bbox_x1": -71.08033,
+ "bbox_y0": 21.170031,
+ "bbox_y1": 21.97361
+ }
+ },
+ {
+ "pk": 236,
+ "model": "base.region",
+ "fields": {
+ "rght": 510,
+ "code": "TUV",
+ "name": "Tuvalu",
+ "parent": 256,
+ "level": 2,
+ "lft": 509,
+ "tree_id": 90,
+ "bbox_x0": 176.06488,
+ "bbox_x1": 179.883789,
+ "bbox_y0": -10.75045,
+ "bbox_y1": -5.64198
+ }
+ },
+ {
+ "pk": 237,
+ "model": "base.region",
+ "fields": {
+ "rght": 45,
+ "code": "UGA",
+ "name": "Uganda",
+ "parent": 12,
+ "level": 3,
+ "lft": 44,
+ "tree_id": 90,
+ "bbox_x0": 29.573549,
+ "bbox_x1": 35.001251,
+ "bbox_y0": -1.47849,
+ "bbox_y1": 4.23403
+ }
+ },
+ {
+ "pk": 238,
+ "model": "base.region",
+ "fields": {
+ "rght": 430,
+ "code": "UKR",
+ "name": "Ukraine",
+ "parent": 5,
+ "level": 2,
+ "lft": 429,
+ "tree_id": 90,
+ "bbox_x0": 22.128811,
+ "bbox_x1": 40.218079,
+ "bbox_y0": 44.390411,
+ "bbox_y1": 52.375359
+ }
+ },
+ {
+ "pk": 239,
+ "model": "base.region",
+ "fields": {
+ "rght": 460,
+ "code": "ARE",
+ "name": "United Arab Emirates",
+ "parent": 15,
+ "level": 2,
+ "lft": 459,
+ "tree_id": 90,
+ "bbox_x0": 51.497978,
+ "bbox_x1": 56.38343,
+ "bbox_y0": 22.644409,
+ "bbox_y1": 26.28219
+ }
+ },
+ {
+ "pk": 240,
+ "model": "base.region",
+ "fields": {
+ "rght": 432,
+ "code": "GBR",
+ "name": "United Kingdom",
+ "parent": 5,
+ "level": 2,
+ "lft": 431,
+ "tree_id": 90,
+ "bbox_x0": -13.41393,
+ "bbox_x1": 1.76896,
+ "bbox_y0": 49.16209,
+ "bbox_y1": 60.854691
+ }
+ },
+ {
+ "pk": 241,
+ "model": "base.region",
+ "fields": {
+ "rght": 47,
+ "code": "TZA",
+ "name": "United Republic of Tanzania",
+ "parent": 12,
+ "level": 3,
+ "lft": 46,
+ "tree_id": 90,
+ "bbox_x0": 29.32716,
+ "bbox_x1": 40.443218,
+ "bbox_y0": -11.74569,
+ "bbox_y1": -0.99073
+ }
+ },
+ {
+ "pk": 242,
+ "model": "base.region",
+ "fields": {
+ "rght": 185,
+ "code": "VIR",
+ "name": "United States Virgin Islands",
+ "parent": 255,
+ "level": 3,
+ "lft": 184,
+ "tree_id": 90,
+ "bbox_x0": -65.086281,
+ "bbox_x1": -64.56517,
+ "bbox_y0": 17.681721,
+ "bbox_y1": 18.458139
+ }
+ },
+ {
+ "pk": 243,
+ "model": "base.region",
+ "fields": {
+ "rght": 211,
+ "code": "USA",
+ "name": "United States of America",
+ "parent": 2,
+ "level": 3,
+ "lft": 210,
+ "tree_id": 90,
+ "bbox_x0": -179.150558,
+ "bbox_x1": -66.940643,
+ "bbox_y0": 18.91172,
+ "bbox_y1": 71.441048
+ }
+ },
+ {
+ "pk": 244,
+ "model": "base.region",
+ "fields": {
+ "rght": 239,
+ "code": "URY",
+ "name": "Uruguay",
+ "parent": 4,
+ "level": 3,
+ "lft": 238,
+ "tree_id": 90,
+ "bbox_x0": -58.442719,
+ "bbox_x1": -53.073929,
+ "bbox_y0": -35.047939,
+ "bbox_y1": -30.08222
+ }
+ },
+ {
+ "pk": 245,
+ "model": "base.region",
+ "fields": {
+ "rght": 259,
+ "code": "UZB",
+ "name": "Uzbekistan",
+ "parent": 8,
+ "level": 3,
+ "lft": 258,
+ "tree_id": 90,
+ "bbox_x0": 55.996632,
+ "bbox_x1": 73.132271,
+ "bbox_y0": 37.18433,
+ "bbox_y1": 45.60519
+ }
+ },
+ {
+ "pk": 246,
+ "model": "base.region",
+ "fields": {
+ "rght": 512,
+ "code": "VUT",
+ "name": "Vanuatu",
+ "parent": 256,
+ "level": 2,
+ "lft": 511,
+ "tree_id": 90,
+ "bbox_x0": 166.524994,
+ "bbox_x1": 170.234802,
+ "bbox_y0": -20.25045,
+ "bbox_y1": -13.07345
+ }
+ },
+ {
+ "pk": 247,
+ "model": "base.region",
+ "fields": {
+ "rght": 241,
+ "code": "VEN",
+ "name": "Venezuela (Bolivarian Republic of)",
+ "parent": 4,
+ "level": 3,
+ "lft": 240,
+ "tree_id": 90,
+ "bbox_x0": -73.374313,
+ "bbox_x1": -59.803768,
+ "bbox_y0": 0.74368,
+ "bbox_y1": 12.2019
+ }
+ },
+ {
+ "pk": 248,
+ "model": "base.region",
+ "fields": {
+ "rght": 315,
+ "code": "VNM",
+ "name": "Viet Nam",
+ "parent": 7,
+ "level": 3,
+ "lft": 314,
+ "tree_id": 90,
+ "bbox_x0": 102.144592,
+ "bbox_x1": 116.521233,
+ "bbox_y0": 7.3116,
+ "bbox_y1": 23.39274
+ }
+ },
+ {
+ "pk": 249,
+ "model": "base.region",
+ "fields": {
+ "rght": 514,
+ "code": "WLF",
+ "name": "Wallis and Futuna Islands",
+ "parent": 256,
+ "level": 2,
+ "lft": 513,
+ "tree_id": 90,
+ "bbox_x0": -178.206787,
+ "bbox_x1": -176.08287,
+ "bbox_y0": -14.38779,
+ "bbox_y1": -13.17343
+ }
+ },
+ {
+ "pk": 250,
+ "model": "base.region",
+ "fields": {
+ "rght": 63,
+ "code": "ESH",
+ "name": "Western Sahara",
+ "parent": 11,
+ "level": 3,
+ "lft": 62,
+ "tree_id": 90,
+ "bbox_x0": -17.10317,
+ "bbox_x1": -8.66942,
+ "bbox_y0": 20.774151,
+ "bbox_y1": 28.219179
+ }
+ },
+ {
+ "pk": 251,
+ "model": "base.region",
+ "fields": {
+ "rght": 462,
+ "code": "YEM",
+ "name": "Yemen",
+ "parent": 15,
+ "level": 2,
+ "lft": 461,
+ "tree_id": 90,
+ "bbox_x0": 41.809608,
+ "bbox_x1": 54.535992,
+ "bbox_y0": 12.10717,
+ "bbox_y1": 19.00276
+ }
+ },
+ {
+ "pk": 252,
+ "model": "base.region",
+ "fields": {
+ "rght": 79,
+ "code": "ZMB",
+ "name": "Zambia",
+ "parent": 14,
+ "level": 3,
+ "lft": 78,
+ "tree_id": 90,
+ "bbox_x0": 21.99938,
+ "bbox_x1": 33.705711,
+ "bbox_y0": -18.07947,
+ "bbox_y1": -8.22436
+ }
+ },
+ {
+ "pk": 253,
+ "model": "base.region",
+ "fields": {
+ "rght": 81,
+ "code": "ZWE",
+ "name": "Zimbabwe",
+ "parent": 14,
+ "level": 3,
+ "lft": 80,
+ "tree_id": 90,
+ "bbox_x0": 25.23702,
+ "bbox_x1": 33.056301,
+ "bbox_y0": -22.41773,
+ "bbox_y1": -15.60883
+ }
+ },
+ {
+ "pk": 254,
+ "model": "base.region",
+ "fields": {
+ "rght": 243,
+ "code": "AME",
+ "name": "Americas",
+ "parent": null,
+ "level": 1,
+ "lft": 128,
+ "tree_id": 90,
+ "bbox_x0": -84.114449,
+ "bbox_x1": -84.097572,
+ "bbox_y0": 9.9313,
+ "bbox_y1": 9.94792
+ }
+ },
+ {
+ "pk": 255,
+ "model": "base.region",
+ "fields": {
+ "rght": 186,
+ "code": "CRB",
+ "name": "Caribbean",
+ "parent": 254,
+ "level": 2,
+ "lft": 129,
+ "tree_id": 90,
+ "bbox_x0": -85.260178,
+ "bbox_x1": -59.286541,
+ "bbox_y0": 10.18548,
+ "bbox_y1": 27.454559
+ }
+ },
+ {
+ "pk": 256,
+ "model": "base.region",
+ "fields": {
+ "rght": 515,
+ "code": "PAC",
+ "name": "Pacific",
+ "parent": null,
+ "level": 1,
+ "lft": 464,
+ "tree_id": 90,
+ "bbox_x0": 139.572356,
+ "bbox_x1": -74.531208,
+ "bbox_y0": -56.267241,
+ "bbox_y1": 62.0215969
+ }
+ },
+ {
+ "pk": 257,
+ "model": "base.region",
+ "fields": {
+ "rght": 12,
+ "code": "CFR",
+ "name": "Central Africa",
+ "parent": 10,
+ "level": 2,
+ "lft": 3,
+ "tree_id": 90,
+ "bbox_x0": -25.35874,
+ "bbox_x1": 63.525379,
+ "bbox_y0": -46.900452,
+ "bbox_y1": 37.56712
+ }
+ },
+ {
+ "pk": 258,
+ "model": "base.region",
+ "fields": {
+ "rght": 276,
+ "code": "EAS",
+ "name": "East Asia",
+ "parent": 6,
+ "level": 2,
+ "lft": 261,
+ "tree_id": 90,
+ "bbox_x0": 19.6381,
+ "bbox_x1": 180,
+ "bbox_y0": -12.56111,
+ "bbox_y1": 82.50045
+ }
+ },
+ {
+ "pk": 259,
+ "model": "base.region",
+ "fields": {
+ "rght": 59,
+ "code": "SSD",
+ "name": "South Sudan",
+ "parent": 11,
+ "level": 3,
+ "lft": 58,
+ "tree_id": 90,
+ "bbox_x0": 24.15192,
+ "bbox_x1": 35.947689,
+ "bbox_y0": 3.48639,
+ "bbox_y1": 12.21558
+ }
+ },
+ {
+ "model": "base.menuplaceholder",
+ "pk": 1,
+ "fields": {
+ "name": "TOPBAR_MENU"
+ }
+ }
+]
diff --git a/fixtures/sample_admin.json b/fixtures/sample_admin.json
new file mode 100644
index 0000000000000000000000000000000000000000..f9a16ecf4c53c05d0ad1d383c084a009d67f0b1b
--- /dev/null
+++ b/fixtures/sample_admin.json
@@ -0,0 +1,18 @@
+[{
+ "fields": {
+ "date_joined": "2011-06-09 15:15:27",
+ "email": "ad@m.in",
+ "first_name": "",
+ "groups": [],
+ "is_active": true,
+ "is_staff": true,
+ "is_superuser": true,
+ "last_login": "2011-06-09 15:45:34",
+ "last_name": "",
+ "password": "pbkdf2_sha256$30000$rjuGt0Obn8on$cxF75frIOSaitNklLZ0IJ/VonUW0fwEFVF96o0M+lGc=",
+ "user_permissions": [],
+ "username": "admin"
+ },
+ "model": "people.Profile",
+ "pk": 1000
+}]
\ No newline at end of file
diff --git a/fixtures/sites_template.json b/fixtures/sites_template.json
new file mode 100644
index 0000000000000000000000000000000000000000..0e05e867e14fdcef2876a0d5c6ecc100c867b9d7
--- /dev/null
+++ b/fixtures/sites_template.json
@@ -0,0 +1,10 @@
+[
+ {
+ "fields": {
+ "domain": "example.com",
+ "name": "example.com"
+ },
+ "model": "sites.site",
+ "pk": 1
+ }
+]
diff --git a/geonode/br/backup.sh b/geonode/br/backup.sh
new file mode 100755
index 0000000000000000000000000000000000000000..18ee0af0bfe37619ed55f1b45f90a2e13849ee3a
--- /dev/null
+++ b/geonode/br/backup.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# ##########################################################
+# Run a backup
+# SOURCE_URL=$SOURCE_URL TARGET_URL=$TARGET_URL ./geonode/br/backup.sh $BKP_FOLDER_NAME
+# - BKP_FOLDER_NAME:
+# Default value = backup_restore
+# Shared Backup Folder name.
+# The scripts assume it is located on "root" e.g.: /$BKP_FOLDER_NAME/
+#
+# - SOURCE_URL:
+# Source Server URL, the one generating the "backup" file.
+#
+# - TARGET_URL:
+# Target Server URL, the one which must be synched.
+#
+# e.g.:
+# docker exec -it django4geonode sh -c 'SOURCE_URL=$SOURCE_URL TARGET_URL=$TARGET_URL ./geonode/br/backup.sh $BKP_FOLDER_NAME'
+# ##########################################################
+
+# Exit script in case of error
+set -e
+
+echo "-----------------------------------------------------"
+echo "STARTING geonode BACKUP $(date)"
+echo "-----------------------------------------------------"
+
+if [ "$1" != "" ]; then
+ BKP_FOLDER_NAME="$1"
+else
+ BKP_FOLDER_NAME="backup_restore"
+fi
+
+cd /usr/src/geonode/
+
+./manage.sh backup -i -f -c $PWD/geonode/br/settings_docker.ini --backup-dir /$BKP_FOLDER_NAME/
+
+BKP_FILE_LATEST=$(find /$BKP_FOLDER_NAME/*.zip -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==1 {print $2}')
+BKP_FILE_NAME=$(echo $BKP_FILE_LATEST | tail -n 1 | grep -oP -m 1 "\/$BKP_FOLDER_NAME\/\K.*" | sed 's|.zip||')
+
+sed -i 's~$~ /'"$BKP_FOLDER_NAME"'/'"$BKP_FILE_NAME"'.zip~g' /$BKP_FOLDER_NAME/$BKP_FILE_NAME.md5
+
+echo "-----------------------------------------------------"
+cat /$BKP_FOLDER_NAME/$BKP_FILE_NAME.md5
+echo "\n"
+echo "-----------------------------------------------------"
diff --git a/geonode/br/restore.sh b/geonode/br/restore.sh
new file mode 100755
index 0000000000000000000000000000000000000000..aca0ec438b8ecbd67b4af35a3269a65a71206725
--- /dev/null
+++ b/geonode/br/restore.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# ##########################################################
+# Run a restore
+# SOURCE_URL=$SOURCE_URL TARGET_URL=$TARGET_URL ./geonode/br/restore.sh $BKP_FOLDER_NAME
+# - BKP_FOLDER_NAME:
+# Default value = backup_restore
+# Shared Backup Folder name.
+# The scripts assume it is located on "root" e.g.: /$BKP_FOLDER_NAME/
+#
+# - SOURCE_URL:
+# Source Server URL, the one generating the "backup" file.
+#
+# - TARGET_URL:
+# Target Server URL, the one which must be synched.
+#
+# e.g.:
+# docker exec -it django4geonode sh -c 'SOURCE_URL=$SOURCE_URL TARGET_URL=$TARGET_URL ./geonode/br/restore.sh $BKP_FOLDER_NAME'
+# ##########################################################
+
+# Exit script in case of error
+set -e
+
+echo "-----------------------------------------------------"
+echo "STARTING geonode RESTORE $(date)"
+echo "-----------------------------------------------------"
+
+if [ "$1" != "" ]; then
+ BKP_FOLDER_NAME="$1"
+else
+ BKP_FOLDER_NAME="backup_restore"
+fi
+
+if [ -z "$SOURCE_URL" ] || [ -z "$TARGET_URL" ]
+then
+ echo "-----------------------------------------------------"
+ echo "ERROR: SOURCE_URL and TARGET_URL environment variables not set"
+ echo " e.g.: SOURCE_URL=test.webgis.adbpo.it TARGET_URL=staging.webgis.adbpo.it"
+ echo "-----------------------------------------------------"
+ exit 1
+else
+ echo "$SOURCE_URL --> $TARGET_URL"
+fi
+
+cd /usr/src/geonode/
+
+echo "-----------------------------------------------------"
+echo " 1. BACKUP $TARGET_URL"
+echo "-----------------------------------------------------"
+
+NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
+mkdir /$BKP_FOLDER_NAME/$NEW_UUID/
+SOURCE_URL=$SOURCE_URL TARGET_URL=$TARGET_URL ./geonode/br/backup.sh $BKP_FOLDER_NAME/$NEW_UUID
+
+echo "-----------------------------------------------------"
+echo " 2. CHECK BACKUP.md5 $TARGET_URL"
+echo "-----------------------------------------------------"
+
+BKP_FILE_LATEST=$(find /$BKP_FOLDER_NAME/$NEW_UUID/*.zip -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==1 {print $2}')
+BKP_FILE_NAME=$(echo $BKP_FILE_LATEST | tail -n 1 | grep -oP -m 1 "\/$BKP_FOLDER_NAME\/$NEW_UUID\/\K.*" | sed 's|.zip||')
+
+if md5sum -c /$BKP_FOLDER_NAME/$NEW_UUID/$BKP_FILE_NAME.md5; then
+
+ echo "-----------------------------------------------------"
+ echo " - Original Backup of $TARGET_URL --> /$BKP_FOLDER_NAME/$NEW_UUID/"
+ echo " 3. RESTORE FROM $SOURCE_URL"
+ echo "-----------------------------------------------------"
+
+ RECOVERY_FILE_NAME=$BKP_FILE_NAME
+ BKP_FILE_LATEST=$(find /$BKP_FOLDER_NAME/*.zip -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==1 {print $2}')
+ BKP_FILE_NAME=$(echo $BKP_FILE_LATEST | tail -n 1 | grep -oP -m 1 "\/$BKP_FOLDER_NAME\/\K.*" | sed 's|.zip||')
+
+ if md5sum -c /$BKP_FOLDER_NAME/$BKP_FILE_NAME.md5; then
+ # The MD5 sum matched
+ ./manage.sh restore -l -n -f --backup-file /$BKP_FOLDER_NAME/$BKP_FILE_NAME.zip --recovery-file /$BKP_FOLDER_NAME/$NEW_UUID/$RECOVERY_FILE_NAME.zip
+ ./manage.sh migrate_baseurl -f --source-address=$SOURCE_URL --target-address=$TARGET_URL
+ ./manage.sh set_all_layers_metadata -d -i
+ else
+ # The MD5 sum didn't match
+ echo "-----------------------------------------------------"
+ echo " - Original Backup of $TARGET_URL --> /$BKP_FOLDER_NAME/$NEW_UUID/"
+ echo "ERROR: The MD5 sum didn't match"
+ echo "-----------------------------------------------------"
+ exit 1
+ fi
+else
+ # The MD5 sum didn't match
+ echo "-----------------------------------------------------"
+ echo " - Original Backup of $TARGET_URL --> /$BKP_FOLDER_NAME/$NEW_UUID/"
+ echo "ERROR: Could not save $TARGET_URL"
+ echo "-----------------------------------------------------"
+ exit 1
+fi
+
+echo "-----------------------------------------------------"
+echo " - Original Backup of $TARGET_URL --> /$BKP_FOLDER_NAME/$NEW_UUID/"
+echo "FINISHED geonode RESTORE $(date)"
+echo "-----------------------------------------------------"
diff --git a/geonode/br/settings_docker.ini b/geonode/br/settings_docker.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bbc6b5b9cbc73cac18f5a9936a01788beebdb4a6
--- /dev/null
+++ b/geonode/br/settings_docker.ini
@@ -0,0 +1,12 @@
+[database]
+pgdump = pg_dump
+pgrestore = pg_restore
+
+[geoserver]
+datadir = /geoserver_data/data
+dumpvectordata = yes
+dumprasterdata = yes
+
+[fixtures]
+apps = contenttypes,auth,people,groups,account,guardian,admin,actstream,announcements,avatar,base,dialogos,documents,geoserver,invitations,pinax_notifications,layers,maps,mapstore2_adapter,oauth2_provider,services,sites,socialaccount,taggit,tastypie,upload,user_messages,geonode_themes
+dumps = contenttypes,auth,people,groups,account,guardian,admin,actstream,announcements,avatar,base,dialogos,documents,geoserver,invitations,pinax_notifications,layers,maps,mapstore2_adapter,oauth2_provider,services,sites,socialaccount,taggit,tastypie,upload,user_messages,geonode_themes
\ No newline at end of file
diff --git a/geonode/celery_app.py b/geonode/celery_app.py
index 0df20e35547515ccbbaf716e105c79dcc61a84b8..bbf5bc38e06a20749bb45e5c12bd36a69e3b2696 100644
--- a/geonode/celery_app.py
+++ b/geonode/celery_app.py
@@ -50,14 +50,14 @@ def setup_periodic_tasks(sender, **kwargs):
@app.task(
bind=True,
- name='{{project_name}}.test',
+ name='geonode.test',
queue='default')
def test(arg):
_log(arg)
@app.task(
bind=True,
- name='{{project_name}}.debug_task',
+ name='geonode.debug_task',
queue='default')
def debug_task(self):
_log("Request: {!r}".format(self.request))
diff --git a/geonode/settings.py b/geonode/settings.py
index ef39d30f1be6e44dfbd625a4f3937c95d2c1e985..0e2d6544520e1820f31d11e5c038e9c50f86b7be 100644
--- a/geonode/settings.py
+++ b/geonode/settings.py
@@ -2018,3 +2018,11 @@ GEOIP_PATH = os.getenv('GEOIP_PATH', os.path.join(PROJECT_ROOT, 'GeoIPCities.dat
#This controls if tastypie search on resourches is performed only with titles
SEARCH_RESOURCES_EXTENDED = strtobool(os.getenv('SEARCH_RESOURCES_EXTENDED', 'True'))
# -- END Settings for MONITORING plugin
+
+## thünen
+## load additional config from ti_setting.py file
+## which is based on the geonode-project settings.py file
+try:
+ from ti_settings import *
+except ImportError:
+ pass
diff --git a/geonode/ti_settings.py b/geonode/ti_settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..428c3ad1467a8dbcd0dd2172dd208887b3247ac1
--- /dev/null
+++ b/geonode/ti_settings.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+#########################################################################
+#
+# Copyright (C) 2017 OSGeo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#########################################################################
+
+# Django settings for the GeoNode project.
+import os
+import ast
+
+try:
+ from urllib.parse import urlparse, urlunparse
+ from urllib.request import urlopen, Request
+except ImportError:
+ from urllib2 import urlopen, Request
+ from urlparse import urlparse, urlunparse
+
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': True,
+ 'formatters': {
+ 'verbose': {
+ 'format': '%(levelname)s %(asctime)s %(module)s %(process)d '
+ '%(thread)d %(message)s'
+ },
+ 'simple': {
+ 'format': '%(message)s',
+ },
+ },
+ 'filters': {
+ 'require_debug_false': {
+ '()': 'django.utils.log.RequireDebugFalse'
+ }
+ },
+ 'handlers': {
+ 'console': {
+ 'level': 'ERROR',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'simple'
+ },
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['require_debug_false'],
+ 'class': 'django.utils.log.AdminEmailHandler',
+ }
+ },
+ "loggers": {
+ "django": {
+ "handlers": ["console"], "level": "ERROR", },
+ "geonode": {
+ "handlers": ["console"], "level": "INFO", },
+ "geoserver-restconfig.catalog": {
+ "handlers": ["console"], "level": "ERROR", },
+ "owslib": {
+ "handlers": ["console"], "level": "ERROR", },
+ "pycsw": {
+ "handlers": ["console"], "level": "ERROR", },
+ "celery": {
+ "handlers": ["console"], "level": "DEBUG", },
+ "mapstore2_adapter.plugins.serializers": {
+ "handlers": ["console"], "level": "DEBUG", },
+ "geonode_logstash.logstash": {
+ "handlers": ["console"], "level": "DEBUG", },
+ },
+}
+
+CENTRALIZED_DASHBOARD_ENABLED = ast.literal_eval(os.getenv('CENTRALIZED_DASHBOARD_ENABLED', 'False'))
+if CENTRALIZED_DASHBOARD_ENABLED and USER_ANALYTICS_ENABLED and 'geonode_logstash' not in INSTALLED_APPS:
+ INSTALLED_APPS += ('geonode_logstash',)
+
+ CELERY_BEAT_SCHEDULE['dispatch_metrics'] = {
+ 'task': 'geonode_logstash.tasks.dispatch_metrics',
+ 'schedule': 3600.0,
+ }
+
+# Add your specific LDAP configuration after this comment:
+# https://docs.geonode.org/en/master/advanced/contrib/#configuration
+# --------------------------------------------------
+# LDAP conf:
+
+from django_auth_ldap import config as ldap_config
+from geonode_ldap.config import GeonodeNestedGroupOfNamesType
+import ldap
+
+LDAP_ENABLED = ast.literal_eval(os.getenv('LDAP_ENABLED', 'False'))
+if LDAP_ENABLED and 'geonode_ldap' not in INSTALLED_APPS:
+ INSTALLED_APPS += ('geonode_ldap',)
+
+# enable logging
+import logging
+logger = logging.getLogger('django_auth_ldap')
+logger.addHandler(logging.StreamHandler())
+logger.setLevel(logging.DEBUG)
+
+# add both standard ModelBackend auth and geonode.contrib.ldap auth
+AUTHENTICATION_BACKENDS += (
+ 'geonode_ldap.backend.GeonodeLdapBackend',
+)
+
+# django_auth_ldap configuration
+AUTH_LDAP_SERVER_URI = os.getenv("LDAP_SERVER_URL")
+AUTH_LDAP_BIND_DN = os.getenv("LDAP_BIND_DN")
+AUTH_LDAP_BIND_PASSWORD = os.getenv("LDAP_BIND_PASSWORD")
+
+# USER
+AUTH_LDAP_USER_SEARCH = ldap_config.LDAPSearch(
+ os.getenv("LDAP_USER_SEARCH_DN"),
+ ldap.SCOPE_SUBTREE,
+ os.getenv("LDAP_USER_SEARCH_FILTERSTR")
+)
+AUTH_LDAP_USER_ATTR_MAP = {
+ "first_name": "givenName",
+ "last_name": "sn",
+ "email": "mail"
+}
+
+# GROUPS
+# should LDAP groups be used to spawn groups in GeoNode?
+AUTH_LDAP_MIRROR_GROUPS = False
+AUTH_LDAP_FIND_GROUP_PERMS = False
+AUTH_LDAP_MIRROR_GROUPS_EXCEPT = False
+AUTH_LDAP_GROUP_SEARCH = ldap_config.LDAPSearch(
+ os.getenv("LDAP_GROUP_SEARCH_DN"),
+ ldap.SCOPE_SUBTREE,
+ os.getenv("LDAP_GROUP_SEARCH_FILTERSTR")
+)
+AUTH_LDAP_GROUP_TYPE = GeonodeNestedGroupOfNamesType()
+
+# these are not needed by django_auth_ldap - we use them to find and match
+# GroupProfiles and GroupCategories
+GEONODE_LDAP_GROUP_NAME_ATTRIBUTE = os.getenv("LDAP_GROUP_NAME_ATTRIBUTE", default="cn")
+GEONODE_LDAP_GROUP_PROFILE_FILTERSTR = os.getenv("LDAP_GROUP_SEARCH_FILTERSTR", default='(ou=research group)')
+GEONODE_LDAP_GROUP_PROFILE_MEMBER_ATTR = os.getenv("LDAP_GROUP_PROFILE_MEMBER_ATTR", default='member')
+# --------------------------------------------------
diff --git a/jetty-runner.xml b/jetty-runner.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f56792aa4296784a4c017cc95a464721fe1b936
--- /dev/null
+++ b/jetty-runner.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+ <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+ <Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Set name="contextPath">/geoserver</Set>
+ <Set name="war"><SystemProperty name="jetty.home" default="../"/>geoserver</Set>
+ <Call name="setAttribute">
+ <Arg>org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</Arg>
+ <Arg>WONTMATCH</Arg>
+ </Call>
+ </Configure>
diff --git a/manage.py b/manage.py
index 00cf85e40717f8a2aea103b0f5fec021adb4f09e..af72f70dd656d8c288c0bc4a3543b016d190323f 100755
--- a/manage.py
+++ b/manage.py
@@ -1,4 +1,6 @@
#!/usr/bin/env python
+
+# -*- coding: utf-8 -*-
#########################################################################
#
# Copyright (C) 2016 OSGeo
diff --git a/manage.sh b/manage.sh
index e410b870790ea7d5587b501e7a83847a253b12d1..69cacc4f08fe163dff44d50f8504ce9a1eeb5051 100755
--- a/manage.sh
+++ b/manage.sh
@@ -1,2 +1,2 @@
. $HOME/.override_env
-/usr/local/bin/python /usr/src/app/manage.py $@
+/usr/local/bin/python /usr/src/geonode/manage.py $@
diff --git a/monitoring-cron b/monitoring-cron
new file mode 100644
index 0000000000000000000000000000000000000000..dcc737d23cecb93870f4cdf1dc84092087ac2306
--- /dev/null
+++ b/monitoring-cron
@@ -0,0 +1,3 @@
+# */1 * * * * /usr/src/geonode/manage.sh collect_metrics -n -t xml >> /var/log/cron.log 2>&1
+# 0 * * * * /usr/src/geonode/manage.sh dispatch_metrics >> /var/log/cron.log 2>&1
+# An empty line is required at the end of this file for a valid cron file.
\ No newline at end of file
diff --git a/package/support/geonode.binary b/package/support/geonode.binary
index 0004c5f17d7eaed50132d05bae6e123b7dd75b2e..e3bb206053fd74152eebd194341b7b3a6a07d2c7 100644
--- a/package/support/geonode.binary
+++ b/package/support/geonode.binary
@@ -2,12 +2,14 @@
DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-geonode.local_settings}
-if [ -n "$VIRTUAL_ENV" ]; then
- DJANGO_ADMIN_CMD=$VIRTUAL_ENV/bin/django-admin
+if [ -n "$WORKON_HOME" ]; then
+ DJANGO_ADMIN_CMD=$WORKON_HOME/bin/django-admin >/dev/null 2>/dev/null
elif hash django-admin 2>/dev/null; then
DJANGO_ADMIN_CMD=django-admin
-else
- DJANGO_ADMIN_CMD=django-admin.py
fi
-DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE $DJANGO_ADMIN_CMD "$@"
+if [ -n "$DJANGO_ADMIN_CMD" ]; then
+ DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE $DJANGO_ADMIN_CMD $@
+else
+ DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE django-admin.py $@
+fi
diff --git a/package/support/geonode.updateip b/package/support/geonode.updateip
index cca95f104a8cd0c607e942d3576fbafe028a67e8..1d9f40240cb0ad2fa6ff8bc89795211abded179b 100644
--- a/package/support/geonode.updateip
+++ b/package/support/geonode.updateip
@@ -171,7 +171,7 @@ geonode fixsitename
echo "Setting up oauth"
# Set oauth keys
-oauth_keys=$(geonode fixoauthuri -f --target-address $NEW_EXT_IP 2>&1)
+oauth_keys=$(geonode fixoauthuri 2>&1)
client_id=`echo $oauth_keys | cut -d \, -f 1`
client_secret=`echo $oauth_keys | cut -d \, -f 2`
@@ -179,14 +179,14 @@ client_secret=`echo $oauth_keys | cut -d \, -f 2`
oauth_config="$GEOSERVER_DATA_DIR/security/filter/geonode-oauth2/config.xml"
sed -i "s|<cliendId>.*</cliendId>|<cliendId>$client_id</cliendId>|g" $oauth_config
sed -i "s|<clientSecret>.*</clientSecret>|<clientSecret>$client_secret</clientSecret>|g" $oauth_config
-sed -i "s|<accessTokenUri>.*</accessTokenUri>|<accessTokenUri>$NEW_EXT_IP/o/token/</accessTokenUri>|g" $oauth_config
+sed -i "s|<accessTokenUri>.*</accessTokenUri>|<accessTokenUri>$NEW_INT_IP/o/token/</accessTokenUri>|g" $oauth_config
sed -i "s|<userAuthorizationUri>.*</userAuthorizationUri>|<userAuthorizationUri>$NEW_EXT_IP/o/authorize/</userAuthorizationUri>|g" $oauth_config
sed -i "s|<redirectUri>.*</redirectUri>|<redirectUri>$NEW_EXT_IP/geoserver/</redirectUri>|g" $oauth_config
-sed -i "s|<checkTokenEndpointUrl>.*</checkTokenEndpointUrl>|<checkTokenEndpointUrl>$NEW_EXT_IP/api/o/v4/tokeninfo/</checkTokenEndpointUrl>|g" $oauth_config
+sed -i "s|<checkTokenEndpointUrl>.*</checkTokenEndpointUrl>|<checkTokenEndpointUrl>$NEW_INT_IP/api/o/v4/tokeninfo/</checkTokenEndpointUrl>|g" $oauth_config
sed -i "s|<logoutUri>.*</logoutUri>|<logoutUri>$NEW_EXT_IP/account/logout/</logoutUri>|g" $oauth_config
# Updating REST Role Service Config
-sed -i "s|<baseUrl>.*</baseUrl>|<baseUrl>$NEW_EXT_IP</baseUrl>|g" "$GEOSERVER_DATA_DIR/security/role/geonode REST role service/config.xml"
+sed -i "s|<baseUrl>.*</baseUrl>|<baseUrl>$NEW_INT_IP</baseUrl>|g" "$GEOSERVER_DATA_DIR/security/role/geonode REST role service/config.xml"
# Updating GeoServer Global Config
global_config="$GEOSERVER_DATA_DIR/global.xml"
@@ -206,7 +206,7 @@ sleep 5s
# Run updatelayers
geonode updatelayers
geonode set_all_layers_alternate
-geonode set_all_layers_metadata -d
+geonode set_all_layers_metadata
# Run updatemaplayerip
geonode updatemaplayerip
diff --git a/pavement.py b/pavement.py
index a7d99913d870470835b5a71fd431fcc0f8eb3343..f1eb92061f5a593df8234a56121dc9847661e114 100644
--- a/pavement.py
+++ b/pavement.py
@@ -422,11 +422,11 @@ def sync(options):
sh("%s python -W ignore manage.py makemigrations --noinput" % settings)
sh("%s python -W ignore manage.py migrate --noinput" % settings)
- sh("%s python -W ignore manage.py loaddata sample_admin.json" % settings)
- sh("%s python -W ignore manage.py loaddata geonode/base/fixtures/default_oauth_apps.json" % settings)
- sh("%s python -W ignore manage.py loaddata geonode/base/fixtures/initial_data.json" % settings)
+ sh("%s python -W ignore manage.py loaddata fixtures/sample_admin.json" % settings)
+ sh("%s python -W ignore manage.py loaddata fixtures/default_oauth_apps.json" % settings)
+ sh("%s python -W ignore manage.py loaddata fixtures/initial_data.json" % settings)
if 'django_celery_beat' in INSTALLED_APPS:
- sh("%s python -W ignore manage.py loaddata geonode/base/fixtures/django_celery_beat.json" % settings)
+ sh("%s python -W ignore manage.py loaddata fixtures/django_celery_beat.json" % settings)
sh("%s python -W ignore manage.py set_all_layers_alternate" % settings)
diff --git a/paver.sh b/paver.sh
new file mode 100755
index 0000000000000000000000000000000000000000..108d6519bc0dc324cc7f80800eec3b145938b3d0
--- /dev/null
+++ b/paver.sh
@@ -0,0 +1,2 @@
+. $HOME/.override_env
+paver $@
diff --git a/production.env b/production.env
new file mode 100644
index 0000000000000000000000000000000000000000..35c4c5c703237342c40ef5a9a853a778f4be4477
--- /dev/null
+++ b/production.env
@@ -0,0 +1,59 @@
+# store production env vars here
+# these values will override .env
+# this file will not be tracked by git
+COMPOSE_PROJECT_NAME=geonode
+### site url
+SITEURL=http://localhost/
+GEOSERVER_WEB_UI_LOCATION=http://localhost/geoserver/
+GEOSERVER_PUBLIC_LOCATION=http://localhost/geoserver/
+GEONODE_LB_HOST_IP=localhost
+HTTP_HOST=localhost
+HTTPS_HOST=
+HTTP_PORT=80
+HTTPS_PORT=443
+
+### credentials
+## !!! remember to change docker/geoserver/datasource-ovr.properties accordingly !!!
+# GeoNode
+ADMIN_USERNAME=admin
+ADMIN_PASSWORD=admin
+#OAUTH2_API_KEY=<new_OAUTH2_API_KEY>
+#OAUTH2_CLIENT_ID=<new_OAUTH2_CLIENT_ID>
+#OAUTH2_CLIENT_SECRET=<new_OAUTH2_CLIENT_SECRET>
+
+
+# PostgreSQL
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+GEONODE_DATABASE=geonode
+GEONODE_DATABASE_PASSWORD=geonode
+GEONODE_GEODATABASE=geonode_data
+GEONODE_GEODATABASE_PASSWORD=geonode
+# !!! use above values !!!
+DATABASE_URL=postgres://geonode:geonode@db:5432/geonode
+GEODATABASE_URL=postgis://geonode_data:geonode@db:5432/geonode_data
+
+# GeoServer
+GEOSERVER_ADMIN_USER=admin
+GEOSERVER_ADMIN_PASSWORD=geoserver
+
+# EMAIL
+DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
+DJANGO_EMAIL_HOST=localhost
+DJANGO_EMAIL_PORT=25
+DJANGO_EMAIL_HOST_USER=
+DJANGO_EMAIL_HOST_PASSWORD=
+DJANGO_EMAIL_USE_TLS=False
+DJANGO_EMAIL_USE_SSL=False
+DEFAULT_FROM_EMAIL='GeoNode <no-reply@geonode.org>'
+
+# LDAP
+LDAP_ENABLED=False
+LDAP_SERVER_URL=ldap://<the_ldap_server>
+LDAP_BIND_DN=uid=ldapinfo,cn=users,dc=ad,dc=example,dc=org
+LDAP_BIND_PASSWORD=<something_secret>
+LDAP_USER_SEARCH_DN=dc=ad,dc=example,dc=org
+LDAP_USER_SEARCH_FILTERSTR=(&(uid=%(user)s)(objectClass=person))
+LDAP_GROUP_SEARCH_DN=cn=groups,dc=ad,dc=example,dc=org
+LDAP_GROUP_SEARCH_FILTERSTR=(|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6))
+LDAP_GROUP_PROFILE_MEMBER_ATTR=uniqueMember
diff --git a/tasks.py b/tasks.py
index 67ffa12f07c6e671e0ee9a5afa5175226b5ffe33..299071d3b000bc3881ddf9b59e96c382d5ea651d 100755
--- a/tasks.py
+++ b/tasks.py
@@ -1,8 +1,20 @@
+import ast
import json
+import logging
import os
-import ast
-
-from invoke import task
+import re
+import time
+import datetime
+import docker
+import socket
+
+try:
+ from urllib.parse import urlparse
+ from urllib.request import urlopen, Request
+except ImportError:
+ from urllib2 import urlopen, Request
+ from urlparse import urlparse
+from invoke import run, task
BOOTSTRAP_IMAGE_CHEIP = 'codenvy/che-ip:nightly'
@@ -13,9 +25,17 @@ def waitfordbs(ctx):
ctx.run("/usr/bin/wait-for-databases {0}".format('db'), pty=True)
+@task
+def waitforgeoserver(ctx):
+ print("****************************geoserver********************************")
+ while not _rest_api_availability(os.environ['GEOSERVER_LOCATION'] + 'rest'):
+ print ("Wait for GeoServer API availability...")
+ print("GeoServer is available for HTTP calls!")
+
+
@task
def update(ctx):
- print("***************************initial*********************************")
+ print("***************************setting env*********************************")
ctx.run("env", pty=True)
pub_ip = _geonode_public_host_ip()
print("Public Hostname or IP is {0}".format(pub_ip))
@@ -26,82 +46,171 @@ def update(ctx):
pub_port = None
db_url = _update_db_connstring()
geodb_url = _update_geodb_connstring()
+ service_ready = False
+ while not service_ready:
+ try:
+ socket.gethostbyname('geonode')
+ service_ready = True
+ except Exception:
+ time.sleep(10)
+
override_env = "$HOME/.override_env"
+ if os.path.exists(override_env):
+ os.remove(override_env)
+ else:
+ print("Can not delete the %s file as it doesn't exists" % override_env)
+
envs = {
+ "local_settings": "{0}".format(_localsettings()),
+ "siteurl": os.environ.get('SITEURL',
+ '{0}://{1}:{2}/'.format(pub_protocol, pub_ip, pub_port) if pub_port else '{0}://{1}/'.format(pub_protocol, pub_ip)),
+ "geonode_docker_host": "{0}".format(socket.gethostbyname('geonode')),
"public_protocol": pub_protocol,
"public_fqdn": "{0}{1}".format(pub_ip, ':' + pub_port if pub_port else ''),
"public_host": "{0}".format(pub_ip),
- "dburl": db_url,
- "geodburl": geodb_url,
+ "dburl": os.environ.get('DATABASE_URL', db_url),
+ "geodburl": os.environ.get('GEODATABASE_URL', geodb_url),
+ "static_root": os.environ.get('STATIC_ROOT', '/mnt/volumes/statics/static/'),
+ "media_root": os.environ.get('MEDIA_ROOT', '/mnt/volumes/statics/uploaded/'),
+ "geoip_path": os.environ.get('GEOIP_PATH', '/mnt/volumes/statics/geoip.db'),
+ "monitoring": os.environ.get('MONITORING_ENABLED', True),
+ "monitoring_host_name": os.environ.get('MONITORING_HOST_NAME', 'geonode'),
+ "monitoring_service_name": os.environ.get('MONITORING_SERVICE_NAME', 'local-geonode'),
+ "monitoring_data_ttl": os.environ.get('MONITORING_DATA_TTL', 7),
+ "geoip_path": os.environ.get('GEOIP_PATH', '/mnt/volumes/statics/geoip.db'),
+ "geonode_geodb_passwd": os.environ.get('GEONODE_GEODATABASE_PASSWORD', 'geonode_data'),
+ "default_backend_datastore": os.environ.get('DEFAULT_BACKEND_DATASTORE', 'datastore'),
+ "geonode_db_passwd": os.environ.get('GEONODE_DATABASE_PASSWORD', 'geonode'),
+ "geonode_geodb": os.environ.get('GEONODE_GEODATABASE', 'geonode_data'),
+ "db_url": os.environ.get('DATABASE_URL', 'postgres://geonode:geonode@db:5432/geonode'),
+ "geodb_url": os.environ.get('GEODATABASE_URL', 'postgis://geonode:geonode@db:5432/geonode_data'),
+ "geonode_db": os.environ.get('GEONODE_DATABASE', 'geonode'),
+ "gs_loc": os.environ.get('GEOSERVER_LOCATION', 'http://geoserver:8080/geoserver/'),
+ "gs_web_ui_loc": os.environ.get('GEOSERVER_WEB_UI_LOCATION',
+ 'http://{0}:{1}/geoserver/'.format(pub_ip, pub_port) if pub_port else 'http://{0}/geoserver/'.format(pub_ip)),
+ "gs_pub_loc": os.environ.get('GEOSERVER_PUBLIC_LOCATION',
+ 'http://{0}:{1}/geoserver/'.format(pub_ip, pub_port) if pub_port else 'http://{0}/geoserver/'.format(pub_ip)),
+ "gs_admin_pwd": os.environ.get('GEOSERVER_ADMIN_PASSWORD', 'geoserver'),
"override_fn": override_env
}
- if os.environ.get(
- 'GEONODE_LB_HOST_IP'
- ) and os.environ.get(
- 'GEONODE_LB_PORT'
- ):
- ctx.run("echo export GEOSERVER_PUBLIC_LOCATION=\
-{public_protocol}://{public_fqdn}/geoserver/ >> {override_fn}".format(**envs), pty=True)
- ctx.run("echo export GEOSERVER_WEB_UI_LOCATION=\
-{public_protocol}://{public_fqdn}/geoserver/ >> {override_fn}".format(**envs), pty=True)
- ctx.run("echo export SITEURL=\
-{public_protocol}://{public_fqdn}/ >> {override_fn}".format(**envs), pty=True)
-
try:
- current_allowed = ast.literal_eval(
- os.getenv('ALLOWED_HOSTS') or "[\
-'{public_fqdn}', '{public_host}', 'localhost', 'django', 'geonode',\
-]".format(**envs))
+ current_allowed = ast.literal_eval(os.getenv('ALLOWED_HOSTS') or \
+ "['{public_fqdn}', '{public_host}', 'localhost', 'django', 'geonode',]".format(**envs))
except ValueError:
current_allowed = []
- current_allowed.extend(
- ['{}'.format(pub_ip), '{}:{}'.format(pub_ip, pub_port)]
- )
- allowed_hosts = ['"{}"'.format(c) for c in current_allowed]
- for host in ['django', 'geonode']:
- if host not in allowed_hosts:
- allowed_hosts.extend(['{}'.format(host)])
-
- ctx.run('echo export ALLOWED_HOSTS="\\"{}\\"" >> {}'.format(
- allowed_hosts, override_env
- ), pty=True)
-
- if not os.environ.get('DATABASE_URL'):
- ctx.run("echo export DATABASE_URL=\
+ current_allowed.extend(['{}'.format(pub_ip), '{}:{}'.format(pub_ip, pub_port)])
+ allowed_hosts = ['"{}"'.format(c) for c in current_allowed] + ['"geonode"', '"django"']
+
+ ctx.run("echo export DJANGO_SETTINGS_MODULE=\
+{local_settings} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export MONITORING_ENABLED=\
+{monitoring} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export MONITORING_HOST_NAME=\
+{monitoring_host_name} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export MONITORING_SERVICE_NAME=\
+{monitoring_service_name} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export MONITORING_DATA_TTL=\
+{monitoring_data_ttl} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOIP_PATH=\
+{geoip_path} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEONODE_GEODATABASE_PASSWORD=\
+{geonode_geodb_passwd} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export DEFAULT_BACKEND_DATASTORE=\
+{default_backend_datastore} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEONODE_DATABASE_PASSWORD=\
+{geonode_db_passwd} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEONODE_GEODATABASE=\
+{geonode_geodb} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export DATABASE_URL=\
+{db_url} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEODATABASE_URL=\
+{geodb_url} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEONODE_DATABASE=\
+{geonode_db} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOSERVER_LOCATION=\
+{gs_loc} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOSERVER_WEB_UI_LOCATION=\
+{gs_web_ui_loc} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOSERVER_PUBLIC_LOCATION=\
+{gs_pub_loc} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOSERVER_ADMIN_PASSWORD=\
+{gs_admin_pwd} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export SITEURL=\
+{siteurl} >> {override_fn}".format(**envs), pty=True)
+ ctx.run('echo export ALLOWED_HOSTS=\
+"\\"{}\\"" >> {override_fn}'.format(allowed_hosts, **envs), pty=True)
+ ctx.run("echo export DATABASE_URL=\
{dburl} >> {override_fn}".format(**envs), pty=True)
- if not os.environ.get('GEODATABASE_URL'):
- ctx.run("echo export GEODATABASE_URL=\
+ ctx.run("echo export GEODATABASE_URL=\
{geodburl} >> {override_fn}".format(**envs), pty=True)
- ctx.run("source $HOME/.override_env", pty=True)
- print("****************************final**********************************")
+ ctx.run("echo export STATIC_ROOT=\
+{static_root} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export MEDIA_ROOT=\
+{media_root} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export GEOIP_PATH=\
+{geoip_path} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export LOGIN_URL=\
+{siteurl}account/login/ >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export LOGOUT_URL=\
+{siteurl}account/logout/ >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export LOGIN_REDIRECT_URL=\
+{siteurl} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("echo export LOGOUT_REDIRECT_URL=\
+{siteurl} >> {override_fn}".format(**envs), pty=True)
+ ctx.run("source %s" % override_env, pty=True)
+ print("****************************finalize env**********************************")
ctx.run("env", pty=True)
@task
def migrations(ctx):
print("**************************migrations*******************************")
- ctx.run("python manage.py makemigrations --settings={0}".format(
+ ctx.run("python manage.py makemigrations --noinput --merge --settings={0}".format(
+ _localsettings()
+ ), pty=True)
+ ctx.run("python manage.py makemigrations --noinput --settings={0}".format(
_localsettings()
), pty=True)
ctx.run("python manage.py migrate --noinput --settings={0}".format(
_localsettings()
), pty=True)
-
+ ctx.run("python manage.py updategeoip --settings={0}".format(
+ _localsettings()
+ ), pty=True)
+ try:
+ ctx.run("python manage.py rebuild_index --noinput --settings={0}".format(
+ _localsettings()
+ ), pty=True)
+ except:
+ pass
@task
def statics(ctx):
- print("**************************migrations*******************************")
+ print("**************************statics*******************************")
ctx.run('mkdir -p /mnt/volumes/statics/{static,uploads}')
- ctx.run("python manage.py collectstatic --noinput --clear --settings={0}".format(
+ ctx.run("python manage.py collectstatic --noinput --settings={0}".format(
_localsettings()
), pty=True)
-
@task
def prepare(ctx):
print("**********************prepare fixture***************************")
ctx.run("rm -rf /tmp/default_oauth_apps_docker.json", pty=True)
_prepare_oauth_fixture()
+ ctx.run("rm -rf /tmp/default_site.json", pty=True)
+ _prepare_site_fixture()
+ # Updating OAuth2 Service Config
+ oauth_config = "/geoserver_data/data/security/filter/geonode-oauth2/config.xml"
+ ctx.run(
+ 'sed -i "s|<cliendId>.*</cliendId>|<cliendId>{client_id}</cliendId>|g" {oauth_config}'.format(
+ client_id=os.environ['OAUTH2_CLIENT_ID'],
+ oauth_config=oauth_config
+ ), pty=True)
+ ctx.run(
+ 'sed -i "s|<clientSecret>.*</clientSecret>|<clientSecret>{client_secret}</clientSecret>|g" {oauth_config}'.format(
+ client_secret=os.environ['OAUTH2_CLIENT_SECRET'],
+ oauth_config=oauth_config
+ ), pty=True)
@task
@@ -111,21 +220,102 @@ def fixtures(ctx):
--settings={0}".format(_localsettings()), pty=True)
ctx.run("python manage.py loaddata /tmp/default_oauth_apps_docker.json \
--settings={0}".format(_localsettings()), pty=True)
- ctx.run("python manage.py loaddata geonode/base/fixtures/initial_data.json \
+ ctx.run("python manage.py loaddata /tmp/default_site.json \
--settings={0}".format(_localsettings()), pty=True)
+ ctx.run("python manage.py loaddata /usr/src/geonode/fixtures/initial_data.json \
+--settings={0}".format(_localsettings()), pty=True)
+ ctx.run("python manage.py set_all_layers_alternate \
+--settings={0}".format(_localsettings()), pty=True)
+# ctx.run("python manage.py set_all_layers_metadata -d \
+# --settings={0}".format(_localsettings()), pty=True)
+@task
+def collectstatic(ctx):
+ print("************************static artifacts******************************")
+ ctx.run("django-admin.py collectstatic --noinput \
+--settings={0}".format(_localsettings()), pty=True)
+
+
+@task
+def geoserverfixture(ctx):
+ print("********************geoserver fixture********************************")
+ _geoserver_info_provision(os.environ['GEOSERVER_LOCATION'] + "rest/")
+
+
+@task
+def monitoringfixture(ctx):
+ print("*******************monitoring fixture********************************")
+ ctx.run("rm -rf /tmp/default_monitoring_apps_docker.json", pty=True)
+ _prepare_monitoring_fixture()
+ try:
+ ctx.run("django-admin.py loaddata /tmp/default_monitoring_apps_docker.json \
+--settings={0}".format(_localsettings()), pty=True)
+ except Exception as e:
+ print("ERROR installing monitoring fixture: " + str(e))
+
+
+@task
+def updategeoip(ctx):
+ print("**************************update geoip*******************************")
+ ctx.run("django-admin.py updategeoip \
+ --settings={0}".format(_localsettings()), pty=True)
+
+
+@task
+def updateadmin(ctx):
+ print("***********************update admin details**************************")
+ ctx.run("rm -rf /tmp/django_admin_docker.json", pty=True)
+ _prepare_admin_fixture(os.environ.get('ADMIN_PASSWORD', 'admin'), os.environ.get('ADMIN_EMAIL', 'admin@example.org'))
+ ctx.run("django-admin.py loaddata /tmp/django_admin_docker.json \
+--settings={0}".format(_localsettings()), pty=True)
+
+
+@task
+def collectmetrics(ctx):
+ print("************************collect metrics******************************")
+ ctx.run("python -W ignore manage.py collect_metrics \
+ --settings={0} -n -t xml".format(_localsettings()), pty=True)
+
@task
def initialized(ctx):
print("**************************init file********************************")
ctx.run('date > /mnt/volumes/statics/geonode_init.lock')
+def _docker_host_ip():
+ client = docker.from_env()
+ ip_list = client.containers.run(BOOTSTRAP_IMAGE_CHEIP,
+ network_mode='host'
+ ).split("\n")
+ if len(ip_list) > 1:
+ print("Docker daemon is running on more than one \
+address {0}".format(ip_list))
+ print("Only the first address:{0} will be returned!".format(
+ ip_list[0]
+ ))
+ else:
+ print("Docker daemon is running at the following \
+address {0}".format(ip_list[0]))
+ return ip_list[0]
@task
def devrequirements(ctx):
print("*********************install dev requirements**********************")
ctx.run('pip install -r requirements_dev.txt --upgrade')
+def _container_exposed_port(component, instname):
+ client = docker.from_env()
+ ports_dict = json.dumps(
+ [c.attrs['Config']['ExposedPorts'] for c in client.containers.list(
+ filters={
+ 'label': 'org.geonode.component={0}'.format(component),
+ 'status': 'running'
+ }
+ ) if '{0}'.format(instname) in c.name][0]
+ )
+ for key in json.loads(ports_dict):
+ port = re.split('/tcp', key)[0]
+ return port
def _update_db_connstring():
user = os.getenv('GEONODE_DATABASE', 'geonode')
@@ -156,24 +346,73 @@ def _localsettings():
return settings
+def _rest_api_availability(url):
+ import requests
+ try:
+ r = requests.request('get', url, verify=False)
+ r.raise_for_status() # Raises a HTTPError if the status is 4xx, 5xxx
+ except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e:
+ print("GeoServer connection error is {0}".format(e))
+ return False
+ except requests.exceptions.HTTPError as er:
+ print("GeoServer HTTP error is {0}".format(er))
+ return False
+ else:
+ print("GeoServer API are available!")
+ return True
+
+
def _geonode_public_host_ip():
- gn_pub_hostip = os.getenv('GEONODE_LB_HOST_IP', 'localhost')
+ gn_pub_hostip = os.getenv('GEONODE_LB_HOST_IP', None)
+ if not gn_pub_hostip:
+ gn_pub_hostip = _docker_host_ip()
return gn_pub_hostip
def _geonode_public_port():
- gn_pub_port = os.getenv('GEONODE_LB_PORT', '80')
- return str(gn_pub_port)
+ gn_pub_port = os.getenv('GEONODE_LB_PORT', '')
+ if not gn_pub_port:
+ gn_pub_port = _container_exposed_port(
+ 'nginx',
+ os.getenv('GEONODE_INSTANCE_NAME', 'geonode')
+ )
+ elif gn_pub_port in ('80', '443'):
+ gn_pub_port = None
+ return gn_pub_port
+
+
+def _geoserver_info_provision(url):
+ from django.conf import settings
+ from geoserver.catalog import Catalog
+ print("Setting GeoServer Admin Password...")
+ cat = Catalog(url,
+ username=settings.OGC_SERVER_DEFAULT_USER,
+ password=settings.OGC_SERVER_DEFAULT_PASSWORD
+ )
+ headers = {
+ "Content-type": "application/xml",
+ "Accept": "application/xml"
+ }
+ data = """<?xml version="1.0" encoding="UTF-8"?>
+<userPassword>
+ <newPassword>{0}</newPassword>
+</userPassword>""".format(os.getenv('GEOSERVER_ADMIN_PASSWORD', 'geoserver'))
+
+ response = cat.http_request(cat.service_url + '/security/self/password', method="PUT", data=data, headers=headers)
+ print("Response Code: %s" % response.status_code)
+ if response.status_code == 200:
+ print("GeoServer admin password updated SUCCESSFULLY!")
+ else:
+ print("WARNING: GeoServer admin password *NOT* updated: code [%s]" % response.status_code)
def _prepare_oauth_fixture():
+ upurl = urlparse(os.environ['SITEURL'])
+ net_scheme = upurl.scheme
pub_ip = _geonode_public_host_ip()
print("Public Hostname or IP is {0}".format(pub_ip))
pub_port = _geonode_public_port()
print("Public PORT is {0}".format(pub_port))
- pub_protocol = 'https' if pub_port == '443' else 'http'
- if pub_protocol == 'https' or pub_port == '80':
- pub_port = None
default_fixture = [
{
"model": "oauth2_provider.application",
@@ -183,16 +422,12 @@ def _prepare_oauth_fixture():
"created": "2018-05-31T10:00:31.661Z",
"updated": "2018-05-31T11:30:31.245Z",
"algorithm": "RS256",
- "redirect_uris": "{0}://{1}{2}/geoserver/index.html".format(
- pub_protocol, pub_ip, ':' + pub_port if pub_port else ''
- ),
+ "redirect_uris": "{0}://{1}:{2}/geoserver/index.html".format(net_scheme, pub_ip, pub_port) if pub_port else "{0}://{1}/geoserver/index.html".format(net_scheme, pub_ip),
"name": "GeoServer",
"authorization_grant_type": "authorization-code",
"client_type": "confidential",
- "client_id": "Jrchz2oPY3akmzndmgUTYrs9gczlgoV20YPSvqaV",
- "client_secret": "\
-rCnp5txobUo83EpQEblM8fVj3QT5zb5qRfxNsuPzCqZaiRyIoxM4jdgMiZKFfePBHYXCLd7B8NlkfDB\
-Y9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3",
+ "client_id": "{0}".format(os.environ['OAUTH2_CLIENT_ID']),
+ "client_secret": "{0}".format(os.environ['OAUTH2_CLIENT_SECRET']),
"user": [
"admin"
]
@@ -201,3 +436,139 @@ Y9HKeIQPcy5Cp08KQNpRHQbjpLItDHv12GvkSeXp6OxaUETv3",
]
with open('/tmp/default_oauth_apps_docker.json', 'w') as fixturefile:
json.dump(default_fixture, fixturefile)
+
+
+def _prepare_site_fixture():
+ upurl = urlparse(os.environ['SITEURL'])
+ default_fixture = [
+ {
+ "model": "sites.site",
+ "pk": 1,
+ "fields": {
+ "domain": "{0}".format(upurl.hostname),
+ "name": "{0}".format(upurl.hostname)
+ }
+ }
+ ]
+ with open('/tmp/default_site.json', 'w') as fixturefile:
+ json.dump(default_fixture, fixturefile)
+
+
+def _prepare_monitoring_fixture():
+ upurl = urlparse(os.environ['SITEURL'])
+ net_scheme = upurl.scheme
+ net_loc = upurl.netloc
+ pub_ip = _geonode_public_host_ip()
+ print("Public Hostname or IP is {0}".format(pub_ip))
+ pub_port = _geonode_public_port()
+ print("Public PORT is {0}".format(pub_port))
+ #d = str(datetime.datetime.now())
+ d = '1970-01-01 00:00:00'
+ default_fixture = [
+ {
+ "fields": {
+ "active": True,
+ "ip": "{0}".format(socket.gethostbyname('geonode')),
+ "name": "{0}".format(os.environ['MONITORING_HOST_NAME'])
+ },
+ "model": "monitoring.host",
+ "pk": 1
+ },
+ {
+ "fields": {
+ "active": True,
+ "ip": "{0}".format(socket.gethostbyname('geoserver')),
+ "name": "geoserver"
+ },
+ "model": "monitoring.host",
+ "pk": 2
+ },
+ {
+ "fields": {
+ "name": "{0}".format(os.environ['MONITORING_SERVICE_NAME']),
+ # "url": "{0}://{1}/".format(net_scheme, net_loc),
+ "url": "{0}".format(os.environ['SITEURL']),
+ "notes": "",
+ "last_check": d,
+ "active": True,
+ "host": 1,
+ "check_interval": "00:01:00",
+ "service_type": 1
+ },
+ "model": "monitoring.service",
+ "pk": 1
+ },
+ {
+ "fields": {
+ "name": "geoserver-hostgeonode",
+ # "url": "{0}://{1}/".format(net_scheme, net_loc),
+ "url": "{0}".format(os.environ['SITEURL']),
+ "notes": "",
+ "last_check": d,
+ "active": True,
+ "host": 1,
+ "check_interval": "00:01:00",
+ "service_type": 3
+ },
+ "model": "monitoring.service",
+ "pk": 2
+ },
+ {
+ "fields": {
+ "name": "geoserver-hostgeoserver",
+ "url": "{0}".format(os.environ['GEOSERVER_PUBLIC_LOCATION']),
+ "notes": "",
+ "last_check": d,
+ "active": True,
+ "host": 2,
+ "check_interval": "00:01:00",
+ "service_type": 4
+ },
+ "model": "monitoring.service",
+ "pk": 3
+ },
+ {
+ "fields": {
+ "name": "default-geoserver",
+ "url": "http://geoserver:8080/geoserver/",
+ "notes": "",
+ "last_check": d,
+ "active": True,
+ "host": 2,
+ "check_interval": "00:01:00",
+ "service_type": 2
+ },
+ "model": "monitoring.service",
+ "pk": 4
+ }
+ ]
+ with open('/tmp/default_monitoring_apps_docker.json', 'w') as fixturefile:
+ json.dump(default_fixture, fixturefile)
+
+
+def _prepare_admin_fixture(admin_password, admin_email):
+ from django.contrib.auth.hashers import make_password
+ d = datetime.datetime.now()
+ mdext_date = d.isoformat()[:23] + "Z"
+ default_fixture = [
+ {
+ "fields": {
+ "date_joined": mdext_date,
+ "email": admin_email,
+ "first_name": "",
+ "groups": [],
+ "is_active": True,
+ "is_staff": True,
+ "is_superuser": True,
+ "last_login": mdext_date,
+ "last_name": "",
+ "password": make_password(admin_password),
+ "user_permissions": [],
+ "username": "admin"
+ },
+ "model": "people.Profile",
+ "pk": 1000
+ }
+ ]
+ with open('/tmp/django_admin_docker.json', 'w') as fixturefile:
+ json.dump(default_fixture, fixturefile)
diff --git a/ti-compose-base.yml b/ti-compose-base.yml
new file mode 100644
index 0000000000000000000000000000000000000000..34b7070f46dd3942b312760f2b34f4fb3cb5f166
--- /dev/null
+++ b/ti-compose-base.yml
@@ -0,0 +1,170 @@
+version: '2.2'
+services:
+
+ db:
+ image: geonode/postgis:11
+ restart: unless-stopped
+ container_name: db4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ # tty: true
+ labels:
+ org.geonode.component: db
+ org.geonode.instance.name: geonode
+ volumes:
+ - dbdata:/var/lib/postgresql/data
+ - dbbackups:/pg_backups
+ env_file:
+ - .env
+
+ rabbitmq:
+ image: rabbitmq
+ restart: unless-stopped
+ container_name: rabbitmq4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ tty: true
+ labels:
+ org.geonode.component: rabbitmq
+ org.geonode.instance.name: geonode
+ org.geonode.deployment.name: ${COMPOSE_PROJECT_NAME}
+
+ geoserver:
+ image: thuenen/geoserver:2.17.2
+ build: ./docker/geoserver/
+ restart: unless-stopped
+ container_name: geoserver4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ # tty: true
+ labels:
+ org.geonode.component: geoserver
+ org.geonode.instance.name: geonode
+ depends_on:
+ - db
+ - data-dir-conf
+ volumes:
+ - statics:/mnt/volumes/statics
+ - geoserver-data-dir:/geoserver_data/data
+ - backup-restore:/backup_restore
+ - data:/data
+ env_file:
+ - .env
+
+ django:
+ image: thuenen/geonode:3.x
+ restart: unless-stopped
+ build: .
+ container_name: django4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ # tty: true
+ labels:
+ org.geonode.component: django
+ org.geonode.instance.name: geonode
+ depends_on:
+ - db
+ - rabbitmq
+ - data-dir-conf
+ volumes:
+ - statics:/mnt/volumes/statics
+ - geoserver-data-dir:/geoserver_data/data
+ - backup-restore:/backup_restore
+ - data:/data
+ env_file:
+ - .env
+ environment:
+ UWSGI_CMD: uwsgi --ini /usr/src/geonode/uwsgi.ini
+ IS_CELERY: 'False'
+
+ celery:
+ image: thuenen/celery:3.x
+ restart: unless-stopped
+ build: .
+ container_name: celery4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ # tty: true
+ labels:
+ org.geonode.component: celery
+ org.geonode.instance.name: geonode
+ depends_on:
+ - db
+ - rabbitmq
+ - data-dir-conf
+ volumes:
+ - statics:/mnt/volumes/statics
+ - geoserver-data-dir:/geoserver_data/data
+ - backup-restore:/backup_restore
+ - data:/data
+ env_file:
+ - .env
+ environment:
+ CELERY_CMD: celery -A geonode.celery_app:app worker -B -E --statedb=/mnt/volumes/statics/worker.state -s /mnt/volumes/statics/celerybeat-schedule --loglevel=INFO --concurrency=10 -n worker1@%h -f /var/log/celery.log
+ IS_CELERY: 'True'
+
+ geonode:
+ image: thuenen/nginx:3.x
+ build: ./docker/nginx/
+ restart: unless-stopped
+ container_name: nginx4${COMPOSE_PROJECT_NAME}
+ stdin_open: true
+ # tty: true
+ labels:
+ org.geonode.component: nginx
+ org.geonode.instance.name: geonode
+ depends_on:
+ - django
+ - geoserver
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - nginx-confd:/etc/nginx
+ - nginx-certificates:/geonode-certificates
+ - statics:/mnt/volumes/statics
+ env_file:
+ - .env
+
+ data-dir-conf:
+ image: geonode/geoserver_data:2.17.2
+ restart: on-failure
+ container_name: gsconf4${COMPOSE_PROJECT_NAME}
+ labels:
+ org.geonode.component: conf
+ org.geonode.instance.name: geonode
+ command: /bin/true
+ volumes:
+ - geoserver-data-dir:/geoserver_data/data
+
+ jenkins:
+ image: jenkins/jenkins:lts
+ # image: istresearch/jenkins:latest
+ container_name: jenkins4${COMPOSE_PROJECT_NAME}
+ user: jenkins
+ ports:
+ - '${JENKINS_HTTP_PORT}:${JENKINS_HTTP_PORT}'
+ - '${JENKINS_HTTPS_PORT}:${JENKINS_HTTPS_PORT}'
+ - '50000:50000'
+ # network_mode: "host"
+ volumes:
+ - jenkins_data:/var/jenkins_home
+ - backup-restore:/backup_restore
+ - data:/data
+ environment:
+ - 'JENKINS_OPTS=--httpPort=${JENKINS_HTTP_PORT} --httpsPort=${JENKINS_HTTPS_PORT} --prefix=/jenkins'
+
+volumes:
+ jenkins_data:
+ driver: local
+ statics:
+ name: ${COMPOSE_PROJECT_NAME}-statics
+ nginx-confd:
+ name: ${COMPOSE_PROJECT_NAME}-nginxconfd
+ nginx-certificates:
+ name: ${COMPOSE_PROJECT_NAME}-nginxcerts
+ geoserver-data-dir:
+ name: ${COMPOSE_PROJECT_NAME}-gsdatadir
+ dbdata:
+ name: ${COMPOSE_PROJECT_NAME}-dbdata
+ dbbackups:
+ name: ${COMPOSE_PROJECT_NAME}-dbbackups
+ backup-restore:
+ name: ${COMPOSE_PROJECT_NAME}-backup-restore
+ data:
+ name: ${COMPOSE_PROJECT_NAME}-data
\ No newline at end of file
diff --git a/ti-compose-prod.yml b/ti-compose-prod.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a49413b545c3434bd5b4df4a9eb5df01dcfbecfc
--- /dev/null
+++ b/ti-compose-prod.yml
@@ -0,0 +1,52 @@
+version: '2.2'
+
+## production setting for internal TISDAR application
+## for DMZ based portal the database port has to be closed
+services:
+
+ django:
+ build: .
+ # Loading the app is defined here to allow for
+ # autoreload on changes it is mounted on top of the
+ # old copy that docker added when creating the image
+ volumes:
+ - '.:/usr/src/geonode'
+ - '/data/backup_restore:/backup_restore' # Link to local volume in the HOST
+ env_file:
+ - .env
+ - production.env
+
+ geonode:
+ volumes:
+ - '/opt/certificates:/geonode-certificates'
+ env_file:
+ - .env
+ - production.env
+
+ celery:
+ volumes:
+ - '/data/backup_restore:/backup_restore' # Link to local volume in the HOST
+ env_file:
+ - .env
+ - production.env
+
+ geoserver:
+ volumes:
+ - '/data/backup_restore:/backup_restore' # Link to local volume in the HOST
+ env_file:
+ - .env
+ - production.env
+
+ jenkins:
+ volumes:
+ - '/data/backup_restore:/backup_restore' # Link to local volume in the HOST
+ env_file:
+ - .env
+ - production.env
+
+ db:
+ ports:
+ - "5432:5432"
+ env_file:
+ - .env
+ - production.env
diff --git a/uwsgi.ini b/uwsgi.ini
index 96da8a20e0993ef1172e2fadcbe26c120e81c433..0313bd7ee8eab4517d0eb19815309aa7ba494d4f 100644
--- a/uwsgi.ini
+++ b/uwsgi.ini
@@ -1,10 +1,10 @@
[uwsgi]
-uwsgi-socket = 0.0.0.0:8000
-# http-socket = 0.0.0.0:8000
+# socket = 0.0.0.0:8000
+http-socket = 0.0.0.0:8000
logto = /var/log/geonode.log
pidfile = /tmp/geonode.pid
-chdir = /usr/src/app/
+chdir = /usr/src/geonode/
module = geonode.wsgi:application
strict = false
@@ -14,21 +14,18 @@ vacuum = true ; Delete sockets during shutdown
single-interpreter = true
die-on-term = true ; Shutdown when receiving SIGTERM (default is respawn)
need-app = true
+thunder-lock = true
-# logging
-# path to where uwsgi logs will be saved
-# logto = /opt/data/geonode_logs/geonode.log
-
-touch-reload = /usr/src/app/geonode/wsgi.py
+touch-reload = /usr/src/geonode/geonode/wsgi.py
buffer-size = 32768
-harakiri = 60 ; forcefully kill workers after 60 seconds
+harakiri = 600 ; forcefully kill workers after 600 seconds
py-callos-afterfork = true ; allow workers to trap signals
max-requests = 1000 ; Restart workers after this many requests
max-worker-lifetime = 3600 ; Restart workers after this many seconds
reload-on-rss = 2048 ; Restart workers after this much resident memory
-worker-reload-mercy = 60 ; How long to wait before forcefully killing workers
+worker-reload-mercy = 600 ; How long to wait before forcefully killing workers
cheaper-algo = busyness
processes = 128 ; Maximum number of workers allowed
@@ -43,5 +40,6 @@ cheaper-busyness-max = 70 ; Above this threshold, spawn new workers
cheaper-busyness-backlog-alert = 16 ; Spawn emergency workers if more than this many requests are waiting in the queue
cheaper-busyness-backlog-step = 2 ; How many emergency workers to create if there are too many requests in the queue
-# daemonize = /var/log/uwsgi/geonode.log
-# cron = -1 -1 -1 -1 -1 /usr/local/bin/python /usr/src/{{project_name}}/manage.py collect_metrics -n
+# cron = -1 -1 -1 -1 -1 sh -c '/usr/src/geonode/manage.sh collect_metrics -n -t xml';
+cron = 0 0 -1 -1 -1 sh -c 'find /backup_restore/ -type f -mtime +30 -exec rm -f {} \;'
+cron = 0 0 -1 -1 -1 sh -c 'find /backup_restore/ -type d -ctime +30 -exec rm -rf {} \;'
diff --git a/wait-for-databases.sh b/wait-for-databases.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6eb6d6498affde2f83af47f3d1378007dc291f21
--- /dev/null
+++ b/wait-for-databases.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+host="$1"
+shift
+
+until PGPASSWORD=postgres psql -h "$host" -U "postgres" -P "pager=off" -c '\l'; do
+ >&2 echo "Postgres is unavailable - sleeping"
+ sleep 1
+done
+
+until PGPASSWORD=${GEONODE_DATABASE_PASSWORD} psql -h "$host" -U ${GEONODE_DATABASE} -d ${GEONODE_DATABASE} -P "pager=off" -c '\l'; do
+ >&2 echo "${GEONODE_DATABASE} is unavailable - sleeping"
+ sleep 1
+done
+
+until PGPASSWORD=${GEONODE_GEODATABASE_PASSWORD} psql -h "$host" -U ${GEONODE_GEODATABASE} -d ${GEONODE_GEODATABASE} -P "pager=off" -c '\l'; do
+ >&2 echo "${GEONODE_GEODATABASE} is unavailable - sleeping"
+ sleep 1
+done
+
+>&2 echo "GeoNode databases are up - executing command"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment