Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,21 @@ jobs:
if: ${{ !cancelled() && steps.set_git_branch.conclusion == 'success' }}
# Do not remove the blank lines from the input.
run: |
printf "latest\n" | \
printf "edge\n" | \
GIT_BRANCH="${GIT_BRANCH}" SKIP_PULL=true sudo -E ./deploy/auto-install.sh --upgrade \
|| (cat /opt/openwisp/autoinstall.log && exit 1)

- name: Fix permissions for CI user
if: ${{ !cancelled() && steps.auto_install_upgrade.conclusion == 'success' }}
run: |
sudo chown -R $USER:$USER /opt/openwisp

- name: Test
if: ${{ !cancelled() && steps.auto_install_upgrade.conclusion == 'success' }}
uses: openwisp/openwisp-utils/.github/actions/retry-command@master
with:
delay_seconds: 30
max_attempts: 5
max_attempts: 1
# The auto-install script installs docker-openwisp by default in
# /opt/openwisp/docker-openwisp. To ensure the test runs correctly
# and environment variables remain intact, it is essential to
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# the heading "Makefile Options".

# The .env file can override ?= variables in the Makefile (e.g. OPENWISP_VERSION, IMAGE_OWNER)
include .env
include .env

# RELEASE_VERSION: version string used when tagging a new release.
RELEASE_VERSION = 25.10.0
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ services:
- openwisp_ssh:/home/openwisp/.ssh
- influxdb_data:/var/lib/influxdb
- ./customization/configuration/django/:/opt/openwisp/openwisp/configuration:ro
- ./customization/theme:/opt/openwisp/static_custom:ro
depends_on:
- postgres
- redis
Expand Down Expand Up @@ -128,7 +129,7 @@ services:
- openwisp_media:/opt/openwisp/public/media:ro
- openwisp_private_storage:/opt/openwisp/public/private:ro
- openwisp_certs:/etc/letsencrypt
- ./customization/theme:/opt/openwisp/public/custom:ro
- ./customization/nginx:/opt/openwisp/public/custom:ro
networks:
default:
aliases:
Expand Down
38 changes: 31 additions & 7 deletions docs/user/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ adding customizations. Execute these commands in the same location as the
touch customization/configuration/django/__init__.py
touch customization/configuration/django/custom_django_settings.py
mkdir -p customization/theme
mkdir -p customization/nginx

You can also refer to the `directory structure of Docker OpenWISP
repository
Expand Down Expand Up @@ -84,16 +85,24 @@ follow the following guide.

2. Create your custom CSS / Javascript file in ``customization/theme``
directory created in the above section. E.g.
``customization/theme/static/custom/css/custom-theme.css``.
3. Start the nginx containers.
``customization/theme/custom/css/custom-theme.css``.
3. Recreate the dashboard container to apply the changes:

.. code-block:: shell

docker compose up -d --force-recreate dashboard

.. note::

1. You can edit the styles / JavaScript files now without restarting
the container, as long as file is in the correct place, it will be
picked.
2. You can create a ``maintenance.html`` file inside the ``customize``
directory to have a custom maintenance page for scheduled downtime.
After adding, updating, or removing files in ``customization/theme``,
you must recreate the dashboard container using the command above.

Alternatively, you can apply changes without recreating the container
by running:

.. code-block:: shell

docker compose exec dashboard bash -c "python collectstatic.py && uwsgi --reload uwsgi.pid"

Supplying Custom uWSGI configuration
------------------------------------
Expand Down Expand Up @@ -175,6 +184,21 @@ Docker
PATH/TO/YOUR/DEFAULT:/etc/raddb/sites-enabled/default
...

Enabling Maintenance Mode
~~~~~~~~~~~~~~~~~~~~~~~~~

To enable maintenance mode, create a ``maintenance.html`` file in the
``customization/nginx/`` directory:

.. code-block:: shell

customization/nginx/maintenance.html

When this file is present, Nginx will automatically serve it instead of
the application for incoming requests.

To disable maintenance mode, simply remove the file.

Supplying Custom Python Source Code
-----------------------------------

Expand Down
69 changes: 59 additions & 10 deletions images/common/collectstatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,78 @@ def get_pip_freeze_hash():
sys.exit(1)


def run_collectstatic():
def get_dir_shasum(directory_path):
"""Return a sha256 hexdigest of all files (names + contents) under directory_path.

If the directory does not exist, return the hash of empty contents.
"""
if not os.path.exists(directory_path):
return hashlib.sha256(b"").hexdigest()
hasher = hashlib.sha256()
for root, dirs, files in os.walk(directory_path):
dirs.sort()
files.sort()
for fname in files:
fpath = os.path.join(root, fname)
relpath = os.path.relpath(fpath, directory_path)
try:
file_hasher = hashlib.sha256()
with open(fpath, "rb") as fh:
for chunk in iter(lambda: fh.read(4096), b""):
file_hasher.update(chunk)
relpath_bytes = relpath.encode()
hasher.update(len(relpath_bytes).to_bytes(8, "big"))
hasher.update(relpath_bytes)
hasher.update(file_hasher.digest())
except OSError:
# If a file can't be read, skip it but continue hashing others
continue
return hasher.hexdigest()


def run_collectstatic(clear=False):
try:
subprocess.run(
[sys.executable, "manage.py", "collectstatic", "--noinput"], check=True
)
cmd = [sys.executable, "manage.py", "collectstatic", "--noinput"]
if clear:
cmd.append("--clear")
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as e:
print(f"Error running 'collectstatic': {e}", file=sys.stderr)
sys.exit(1)


def main():
if os.environ.get("COLLECTSTATIC_WHEN_DEPS_CHANGE", "true").lower() == "false":
run_collectstatic()
run_collectstatic(clear=True)
return
redis_connection = redis.Redis.from_url(settings.CACHES["default"]["LOCATION"])
current_pip_hash = get_pip_freeze_hash()
current_static_hash = get_dir_shasum(
os.path.join(settings.BASE_DIR, "static_custom")
)
cached_pip_hash = redis_connection.get("pip_freeze_hash")
if not cached_pip_hash or cached_pip_hash.decode() != current_pip_hash:
print("Changes in Python dependencies detected, running collectstatic...")
run_collectstatic()
redis_connection.set("pip_freeze_hash", current_pip_hash)
cached_static_hash = redis_connection.get("static_custom_hash")
pip_changed = not cached_pip_hash or cached_pip_hash.decode() != current_pip_hash
static_changed = (
not cached_static_hash or cached_static_hash.decode() != current_static_hash
)
if pip_changed or static_changed:
print(
"Changes in Python dependencies or static_custom detected,"
" running collectstatic..."
)
run_collectstatic(clear=static_changed)
try:
redis_connection.set("pip_freeze_hash", current_pip_hash)
redis_connection.set("static_custom_hash", current_static_hash)
except Exception:
# If caching fails, don't crash the startup; collectstatic already ran
pass
else:
print("No changes in Python dependencies, skipping collectstatic...")
print(
"No changes in Python dependencies or static_custom,"
" skipping collectstatic..."
)


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions images/common/openwisp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/

STATICFILES_DIRS = [os.path.join(BASE_DIR, "static_custom")]
STATIC_ROOT = os.path.join(BASE_DIR, "static")
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# PRIVATE_STORAGE_ROOT path should be similar to ansible-openwisp2
Expand Down
3 changes: 2 additions & 1 deletion tests/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"username": "admin",
"password": "admin",
"services_max_retries": 25,
"services_delay_retries": 5
"services_delay_retries": 5,
"custom_css_filename": "custom-openwisp-test.css"
}
Loading
Loading