diff --git a/Techops/reviewboard.knownelement.com/Dockerfile b/Techops/reviewboard.knownelement.com/Dockerfile new file mode 100644 index 0000000..b777422 --- /dev/null +++ b/Techops/reviewboard.knownelement.com/Dockerfile @@ -0,0 +1,44 @@ +FROM cloudron/base:4.2.0 + +# Install required packages +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + python3 python3-pip python3-dev python3-venv \ + nginx supervisor \ + memcached libpq-dev \ + libldap2-dev libsasl2-dev \ + git-core subversion \ + libxml2-dev libxslt1-dev \ + libmagic-dev \ + gcc && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Create Python virtual environment +RUN python3 -m venv /app/code/venv +ENV PATH="/app/code/venv/bin:${PATH}" + +# Install Review Board dependencies +RUN pip3 install --no-cache-dir --upgrade pip wheel setuptools && \ + pip3 install --no-cache-dir psycopg2-binary gunicorn django-storages + +# Install Review Board +RUN pip3 install --no-cache-dir reviewboard + +# Install OIDC authentication +RUN pip3 install --no-cache-dir mozilla-django-oidc + +# Install LDAP authentication +RUN pip3 install --no-cache-dir django-auth-ldap + +# Make the data directories ready +RUN mkdir -p /app/data/media /app/data/static /app/data/logs /app/data/conf /app/data/site + +# Copy configuration files +COPY nginx.conf /etc/nginx/sites-available/default +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY start.sh /app/code/start.sh +RUN chmod +x /app/code/start.sh + +# Set up the entry point +CMD ["/app/code/start.sh"] \ No newline at end of file diff --git a/Techops/reviewboard.knownelement.com/ReviewBoard-BuildNotes.md b/Techops/reviewboard.knownelement.com/ReviewBoard-BuildNotes.md new file mode 100644 index 0000000..c3211c4 --- /dev/null +++ b/Techops/reviewboard.knownelement.com/ReviewBoard-BuildNotes.md @@ -0,0 +1,147 @@ +# Review Board - Cloudron Build Notes + +This document provides instructions for building, testing, and deploying the Review Board Cloudron package. + +## Package Overview + +Review Board is a powerful web-based code review tool that helps teams review code, documents, and images before they are committed. This package configures Review Board to run on Cloudron with the following features: + +- PostgreSQL database for data storage +- Memcached for caching +- Nginx as the web server +- Gunicorn as the WSGI server +- Support for Cloudron’s OIDC and LDAP authentication +- Proper data separation following Cloudron’s filesystem layout + +## Prerequisites + +1. Cloudron CLI tool installed (`npm install -g cloudron`) +2. Docker installed and running +3. Cloudron account with administrative access + +## Files Included in the Package + +1. **CloudronManifest.json** - Defines the application for Cloudron +2. **Dockerfile** - Instructions for building the Docker image +3. **start.sh** - Initialization and startup script +4. **supervisord.conf** - Process management configuration +5. **nginx.conf** - Web server configuration + +## Building the Package + +1. Create a new directory for your package files: + ```bash + mkdir reviewboard-cloudron + cd reviewboard-cloudron + ``` + +2. Create all the package files in this directory. + +3. Download the Review Board icon and save it as `icon.png`: + ```bash + curl -L “https://raw.githubusercontent.com/reviewboard/reviewboard/master/reviewboard/static/rb/images/logo.png” -o icon.png + ``` + +4. Build the package: + ```bash + cloudron build + ``` + +## Testing Locally (Optional) + +1. Run the Docker image locally to test basic functionality: + ```bash + docker run -p 8000:8000 cloudron/reviewboard-app:1.0.0 + ``` + +2. Access the application at http://localhost:8000 to check if it starts correctly. + +## Deploying to Cloudron + +1. Install the package on your Cloudron: + ```bash + cloudron install —image cloudron/reviewboard-app:1.0.0 + ``` + +2. Or, to update an existing installation: + ```bash + cloudron update —image cloudron/reviewboard-app:1.0.0 —app reviewboard.yourdomain.com + ``` + +## Post-Installation + +1. Access your Review Board instance at the URL assigned by Cloudron. +2. Log in using the initial admin credentials: + - Username: `admin` + - Password: Check the file `/app/data/admin_password.txt` inside the app container: + ```bash + cloudron exec —app reviewboard.yourdomain.com cat /app/data/admin_password.txt + ``` + +3. Configure your repository connections in the Review Board admin interface at `/admin/`. + +## Authentication Details + +### OIDC Authentication (Default) + +The package is configured to use Cloudron’s OIDC provider when available. Users logging in via OIDC will be automatically provisioned in Review Board. + +### LDAP Authentication (Alternative) + +If OIDC is not available, the package will fall back to using Cloudron’s LDAP server for authentication. + +## Repository Support + +Review Board supports the following repository types: +- Git +- SVN +- Mercurial +- Perforce +- Bazaar +- CVS +- IBM Rational ClearCase +- And more + +Configure these in the Admin > Repositories section after login. + +## Troubleshooting + +1. Check application logs: + ```bash + cloudron logs —app reviewboard.yourdomain.com + ``` + +2. Access the container directly to troubleshoot: + ```bash + cloudron exec —app reviewboard.yourdomain.com bash + ``` + +3. Validate database connectivity: + ```bash + cloudron exec —app reviewboard.yourdomain.com psql “$CLOUDRON_POSTGRESQL_URL” + ``` + +4. If Review Board shows errors about missing repositories, ensure they are accessible from the Cloudron container. + +## Backup and Restore + +Cloudron automatically backs up the `/app/data` directory, which includes: +- Database (via PostgreSQL addon) +- Media files (uploaded files, screenshots, etc.) +- Configuration files +- Repository cache + +No additional backup configuration is necessary. + +## Upgrading Review Board + +When a new version of Review Board is released: + +1. Update the Dockerfile to install the new version +2. Rebuild the Docker image +3. Update the Cloudron app using the `cloudron update` command + +## Additional Resources + +- [Review Board Documentation](https://www.reviewboard.org/docs/) +- [Cloudron Documentation](https://docs.cloudron.io/) \ No newline at end of file diff --git a/Techops/reviewboard.knownelement.com/nginx.conf b/Techops/reviewboard.knownelement.com/nginx.conf new file mode 100644 index 0000000..db9ea1a --- /dev/null +++ b/Techops/reviewboard.knownelement.com/nginx.conf @@ -0,0 +1,43 @@ +server { + listen 8000; + server_name CLOUDRON_APP_DOMAIN; + + client_max_body_size 100M; + + # Handle static and media files + location /static/ { + alias /app/data/static/; + expires 30d; + } + + location /media/ { + alias /app/data/media/; + expires 30d; + } + + # Forward requests to the Django application + location / { + proxy_pass http://127.0.0.1:8001; + proxy_set_header Host $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_connect_timeout 300s; + proxy_read_timeout 300s; + } + + # Set up OIDC callback path + location /api/v1/session/callback { + proxy_pass http://127.0.0.1:8001; + proxy_set_header Host $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; + } + + # Handle errors + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} \ No newline at end of file diff --git a/Techops/reviewboard.knownelement.com/start.sh b/Techops/reviewboard.knownelement.com/start.sh new file mode 100644 index 0000000..ca57273 --- /dev/null +++ b/Techops/reviewboard.knownelement.com/start.sh @@ -0,0 +1,187 @@ +#!/bin/bash +set -e + +# Create data directories if they don't exist +if [ ! -f /app/data/.initialized ]; then + echo "Initializing Review Board data directories..." + + # Create directories + mkdir -p /app/data/conf + mkdir -p /app/data/media + mkdir -p /app/data/static + mkdir -p /app/data/logs + + # Generate a random admin password and save it + ADMIN_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16) + echo $ADMIN_PASSWORD > /app/data/admin_password.txt + chmod 640 /app/data/admin_password.txt + + # Mark as initialized + touch /app/data/.initialized + echo "Initialization complete." +fi + +# Set proper ownership +chown -R cloudron:cloudron /app/data + +# Configure database connection +if [ ! -f /app/data/conf/settings_local.py ]; then + echo "Creating Review Board configuration..." + + # Get database connection details from CLOUDRON_POSTGRESQL_URL + DB_HOST=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d@ -f2 | cut -d/ -f1) + DB_NAME=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f4) + DB_USER=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f3 | cut -d: -f1) + DB_PASSWORD=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d: -f3 | cut -d@ -f1) + + # Create settings_local.py + cat > /app/data/conf/settings_local.py << EOF +# Cloudron Review Board Settings +import os + +# Database settings +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': '${DB_NAME}', + 'USER': '${DB_USER}', + 'PASSWORD': '${DB_PASSWORD}', + 'HOST': '${DB_HOST}', + } +} + +# Site settings +SITE_ROOT = '/' +MEDIA_ROOT = '/app/data/media' +STATIC_ROOT = '/app/data/static' + +# Email settings +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'mail' +EMAIL_PORT = 25 +DEFAULT_FROM_EMAIL = 'reviewboard@${CLOUDRON_APP_DOMAIN}' +SERVER_EMAIL = 'reviewboard@${CLOUDRON_APP_DOMAIN}' + +# Cache settings +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:11211', + } +} +EOF + + # Add authentication settings based on Cloudron's environment + if [ -n "${CLOUDRON_LDAP_SERVER}" ]; then + # LDAP Authentication + cat >> /app/data/conf/settings_local.py << EOF +# LDAP Authentication +AUTHENTICATION_BACKENDS = ( + 'django_auth_ldap.backend.LDAPBackend', + 'django.contrib.auth.backends.ModelBackend', +) + +import ldap +from django_auth_ldap.config import LDAPSearch, GroupOfNamesType + +AUTH_LDAP_SERVER_URI = "ldap://${CLOUDRON_LDAP_SERVER}:${CLOUDRON_LDAP_PORT}" +AUTH_LDAP_BIND_DN = "${CLOUDRON_LDAP_BIND_DN}" +AUTH_LDAP_BIND_PASSWORD = "${CLOUDRON_LDAP_BIND_PASSWORD}" +AUTH_LDAP_USER_SEARCH = LDAPSearch( + "${CLOUDRON_LDAP_USERS_BASE_DN}", + ldap.SCOPE_SUBTREE, + "(${CLOUDRON_LDAP_USERNAME_FIELD}=%(user)s)" +) +AUTH_LDAP_GROUP_SEARCH = LDAPSearch( + "${CLOUDRON_LDAP_GROUPS_BASE_DN}", + ldap.SCOPE_SUBTREE, + "(objectClass=groupOfNames)" +) +AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail" +} +AUTH_LDAP_ALWAYS_UPDATE_USER = True +EOF + elif [ -n "${CLOUDRON_OIDC_IDENTIFIER}" ]; then + # OIDC Authentication + cat >> /app/data/conf/settings_local.py << EOF +# OIDC Authentication +AUTHENTICATION_BACKENDS = ( + 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', + 'django.contrib.auth.backends.ModelBackend', +) + +OIDC_RP_CLIENT_ID = "${CLOUDRON_OIDC_CLIENT_ID}" +OIDC_RP_CLIENT_SECRET = "${CLOUDRON_OIDC_CLIENT_SECRET}" +OIDC_OP_AUTHORIZATION_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/authorize" +OIDC_OP_TOKEN_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/token" +OIDC_OP_USER_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/userinfo" +OIDC_OP_JWKS_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/jwks" +OIDC_AUTHENTICATE_CLASS = 'mozilla_django_oidc.views.OIDCAuthenticationRequestView' +OIDC_CALLBACK_CLASS = 'mozilla_django_oidc.views.OIDCAuthenticationCallbackView' +LOGIN_REDIRECT_URL = '/' +LOGOUT_REDIRECT_URL = '/' + +def oidc_username_transform(username): + return username.split('@')[0] + +OIDC_USERNAME_ALGO = oidc_username_transform +EOF + fi +fi + +# Initialize the Review Board site if not already done +if [ ! -f /app/data/.db_initialized ]; then + echo "Setting up the Review Board site..." + + # Get database connection details + DB_HOST=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d@ -f2 | cut -d/ -f1) + DB_NAME=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f4) + DB_USER=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f3 | cut -d: -f1) + DB_PASSWORD=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d: -f3 | cut -d@ -f1) + + # Create a site directory for Review Board + rb-site install --noinput \ + --domain-name=${CLOUDRON_APP_DOMAIN} \ + --site-root=/ \ + --static-url=static/ \ + --media-url=media/ \ + --db-type=postgresql \ + --db-name=${DB_NAME} \ + --db-user=${DB_USER} \ + --db-pass=${DB_PASSWORD} \ + --db-host=${DB_HOST} \ + --cache-type=memcached \ + --cache-info=localhost:11211 \ + --web-server-type=wsgi \ + --admin-user=admin \ + --admin-password=$(cat /app/data/admin_password.txt) \ + --admin-email=admin@${CLOUDRON_APP_DOMAIN} \ + /app/data/site + + # Copy settings_local.py to the site + cp /app/data/conf/settings_local.py /app/data/site/conf/settings_local.py + + # Mark as initialized + touch /app/data/.db_initialized + echo "Database initialization complete." +fi + +# Collect static files if they don't exist yet +if [ ! -f /app/data/.static_collected ]; then + echo "Collecting static files..." + cd /app/data/site + PYTHONPATH=/app/data/site python /app/data/site/manage.py collectstatic --noinput + touch /app/data/.static_collected + echo "Static files collected." +fi + +# Configure NGINX to use the static and media directories +sed -i "s|CLOUDRON_APP_DOMAIN|${CLOUDRON_APP_DOMAIN}|g" /etc/nginx/sites-available/default + +# Start services using supervisord +echo "Starting Review Board..." +exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf \ No newline at end of file diff --git a/Techops/reviewboard.knownelement.com/supervisord.conf b/Techops/reviewboard.knownelement.com/supervisord.conf new file mode 100644 index 0000000..602edeb --- /dev/null +++ b/Techops/reviewboard.knownelement.com/supervisord.conf @@ -0,0 +1,35 @@ +[supervisord] +nodaemon=true +logfile=/dev/stdout +logfile_maxbytes=0 +user=root + +[program:memcached] +command=/usr/bin/memcached -m 64 -p 11211 -u nobody -l 127.0.0.1 +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:reviewboard] +command=/app/code/venv/bin/gunicorn --bind 127.0.0.1:8001 --workers 2 --timeout 90 wsgi:application +directory=/app/data/site +user=cloudron +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +environment=HOME="/app/data",PYTHONPATH="/app/data/site" + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 \ No newline at end of file