diff --git a/.github/workflows/10min-iiab-test-install.yml b/.github/workflows/10min-iiab-test-install.yml new file mode 100644 index 000000000..d2b8bd056 --- /dev/null +++ b/.github/workflows/10min-iiab-test-install.yml @@ -0,0 +1,58 @@ +name: '"10 min" IIAB on Ubuntu 24.04 on x86-64' +# run-name: ${{ github.actor }} is testing out GitHub Actions πŸš€ + +# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html +on: [push, pull_request, workflow_dispatch] + +# on: +# push: +# +# pull_request: +# +# # Allows you to run this workflow manually from the Actions tab +# workflow_dispatch: +# +# # Set your workflow to run every day of the week from Monday to Friday at 6:00 UTC +# schedule: +# - cron: "0 6 * * 1-5" + +jobs: + test-install: + runs-on: ubuntu-24.04 + steps: + - run: echo "πŸŽ‰ The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "πŸ”Ž The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + #- name: Dump GitHub context (typically almost 500 lines) + # env: + # GITHUB_CONTEXT: ${{ toJSON(github) }} + # run: echo "$GITHUB_CONTEXT" + - name: Check out repository code + uses: actions/checkout@v4 + - run: echo "🍏 This job's status is ${{ job.status }}." + - name: GitHub Actions "runner" environment + run: | + uname -a # uname -srm + whoami # Typically 'runner' instead of 'root' + pwd # /home/runner/work/iiab/iiab == $GITHUB_WORKSPACE == ${{ github.workspace }} + # ls + # ls $GITHUB_WORKSPACE + # ls ${{ github.workspace }} + # ls -la /opt # az, containerd, google, hostedtoolcache, microsoft, mssql-tools, pipx, pipx_bin, post-generation, runner, vsts + # apt update + # apt dist-upgrade -y + # apt autoremove -y + - name: Set up /opt/iiab/iiab + run: | + mkdir /opt/iiab + mv $GITHUB_WORKSPACE /opt/iiab + mkdir $GITHUB_WORKSPACE # OR SUBSEQUENT STEPS WILL FAIL ('working-directory: /opt/iiab/iiab' hacks NOT worth it!) + - name: Set up /etc/iiab/local_vars.yml + run: | + sudo mkdir /etc/iiab + # touch /etc/iiab/local_vars.yml + sudo cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml + - run: sudo /opt/iiab/iiab/scripts/ansible + - run: sudo ./iiab-install + working-directory: /opt/iiab/iiab + - run: iiab-summary + - run: cat /etc/iiab/iiab_state.yml diff --git a/.github/workflows/30min-iiab-test-install-deb12-on-rpi3.yml b/.github/workflows/30min-iiab-test-install-deb12-on-rpi3.yml new file mode 100644 index 000000000..a8703346e --- /dev/null +++ b/.github/workflows/30min-iiab-test-install-deb12-on-rpi3.yml @@ -0,0 +1,65 @@ +name: '"30 min" IIAB on Debian 12 on RPi 3' +# run-name: ${{ github.actor }} is testing out GitHub Actions πŸš€ + +# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html +on: [push, pull_request, workflow_dispatch] + +# on: +# push: +# +# pull_request: +# +# # Allows you to run this workflow manually from the Actions tab +# workflow_dispatch: +# +# # Set your workflow to run every day of the week from Monday to Friday at 6:00 UTC +# schedule: +# - cron: "0 6 * * 1-5" + +jobs: + test-install: + runs-on: ubuntu-22.04 + strategy: + matrix: + arch: [debian12] + include: + - arch: debian12 + cpu: cortex-a7 + cpu_info: cpuinfo/raspberrypi_3b + base_image: https://raspi.debian.net/daily/raspi_3_bookworm.img.xz + # source https://raspi.debian.net/daily-images/ + steps: + #- run: echo "πŸŽ‰ The job was automatically triggered by a ${{ github.event_name }} event." + #- run: echo "πŸ”Ž The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + #- name: Dump GitHub context (typically almost 500 lines) + # env: + # GITHUB_CONTEXT: ${{ toJSON(github) }} + # run: echo "$GITHUB_CONTEXT" + - name: Dump matrix context + env: + MATRIX_CONTEXT: ${{ toJSON(matrix) }} + run: echo "$MATRIX_CONTEXT" + - uses: actions/checkout@v3.1.0 + - uses: pguyot/arm-runner-action@v2 + with: + image_additional_mb: 1024 + base_image: ${{ matrix.base_image }} + cpu: ${{ matrix.cpu }} + cpu_info: ${{ matrix.cpu_info }} + copy_repository_path: /opt/iiab/iiab + commands: | + echo "🍏 This job's status is ${{ job.status }}." + grep Model /proc/cpuinfo + uname -a # uname -srm + whoami # Typically 'root' instead of 'runner' + pwd # /home/runner/work/iiab/iiab == $GITHUB_WORKSPACE == ${{ github.workspace }} + apt-get update -y --allow-releaseinfo-change + apt-get install --no-install-recommends -y git + ls /opt/iiab/iiab + mkdir /etc/iiab + cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml + /opt/iiab/iiab/scripts/ansible + ./iiab-install + cd /opt/iiab/iiab + iiab-summary + cat /etc/iiab/iiab_state.yml diff --git a/.github/workflows/30min-iiab-test-install-raspios-on-zero2w.yml b/.github/workflows/30min-iiab-test-install-raspios-on-zero2w.yml new file mode 100644 index 000000000..9b521fee6 --- /dev/null +++ b/.github/workflows/30min-iiab-test-install-raspios-on-zero2w.yml @@ -0,0 +1,77 @@ +name: '"30 min" IIAB on RasPiOS on Zero 2 W' +# run-name: ${{ github.actor }} is testing out GitHub Actions πŸš€ + +# https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/ci-cd/github-actions/triggers.html +on: [push, pull_request, workflow_dispatch] + +# on: +# push: +# +# pull_request: +# +# # Allows you to run this workflow manually from the Actions tab +# workflow_dispatch: +# +# # Set your workflow to run every day of the week from Monday to Friday at 6:00 UTC +# schedule: +# - cron: "0 6 * * 1-5" + +jobs: + test-install: + runs-on: ubuntu-22.04 + strategy: + matrix: + arch: [aarch64] #[zero_raspbian, zero_raspios, zero2_raspios, aarch64] + include: + #- arch: zero_raspbian + # cpu: arm1176 + # cpu_info: cpuinfo/raspberrypi_zero_w + # base_image: raspbian_lite:latest + #- arch: zero_raspios + # cpu: arm1176 + # cpu_info: cpuinfo/raspberrypi_zero_w + # base_image: raspios_lite:latest + #- arch: zero2_raspios + # cpu: cortex-a7 + # cpu_info: cpuinfo/raspberrypi_zero2_w + # base_image: raspios_lite:latest + - arch: aarch64 + cpu: cortex-a53 + cpu_info: cpuinfo/raspberrypi_zero2_w_arm64 + base_image: raspios_lite_arm64:latest + steps: + #- run: echo "πŸŽ‰ The job was automatically triggered by a ${{ github.event_name }} event." + #- run: echo "πŸ”Ž The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + #- name: Dump GitHub context (typically almost 500 lines) + # env: + # GITHUB_CONTEXT: ${{ toJSON(github) }} + # run: echo "$GITHUB_CONTEXT" + - name: Dump matrix context + env: + MATRIX_CONTEXT: ${{ toJSON(matrix) }} + run: echo "$MATRIX_CONTEXT" + - uses: actions/checkout@v3.1.0 + - uses: pguyot/arm-runner-action@v2 + with: + image_additional_mb: 1024 + base_image: ${{ matrix.base_image }} + cpu: ${{ matrix.cpu }} + cpu_info: ${{ matrix.cpu_info }} + copy_repository_path: /opt/iiab/iiab + commands: | + echo "🍏 This job's status is ${{ job.status }}." + #test `uname -m` = ${{ matrix.arch }} + grep Model /proc/cpuinfo + uname -a # uname -srm + whoami # Typically 'root' instead of 'runner' + pwd # /home/runner/work/iiab/iiab == $GITHUB_WORKSPACE == ${{ github.workspace }} + apt-get update -y --allow-releaseinfo-change + apt-get install --no-install-recommends -y git + ls /opt/iiab/iiab + mkdir /etc/iiab + cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml + /opt/iiab/iiab/scripts/ansible + ./iiab-install + cd /opt/iiab/iiab + iiab-summary + cat /etc/iiab/iiab_state.yml diff --git a/.gitignore b/.gitignore index 38f8427ed..62c1c7bcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,13 @@ -xs-config.spec +# https://git-scm.com/docs/gitignore + build deprecated .ansible *.patches -*.log +*.log *.retry + +# Lines below for emacs, which generates even more tmp files since 2022 *~ +.#* +\#*# diff --git a/.travis.yml b/.travis.yml.unused similarity index 100% rename from .travis.yml rename to .travis.yml.unused diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index caf8b425b..4ddde9b53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ -# SEE THE NEW
[github.com/iiab/iiab/wiki/IIAB-Contributors-Guide](https://github.com/iiab/iiab/wiki/IIAB-Contributors-Guide) +# SEE THE NEW
[github.com/iiab/iiab/wiki/Contributors-Guide-(EN)](https://github.com/iiab/iiab/wiki/Contributors-Guide-(EN)) # THANKS! diff --git a/LICENSING.md b/LICENSING.md index fac901b1d..77c1ed0b9 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -15,6 +15,6 @@ this is to include the following two lines at the top of the file: Licensed under the terms of the GNU GPL v2 or later; see LICENSE for details. All files not containing an explicit copyright notice or terms of license in -the file are Copyright Β© 2015-2021, Unleash Kids, and are licensed under the +the file are Copyright Β© 2015-2025, Unleash Kids, and are licensed under the terms of the GPLv2 license in the file named LICENSE in the root of the repository. diff --git a/README.md b/README.md index 2158149d1..fbfd30d35 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,26 @@ # Internet-in-a-Box (IIAB) -[Internet-in-a-Box (IIAB)](https://internet-in-a-box.org) is a "learning hotspot" that brings the Internet's crown jewels -(Wikipedia in any language, thousands of Khan Academy videos, zoomable OpenStreetMap, electronic books, WordPress journaling, Toys from Trash electronics projects, ETC) to those without Internet. +[Internet-in-a-Box (IIAB)](https://internet-in-a-box.org) is a β€œlearning hotspot” that brings the Internet's crown jewels +(Wikipedia in any language, thousands of Khan Academy videos, zoomable OpenStreetMap, electronic books, WordPress journaling, β€œToys from Trash” electronics projects, ETC) to those without Internet. You can build your own tiny, affordable server (an offline digital library) for your school, your medical clinic, your prison, your region and/or your very own family β€” accessible with any nearby smartphone, tablet or laptop. Internet-in-a-Box gives you the DIY tools to: 1. Download then drag-and-drop to arrange the [very best of the World’s Free Knowledge](https://internet-in-a-box.org/#quality-content). -2. Choose among [30+ powerful educational apps](http://FAQ.IIAB.IO#What_services_.28IIAB_apps.29_are_suggested_during_installation.3F) for your school or learning/teaching community, optionally with a complete LMS (learning management system). +2. Choose among [30+ powerful educational apps](https://wiki.iiab.io/go/FAQ#What_services_%28IIAB_apps%29_are_suggested_during_installation%3F) for your school or learning/teaching community, optionally with a complete LMS (learning management system). 3. Exchange local/indigenous knowledge with nearby communities, using our [Manage Content](https://github.com/iiab/iiab-admin-console/blob/master/roles/console/files/help/InstContent.rst#manage-content) interface and possible mesh networking. -FYI this [community product](https://en.wikipedia.org/wiki/Internet-in-a-Box) is enabled by professional volunteers working [side-by-side](http://FAQ.IIAB.IO#What_are_the_best_places_for_community_support.3F) with schools, clinics and libraries around the world. *Thank you for being a part of our http://OFF.NETWORK grassroots technology [movement](https://meta.wikimedia.org/wiki/Internet-in-a-Box)!* +FYI this [community product](https://en.wikipedia.org/wiki/Internet-in-a-Box) is enabled by professional volunteers working [side-by-side](https://wiki.iiab.io/go/FAQ#What_are_the_best_places_for_community_support%3F) with schools, clinics and libraries around the world. *Thank you for being a part of our http://OFF.NETWORK grassroots technology [movement](https://meta.wikimedia.org/wiki/Internet-in-a-Box)!* ## Installation -Install Internet-in-a-Box (IIAB) from [download.iiab.io](https://download.iiab.io/) +Install Internet-in-a-Box (IIAB) from: [**download.iiab.io**](https://download.iiab.io/) -Please see [FAQ.IIAB.IO](http://FAQ.IIAB.IO) which has 40+ questions and answers to help you along the way, as you put together the "local learning hotspot" most suitable for your own teaching/learning community. Here are 2 ways to install IIAB: +Please see [FAQ.IIAB.IO](https://wiki.iiab.io/go/FAQ) which has 50+ questions and answers to help you along the way (e.g. [β€œIs a quick installation possible?”](https://wiki.iiab.io/go/FAQ#Is_a_quick_installation_possible%3F)) as you put together the β€œlocal learning hotspot” most suitable for your own teaching/learning community. Here are 2 ways to install IIAB: - Our [1-line installer](https://download.iiab.io/) gets you the very latest, typically within about an hour, on [different Linux distributions](https://github.com/iiab/iiab/wiki/IIAB-Platforms#operating-systems). -- [Prefab disk images](https://github.com/iiab/iiab/wiki/Raspberry-Pi-Images:-Summary) ([.img files](https://archive.org/search.php?query=iiab%20.img&sort=-publicdate)) are sometimes a few months out of date, but can be flashed directly onto a microSD card, for insertion into Raspberry Pi. +- [Prefab disk images](https://github.com/iiab/iiab/wiki/Raspberry-Pi-Images-~-Summary#iiab-images-for-raspberry-pi) ([.img files](https://archive.org/search.php?query=iiab%20.img&sort=-publicdate)) are sometimes a few months out of date, but can be flashed directly onto a microSD card, for insertion into Raspberry Pi. Our [HOW-TO videos](https://www.youtube.com/channel/UC0cBGCxr_WPBPa3IqPVEe3g) can be very helpful and the [Installation](https://github.com/iiab/iiab/wiki/IIAB-Installation) wiki page has more intricate details e.g. if you're trying to install Internet-in-a-Box (IIAB) onto a [another Linux](https://github.com/iiab/iiab/wiki/IIAB-Platforms) that has not yet been tried. @@ -29,20 +29,22 @@ See our [Tech Docs Wiki](https://github.com/iiab/iiab/wiki) for more about the u After you've installed the software, you should [add content](https://github.com/iiab/iiab/wiki/IIAB-Installation#add-content), which can of course take time when downloading multi-gigabyte Content Packs! -Finally, you can [customize your Internet-in-a-Box home page](http://FAQ.IIAB.IO#How_do_I_customize_my_Internet-in-a-Box_home_page.3F) (typically http://box or http://box.lan) using our **drag-and-drop** Admin Console (http://box.lan/admin) — to arrange Content Packs and IIAB Apps (services) for your local community's needs. +Finally, you can [customize your Internet-in-a-Box home page](https://wiki.iiab.io/go/FAQ#How_do_I_customize_my_Internet-in-a-Box_home_page%3F) (typically http://box or http://box.lan) using our **drag-and-drop** Admin Console (http://box.lan/admin) — to arrange Content Packs and IIAB Apps (services) for your local community's needs. ## Community -Internet-in-a-Box (IIAB) greatly welcomes contributions from educators, librarians and [IT/UX/QA people](https://github.com/iiab/iiab/wiki/Technical-Contributors-Guide) of all kinds! +Global community updates and videos are regularly posted to: **[@internet_in_box](https://twitter.com/internet_in_box)** -If you would like to volunteer, please [make contact](https://internet-in-a-box.org/pages/contributing.html) after looking over "[How can I help?](http://FAQ.IIAB.IO#How_can_I_help.3F)" at: [FAQ.IIAB.IO](http://FAQ.IIAB.IO) +_Internet-in-a-Box (IIAB) greatly welcomes contributions from educators, librarians and [IT/UX/QA people](https://github.com/iiab/iiab/wiki/Contributors-Guide-(EN)) ([versiΓ³n en espaΓ±ol](https://github.com/iiab/iiab/wiki/Gu%C3%ADa-para-Contribuidores-(ES))) of all kinds!_ + +If you would like to volunteer, please [make contact](https://internet-in-a-box.org/contributing.html) after looking over [β€œHow can I help?”](https://wiki.iiab.io/go/FAQ#How_can_I_help%3F) at: [FAQ.IIAB.IO](https://wiki.iiab.io/go/FAQ) -To learn more about our open community architecture for "offline" learning, check out "[What technical documentation exists?](http://FAQ.IIAB.IO#What_technical_documentation_exists.3F)" -FYI we use [Ansible](http://FAQ.IIAB.IO#What_is_Ansible_and_what_version_should_I_use.3F) to install, deploy, configure and manage the various software components. +To learn more about our open community architecture for β€œoffline” learning, check out [β€œWhat technical documentation exists?”](https://wiki.iiab.io/go/FAQ#What_technical_documentation_exists%3F) +FYI we use [Ansible](https://wiki.iiab.io/go/FAQ#What_is_Ansible_and_what_version_should_I_use%3F) to install, deploy, configure and manage the various software components. -*Thank you for helping us enable offline access to the Internet's free/open knowledge jewels, as well as "Sneakernet-of-Alexandria" distribution of local/indigenous content, when mass media channels do not serve grassroots voices.* +*Thank you for helping us enable offline access to the Internet's free/open knowledge jewels, as well as β€œSneakernet-of-Alexandria” distribution of local/indigenous content, when mass media channels do not serve grassroots voices.* ## Versions @@ -52,4 +54,4 @@ Install our latest pre-release using the 1-line installer at: [**download.iiab.i You can also consider earlier official releases at: [github.com/iiab/iiab/releases](https://github.com/iiab/iiab/releases) -For much older versions, see: [github.com/xsce](http://github.com/xsce), [schoolserver.org](http://schoolserver.org) +For much older versions, see: [github.com/xsce](https://github.com/xsce), [schoolserver.org](http://schoolserver.org) diff --git a/ansible.cfg b/ansible.cfg index 4030a931e..deb5328ed 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -5,4 +5,4 @@ # Disallowed by Ansible 2.11+ -- see https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_2.7.html#using-a-loop-on-a-package-module-via-squash-actions #squash_actions = apk, apt, dnf, homebrew, openbsd_pkg, pacman, pkgng, yum, zypper, package [defaults] -interpreter_python=/usr/bin/python3 +interpreter_python=/usr/local/ansible/bin/python3 diff --git a/iiab-from-cmdline.yml b/iiab-from-cmdline.yml index 74b507b56..68956b3ad 100644 --- a/iiab-from-cmdline.yml +++ b/iiab-from-cmdline.yml @@ -3,10 +3,10 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml - - /etc/iiab/iiab_state.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml + - /etc/iiab/iiab_state.yml roles: - { role: 0-init } diff --git a/iiab-from-console.yml b/iiab-from-console.yml index e83aefdb9..fb8282580 100644 --- a/iiab-from-console.yml +++ b/iiab-from-console.yml @@ -3,10 +3,10 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml - - /etc/iiab/iiab_state.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml + - /etc/iiab/iiab_state.yml roles: - { role: 0-init } diff --git a/iiab-install b/iiab-install index 037d61b24..45e637c2a 100755 --- a/iiab-install +++ b/iiab-install @@ -1,17 +1,57 @@ #!/bin/bash -e # Running from a git repo # Add cmdline options for passing to ansible -# Todo add proper shift to gobble up --debug --reinstall PLAYBOOK=iiab-stages.yml INVENTORY=ansible_hosts IIAB_STATE_FILE=/etc/iiab/iiab_state.yml -ARGS="" +ARGS="--extra-vars {" # Needs boolean not string so use JSON list. bash forces {...} to '{...}' for Ansible + CWD=`pwd` OS=`grep ^ID= /etc/os-release | cut -d= -f2` -OS=${OS//\"/} -MIN_RPI_KERN=5.4.0 # Do not use 'rpi-update' unless absolutely necessary: https://github.com/iiab/iiab/issues/1993 -MIN_ANSIBLE_VER=2.11.6 # Ansible 2.8.3 and 2.8.6 had serious bugs, preventing their use with IIAB. +OS=${OS//\"/} # Remove all '"' +MIN_RPI_KERN=5.4.0 # Do not use 'rpi-update' unless absolutely necessary: https://github.com/iiab/iiab/issues/1993 +MIN_ANSIBLE_VER=2.16.14 # 2024-11-08: ansible-core 2.15 EOL is November 2024 per https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix 2022-11-09: Raspberry Pi 3 (and 3 B+ etc?) apparently install (and require?) ansible-core 2.11 for now -- @deldesir can explain more on PR #3419. Historical: Ansible 2.8.3 and 2.8.6 had serious bugs, preventing their use with IIAB. + +REINSTALL=false +DEBUG=false +SKIP_ROLE_ON_ERROR=false + +usage() { + echo -e "\n\e[1mUse './iiab-install' for regular installs, or to continue an install." + echo -e "Use './iiab-install --risky' to force 'skip_role_on_error: True'" + echo -e "Use './iiab-install --reinstall' to force running all Stages 0-9, followed by the Network Role." + echo -e "Use './iiab-install --debug' to run Stage 0, followed by Stages 3-9, followed by the Network Role." + echo -e "Use './iiab-configure' to run Stage 0, followed by Stages 4-9." + echo -e "Use './runrole' to run Stage 0, followed by a single Stage or Role." + echo -e "Use './iiab-network' to run Stage 0, followed by the Network Role.\e[0m\n" +} + +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash/14203146#14203146 +while [[ $# -gt 0 ]]; do + case $1 in + --reinstall) + REINSTALL=true + shift + ;; + --debug) + DEBUG=true + shift + ;; + -r|--risky) + SKIP_ROLE_ON_ERROR=true + shift + ;; + *) + usage + exit 1 + ;; + esac +done + +ARGS="$ARGS\"skip_role_on_error\":$SKIP_ROLE_ON_ERROR" # Needs boolean not +# string so use JSON list. Ansible permits these boolean values: (refresher) +# https://github.com/iiab/iiab/blob/master/roles/0-init/tasks/validate_vars.yml#L19-L43 if [ ! -f /etc/iiab/local_vars.yml ]; then @@ -25,13 +65,13 @@ if [ ! -f /etc/iiab/local_vars.yml ]; then echo -e "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ\n" >&2 fi - echo -e "\nEXITING: /opt/iiab/iiab/iiab-install REQUIRES /etc/iiab/local_vars.yml\n" >&2 + echo -e "\n\e[1mEXITING: /opt/iiab/iiab/iiab-install REQUIRES /etc/iiab/local_vars.yml\e[0m\n" >&2 - echo -e "(1) Please read http://wiki.laptop.org/go/IIAB/local_vars.yml to learn more" >&2 - echo -e "(2) MIN/MEDIUM/BIG samples are included in /opt/iiab/iiab/vars" >&2 + echo -e "(1) See http://FAQ.IIAB.IO -> What is local_vars.yml and how do I customize it?" >&2 + echo -e "(2) SMALL/MEDIUM/LARGE samples are included in /opt/iiab/iiab/vars" >&2 echo -e "(3) NO TIME FOR DETAILS? RUN INTERNET-IN-A-BOX'S FRIENDLY 1-LINE INSTALLER:\n" >&2 - echo -e ' http://download.iiab.io\n' >&2 + echo -e ' https://download.iiab.io\n' >&2 exit 1 fi @@ -42,14 +82,15 @@ fi echo -e "\n\n./iiab-install $* BEGUN IN $CWD\n" echo -e "local_facts.fact DIAGNOSTICS... (A FEW LINES OF ERRORS/WARNINGS BELOW ARE OK!)\n" - scripts/local_facts.fact # Exit & advise, if OS not supported. -if [ ! -f /etc/ansible/facts.d/local_facts.fact ]; then - mkdir -p /etc/ansible/facts.d -fi +mkdir -p /etc/ansible/facts.d cp scripts/local_facts.fact /etc/ansible/facts.d/local_facts.fact -echo -e "\nPlaced /etc/ansible/facts.d/local_facts.fact into position." +echo -e "\nPlaced /etc/ansible/facts.d/local_facts.fact into position.\n" + +mkdir -p /etc/iiab/install-flags # MANDATORY since 2022-07-22 +echo -e "/etc/iiab/install-flags directory created/verified." +echo -e "(e.g. for PR #3318 netwarn pop-ups, asking you to run iiab-network)\n" if [ ! -f $PLAYBOOK ]; then echo "EXITING: IIAB Playbook ""$PLAYBOOK"" not found." @@ -57,16 +98,6 @@ if [ ! -f $PLAYBOOK ]; then exit 1 fi -if [ "$1" != "--debug" ] && [ "$1" != "--reinstall" ] && [ "$1" != "" ]; then - echo "Use './iiab-install' for regular installs, or to continue an install." - echo "Use './iiab-install --reinstall' to force running all Stages 0-9, followed by the Network Role." - echo "Use './iiab-install --debug' to run Stage 0, followed by Stages 3-9, followed by the Network Role." - echo "Use './iiab-configure' to run Stage 0, followed by Stages 4-9." - echo "Use './runrole' to run Stage 0, followed by a single Stage or Role." - echo "Use './iiab-network' to run Stage 0, followed by the Network Role." - exit 1 -fi - # Subroutine compares software version numbers. Generates rare false positives # like "1.0 > 1" and "2.4.0 > 2.4". Avoid risks by structuring conditionals w/ # a consistent # of decimal points e.g. "if version_gt w.x.y.z a.b.c.d; then" @@ -93,7 +124,7 @@ CURR_ANSIBLE_VER=0 #if [[ $(command -v ansible) ]]; then # Also Works! $(...) nests more easily than backticks #if [[ `which ansible` ]]; then # "which" misses built-in commands like cd, and is RISKY per https://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script #if [[ `type -P ansible` ]]; then # "type -P" isn't POSIX compliant; it misses built-in commands like "cd" -if [[ `command -v ansible` ]]; then # "command -v" is POSIX compliant; it catches built-in commands like "cd" +if [[ $(command -v ansible) ]]; then # "command -v" is POSIX compliant; it catches built-in commands like "cd" CURR_ANSIBLE_VER=$(ansible --version | head -1 | cut -f 2- -d " " | sed 's/.* \([^ ]*\)\].*/\1/') # Above works with 'ansible [core 2.11.0rc2]' -- these old ways do not: #CURR_ANSIBLE_VER=$(ansible --version | head -1 | awk '{print $2}') @@ -125,41 +156,38 @@ if [ -f /etc/iiab/iiab.env ]; then fi fi - if [ "$1" == "--reinstall" ]; then + if $($REINSTALL); then STAGE=0 - ARGS="$ARGS"" --extra-vars reinstall=True" + #ARGS="$ARGS"" --extra-vars reinstall=True" + ARGS="$ARGS,\"reinstall\":True" # Needs boolean not string so use JSON list sed -i 's/^STAGE=.*/STAGE=0/' /etc/iiab/iiab.env echo "Wrote STAGE=0 (counter) to /etc/iiab/iiab.env" - elif [ "$STAGE" -ge 2 ] && [ "$1" == "--debug" ]; then + elif [ "$STAGE" -ge 2 ] && $($DEBUG); then STAGE=2 sed -i 's/^STAGE=.*/STAGE=2/' /etc/iiab/iiab.env echo "Wrote STAGE=2 (counter) to /etc/iiab/iiab.env" elif [ "$STAGE" -eq 9 ]; then - echo -e "\nEXITING: STAGE (counter) in /etc/iiab/iiab.env shows Stage 9 Is Already Done." - echo -e "Use './iiab-install --reinstall' to force running all Stages 0-9, followed by the Network Role." - echo -e "Use './iiab-install --debug' to run Stage 0, followed by Stages 3-9, followed by the Network Role." - echo -e "Use './iiab-configure' to run Stage 0, followed by Stages 4-9." - echo -e "Use './runrole' to run Stage 0, followed by a single Stage or Role." - echo -e "Use './iiab-network' to run Stage 0, followed by the Network Role.\n\n" - - exit 0 # Allows rerunning http://download.iiab.io/install.txt + echo -e "\n\e[1mEXITING: STAGE (counter) in /etc/iiab/iiab.env shows Stage 9 Is Already Done.\e[0m" + usage + exit 0 # Allows rerunning https://download.iiab.io/install.txt fi fi -if [ "$STAGE" -lt 2 ] && [ "$1" == "--debug" ]; then +if [ "$STAGE" -lt 2 ] && $($DEBUG); then echo -e "\n'--debug' *ignored* as STAGE (counter) < 2." fi # /etc/iiab/iiab_state.yml is mandatory and must be created here. Background: # Allow iiab-install to read IIAB_STATE_FILE to not repeat installs of previous # roles that already completed within the stage. -if [ ! -f $IIAB_STATE_FILE ]; then - #touch $IIAB_STATE_FILE +if [ ! -f $IIAB_STATE_FILE ]; then # touch $IIAB_STATE_FILE + echo -e "\nCreating... $IIAB_STATE_FILE" cat > $IIAB_STATE_FILE << EOF # DO *NOT* MANUALLY EDIT THIS, THANKS! # IIAB does NOT currently support uninstalling apps/services. EOF fi + echo -e "\nTRY TO RERUN './iiab-install' IF IT FAILS DUE TO CONNECTIVITY ISSUES ETC!\n" echo -e "\e[1mRunning local Ansible playbooks...\n...Stage 0 will now run\n...followed by Stages $(($STAGE + 1))-9\n...and then the Network Role.\e[0m\n" @@ -168,6 +196,8 @@ export ANSIBLE_LOG_PATH="$CWD""/iiab-install.log" ansible -m setup -i $INVENTORY localhost --connection=local | grep python ansible -m setup -i $INVENTORY localhost --connection=local >> /dev/null # So vars are recorded in /opt/iiab/iiab/iiab-install.log -ansible-playbook -i $INVENTORY $PLAYBOOK ${ARGS} --connection=local +ARGS="$ARGS}" +echo -e "\nNOW RUN: ansible-playbook -i $INVENTORY $PLAYBOOK $ARGS --connection=local\n" +ansible-playbook -i $INVENTORY $PLAYBOOK $ARGS --connection=local echo -e "./iiab-install $* COMPLETED IN $CWD\n\n" diff --git a/iiab-network b/iiab-network index 6ff4b5cd3..c888c27bf 100755 --- a/iiab-network +++ b/iiab-network @@ -4,11 +4,14 @@ CWD=`pwd` export ANSIBLE_LOG_PATH="$CWD/iiab-network.log" -if [ ! -f iiab-network.yml ]; then - echo "iiab-network.yml not found in current directory." - echo "Please rerun this command from the top level of the git repo." - echo "Exiting." +exit_error() { + echo -e "\nEXITING: "$@ | tee -a /opt/iiab/iiab/iiab-network.log exit 1 +} + +if [ ! -f iiab-network.yml ]; then + exit_error "iiab-network.yml not found in current directory." \ + "Please rerun this command from the top level of the git repo." fi OS="unknown" # will be overridden below, if /etc/iiab/iiab.env is legit @@ -19,32 +22,27 @@ if [ -f /etc/iiab/iiab.env ]; then if grep -q STAGE= /etc/iiab/iiab.env ; then echo -e "\nExtracted STAGE=$STAGE (counter) from /etc/iiab/iiab.env" if ! [ "$STAGE" -eq "$STAGE" ] 2> /dev/null; then - echo -e "\nEXITING: STAGE (counter) value == ""$STAGE"" is non-integer" - exit 1 + exit_error "STAGE (counter) value == ""$STAGE"" is non-integer" elif [ "$STAGE" -lt 0 ] || [ "$STAGE" -gt 9 ]; then - echo -e "\nEXITING: STAGE (counter) value == ""$STAGE"" is out-of-range" - exit 1 + exit_error "STAGE (counter) value == ""$STAGE"" is out-of-range" elif [ "$STAGE" -lt 3 ]; then - echo -e "\nEXITING: STAGE (counter) value == ""$STAGE" - echo -e "\nIIAB Stage 3 not complete." - echo -e "\nPlease run: ./iiab-install" - exit 1 + exit_error "STAGE (counter) value == ""$STAGE" \ + "\nIIAB Stage 3 not complete." \ + "\nPlease run: ./iiab-install" fi else - echo -e "\nEXITING: STAGE (counter) not found" - echo -e "\nIIAB not installed." - echo -e "\nPlease run: ./iiab-install" - exit 1 + exit_error "STAGE (counter) not found" \ + "\nIIAB not installed." \ + "\nPlease run: ./iiab-install" fi else - echo -e "\nEXITING: /etc/iiab/iiab.env not found" - exit 1 + exit_error "/etc/iiab/iiab.env not found" fi echo "Ansible will now run iiab-network.yml -- log file is iiab-network.log" Start=`date` ansible -m setup -i ansible_hosts localhost --connection=local | grep python -ansible-playbook -i ansible_hosts iiab-network.yml --connection=local +ansible-playbook -i ansible_hosts iiab-network.yml --extra-vars "{\"skip_role_on_error\":false}" --connection=local End=`date` @@ -94,3 +92,4 @@ echo "iiab-network run start: $Start" echo "iiab-network run end: $End" echo echo "Please REBOOT to fully verify your network -- graphical desktops MUST reboot!" +exit 0 diff --git a/iiab-network.yml b/iiab-network.yml index a72678367..2725a78c5 100644 --- a/iiab-network.yml +++ b/iiab-network.yml @@ -3,10 +3,10 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml - - /etc/iiab/iiab_state.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml + - /etc/iiab/iiab_state.yml roles: - { role: 0-init } diff --git a/iiab-setup b/iiab-setup new file mode 100755 index 000000000..359967bc2 --- /dev/null +++ b/iiab-setup @@ -0,0 +1,20 @@ +#!/bin/bash -e +# Running from a git repo +# Assumes iiab repos are downloaded + +apt -y update +apt -y full-upgrade + +apt -y install git curl nano gawk wget pastebinit + +cd /opt/iiab/iiab +scripts/ansible + +# 2022-09-27: iiab-install now handles this +#mkdir -p /etc/iiab/install-flags + +if [ ! -f /etc/iiab/local_vars.yml ]; then + cp /opt/iiab/iiab/vars/local_vars_none.yml /etc/iiab/local_vars.yml +fi + +reboot diff --git a/iiab-stages.yml b/iiab-stages.yml index 4b0940db6..32a6ca751 100644 --- a/iiab-stages.yml +++ b/iiab-stages.yml @@ -3,11 +3,11 @@ become: yes vars_files: - - roles/0-init/defaults/main.yml - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml - - /etc/iiab/iiab_state.yml + - roles/0-init/defaults/main.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml + - /etc/iiab/iiab_state.yml tasks: diff --git a/install-support.yml b/install-support.yml.unused similarity index 51% rename from install-support.yml rename to install-support.yml.unused index f8e6802f6..f2835214d 100644 --- a/install-support.yml +++ b/install-support.yml.unused @@ -2,9 +2,9 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml roles: - { role: 0-init } diff --git a/roles/0-DEPRECATED-ROLES/httpd/defaults/main.yml b/roles/0-DEPRECATED-ROLES/httpd/defaults/main.yml index f728ffca8..a28c2da61 100644 --- a/roles/0-DEPRECATED-ROLES/httpd/defaults/main.yml +++ b/roles/0-DEPRECATED-ROLES/httpd/defaults/main.yml @@ -8,7 +8,7 @@ # apache_interface: 127.0.0.1 # Make this False to disable http://box/common/services/power_off.php button: -# apache_allow_sudo: True +# allow_www_data_poweroff: False # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! diff --git a/roles/openvpn/defaults/main.yml b/roles/0-DEPRECATED-ROLES/openvpn/defaults/main.yml similarity index 62% rename from roles/openvpn/defaults/main.yml rename to roles/0-DEPRECATED-ROLES/openvpn/defaults/main.yml index adc23ec2b..136e01f5d 100644 --- a/roles/openvpn/defaults/main.yml +++ b/roles/0-DEPRECATED-ROLES/openvpn/defaults/main.yml @@ -1,13 +1,17 @@ +# SECURITY WARNING: https://wiki.iiab.io/go/Security + # openvpn_install: True # openvpn_enabled: False -# For /etc/iiab/openvpn_handle +# Empty string on purpose since ~2016, for /etc/iiab/uuid +# SEE https://github.com/iiab/iiab/blob/master/roles/openvpn/tasks/main.yml#L5-L20 # openvpn_handle: "" # cron seems necessary on CentOS: # openvpn_cron_enabled: False # openvpn_server: xscenet.net +# openvpn_server_real_ip: 3.89.148.185 # openvpn_server_virtual_ip: 10.8.0.1 # openvpn_server_port: 1194 diff --git a/roles/openvpn/tasks/enable-or-disable.yml b/roles/0-DEPRECATED-ROLES/openvpn/tasks/enable-or-disable.yml similarity index 100% rename from roles/openvpn/tasks/enable-or-disable.yml rename to roles/0-DEPRECATED-ROLES/openvpn/tasks/enable-or-disable.yml diff --git a/roles/openvpn/tasks/install.yml b/roles/0-DEPRECATED-ROLES/openvpn/tasks/install.yml similarity index 92% rename from roles/openvpn/tasks/install.yml rename to roles/0-DEPRECATED-ROLES/openvpn/tasks/install.yml index cbe2e36af..53f5dc7f2 100644 --- a/roles/openvpn/tasks/install.yml +++ b/roles/0-DEPRECATED-ROLES/openvpn/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Install packages: ncat, nmap, openvpn, sudo" package: name: @@ -100,6 +105,17 @@ # RECORD OpenVPN AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'openvpn_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: openvpn + option: openvpn_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'openvpn_installed: True'" set_fact: openvpn_installed: True diff --git a/roles/openvpn/tasks/main.yml b/roles/0-DEPRECATED-ROLES/openvpn/tasks/main.yml similarity index 76% rename from roles/openvpn/tasks/main.yml rename to roles/0-DEPRECATED-ROLES/openvpn/tasks/main.yml index 8c8577767..6e71e6374 100644 --- a/roles/openvpn/tasks/main.yml +++ b/roles/0-DEPRECATED-ROLES/openvpn/tasks/main.yml @@ -56,21 +56,21 @@ option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: - - option: name - value: OpenVPN - - option: description - value: '"OpenVPN enables live/remote support by connecting machines anywhere on the Internet, via a middleman server, using Virtual Private Network (VPN) techniques to create secure connections."' - - option: openvpn_install - value: "{{ openvpn_install }}" - - option: openvpn_enabled - value: "{{ openvpn_enabled }}" - - option: openvpn_handle - value: "{{ openvpn_handle }}" - - option: openvpn_cron_enabled - value: "{{ openvpn_cron_enabled }}" - - option: openvpn_server - value: "{{ openvpn_server }}" - - option: openvpn_server_virtual_ip - value: "{{ openvpn_server_virtual_ip }}" - - option: openvpn_server_port - value: "{{ openvpn_server_port }}" + - option: name + value: OpenVPN + - option: description + value: '"OpenVPN enables live/remote support by connecting machines anywhere on the Internet, via a middleman server, using Virtual Private Network (VPN) techniques to create secure connections."' + - option: openvpn_install + value: "{{ openvpn_install }}" + - option: openvpn_enabled + value: "{{ openvpn_enabled }}" + - option: openvpn_handle + value: "{{ openvpn_handle }}" + - option: openvpn_cron_enabled + value: "{{ openvpn_cron_enabled }}" + - option: openvpn_server + value: "{{ openvpn_server }}" + - option: openvpn_server_virtual_ip + value: "{{ openvpn_server_virtual_ip }}" + - option: openvpn_server_port + value: "{{ openvpn_server_port }}" diff --git a/roles/openvpn/templates/15-openvpn.unused b/roles/0-DEPRECATED-ROLES/openvpn/templates/15-openvpn.unused similarity index 100% rename from roles/openvpn/templates/15-openvpn.unused rename to roles/0-DEPRECATED-ROLES/openvpn/templates/15-openvpn.unused diff --git a/roles/openvpn/templates/announce b/roles/0-DEPRECATED-ROLES/openvpn/templates/announce similarity index 100% rename from roles/openvpn/templates/announce rename to roles/0-DEPRECATED-ROLES/openvpn/templates/announce diff --git a/roles/openvpn/templates/announcer b/roles/0-DEPRECATED-ROLES/openvpn/templates/announcer similarity index 100% rename from roles/openvpn/templates/announcer rename to roles/0-DEPRECATED-ROLES/openvpn/templates/announcer diff --git a/roles/openvpn/templates/ca.crt b/roles/0-DEPRECATED-ROLES/openvpn/templates/ca.crt similarity index 100% rename from roles/openvpn/templates/ca.crt rename to roles/0-DEPRECATED-ROLES/openvpn/templates/ca.crt diff --git a/roles/openvpn/templates/client1.crt b/roles/0-DEPRECATED-ROLES/openvpn/templates/client1.crt similarity index 100% rename from roles/openvpn/templates/client1.crt rename to roles/0-DEPRECATED-ROLES/openvpn/templates/client1.crt diff --git a/roles/openvpn/templates/client1.key b/roles/0-DEPRECATED-ROLES/openvpn/templates/client1.key similarity index 100% rename from roles/openvpn/templates/client1.key rename to roles/0-DEPRECATED-ROLES/openvpn/templates/client1.key diff --git a/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-remote-off b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-remote-off new file mode 100755 index 000000000..6d5003b78 --- /dev/null +++ b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-remote-off @@ -0,0 +1,39 @@ +#!/bin/bash + +# /usr/bin/iiab-remote-off should fully turn off multiple remote support +# services like OpenVPN and others, to reduce risk of remote attacks. + +# echo -e '\nWARNING: To disable OpenVPN long-term, it'"'"'s recommended you:\n' +# +# echo -e '1) Set this variable in /etc/iiab/local_vars.yml' +# echo -e ' openvpn_enabled: False\n' +# +# echo -e '2) Run:' +# echo -e ' cd /opt/iiab/iiab' +# echo -e ' sudo ./runrole openvpn\n' + +# Do nothing if OpenVPN not installed +which openvpn +if [ $? -ne 0 ]; then + echo 'Cannot find the OpenVPN program (openvpn).' + exit 1 +fi + +if grep -q '^openvpn_enabled:' /etc/iiab/local_vars.yml; then + sed -i "s/^openvpn_enabled:.*/openvpn_enabled: False/" /etc/iiab/local_vars.yml +else + echo "openvpn_enabled: False" >> /etc/iiab/local_vars.yml +fi + +systemctl disable openvpn +systemctl stop openvpn + +sleep 5 +ps -e | grep openvpn # 2018-09-05: "ps -e | grep vpn" no longer works (nor would "pgrep vpn") when invoked from iiab-vpn-off (as filename itself causes [multiple] "vpn" instances to appear in process list!) +if [ $? -eq 0 ]; then + echo "OpenVPN failed to stop." +else + echo "OpenVPN's systemd service was successfully stopped and disabled." + echo + echo "Also, 'openvpn_enabled: False' was set in /etc/iiab/local_vars.yml" +fi diff --git a/roles/openvpn/templates/iiab-remote-on.j2 b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-remote-on.j2 similarity index 100% rename from roles/openvpn/templates/iiab-remote-on.j2 rename to roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-remote-on.j2 diff --git a/roles/openvpn/templates/iiab-support b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support similarity index 98% rename from roles/openvpn/templates/iiab-support rename to roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support index 352ad1677..1d88a66b4 100755 --- a/roles/openvpn/templates/iiab-support +++ b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support @@ -10,11 +10,11 @@ DEBUG=false # Using /usr/bin/true or /usr/bin/false PLAYBOOK="install-support.yml" INVENTORY="ansible_hosts" -# 2021-08-18: bash scripts using default_vars.yml &/or local_vars.yml +# 2023-02-25: bash scripts using default_vars.yml &/or local_vars.yml # https://github.com/iiab/iiab-factory/blob/master/iiab -# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L13 +# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L10-14 # https://github.com/iiab/iiab/blob/master/roles/network/templates/gateway/iiab-gen-iptables#L48-L52 -# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L25-L34 +# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L23-L39 # https://github.com/iiab/iiab/blob/master/roles/openvpn/templates/iiab-support READS AND WRITES, INCL NON-BOOLEAN # PARSE local_vars.yml JUST AS Ansible & /etc/openvpn/scripts/announcer DO: diff --git a/roles/openvpn/templates/iiab-support.older b/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support.older similarity index 100% rename from roles/openvpn/templates/iiab-support.older rename to roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support.older diff --git a/roles/openvpn/templates/openvpn_handle.j2.unused b/roles/0-DEPRECATED-ROLES/openvpn/templates/openvpn_handle.j2.unused similarity index 100% rename from roles/openvpn/templates/openvpn_handle.j2.unused rename to roles/0-DEPRECATED-ROLES/openvpn/templates/openvpn_handle.j2.unused diff --git a/roles/openvpn/templates/silence b/roles/0-DEPRECATED-ROLES/openvpn/templates/silence similarity index 100% rename from roles/openvpn/templates/silence rename to roles/0-DEPRECATED-ROLES/openvpn/templates/silence diff --git a/roles/openvpn/templates/xscenet.conf.j2 b/roles/0-DEPRECATED-ROLES/openvpn/templates/xscenet.conf.j2 similarity index 100% rename from roles/openvpn/templates/xscenet.conf.j2 rename to roles/0-DEPRECATED-ROLES/openvpn/templates/xscenet.conf.j2 diff --git a/roles/0-init/defaults/main.yml b/roles/0-init/defaults/main.yml index 95cca916b..a07cde5cf 100644 --- a/roles/0-init/defaults/main.yml +++ b/roles/0-init/defaults/main.yml @@ -23,14 +23,6 @@ # ...after it is set in 0-init/tasks/main.yml first_run: False rpi_model: none # 2021-07-30: Broadly used! -#xo_model: none # 2021-07-30: No longer used -# 2021-07-30: Recorded to /etc/iiab/iiab.ini but not used programmatically: -gw_active: False -# 2021-07-30: Broadly used, but not in an organized way -- most all IIAB -# outfitting/provisioning happens online -- in situations where connectivity -# failures should be reported to the operator, rather than papered over: -internet_available: False -discovered_wan_iface: none # 2021-07-30: Very broadly used! # 2021-07-30: Barely used -- for {named, dhcpd, squid} in # roles/network/tasks/main.yml -- after being set in 0-init/tasks/network.yml diff --git a/roles/0-init/tasks/create_iiab_ini.yml b/roles/0-init/tasks/create_iiab_ini.yml index d29f791c8..75b2b338f 100644 --- a/roles/0-init/tasks/create_iiab_ini.yml +++ b/roles/0-init/tasks/create_iiab_ini.yml @@ -1,13 +1,26 @@ -# workaround for fact that auto create does not work on iiab_ini_file (/etc/iiab/iiab.ini) +- name: Record disk_used_a_priori (permanently, into {{ iiab_ini_file }} below) to later estimate iiab_software_disk_usage + shell: df -B1 --output=used / | tail -1 + register: df1 + +# workaround for fact that auto create does not work on iiab_ini_file - name: Create {{ iiab_ini_file }} file: - path: "{{ iiab_ini_file }}" + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini state: touch -- name: Add 'location' variable values to {{ iiab_ini_file }} +- name: Run command 'dpkg --print-architecture' to identify OS architecture (CPU arch as revealed by ansible_architecture ~= ansible_machine is NOT enough!) + command: dpkg --print-architecture + register: dpkg_arch + +- name: Run command 'dpkg --print-foreign-architectures' (secondary OS arch, if available) + command: dpkg --print-foreign-architectures + register: dpkg_foreign_arch + + +- name: Add 'summary' variable values to {{ iiab_ini_file }} ini_file: path: "{{ iiab_ini_file }}" - section: location + section: summary option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: @@ -15,29 +28,39 @@ value: "{{ iiab_base }}" - option: iiab_dir value: "{{ iiab_dir }}" + - option: disk_used_a_priori + value: "{{ df1.stdout }}" -- name: Add 'version' variable values to {{ iiab_ini_file }} +- name: Add 'initial' variable values to {{ iiab_ini_file }} ini_file: path: "{{ iiab_ini_file }}" - section: version + section: initial option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: + - option: os_ver + value: "{{ os_ver }}" - option: distribution - value: "{{ ansible_distribution }}" + value: "{{ ansible_facts['distribution'] }}" - option: arch value: "{{ ansible_architecture }}" - - option: iiab_base_ver - value: "{{ iiab_base_ver }}" - - option: iiab_branch - value: "{{ ansible_local.local_facts.iiab_branch }}" - - option: iiab_commit - value: "{{ ansible_local.local_facts.iiab_commit }}" - - option: install_date - value: "{{ ansible_date_time.iso8601 }}" - #- option: xo_model - # value: "{{ xo_model }}" + - option: dpkg_arch + value: "{{ dpkg_arch.stdout }}" + - option: dpkg_foreign_arch + value: "{{ dpkg_foreign_arch.stdout }}" - option: rpi_model value: "{{ rpi_model }}" - option: devicetree_model value: "{{ devicetree_model }}" + - option: iiab_base_ver + value: "{{ iiab_base_ver }}" + - option: iiab_remote_url + value: "{{ ansible_local.local_facts.iiab_remote_url }}" + - option: iiab_branch + value: "{{ ansible_local.local_facts.iiab_branch }}" + - option: iiab_commit + value: "{{ ansible_local.local_facts.iiab_commit }}" + - option: iiab_recent_tag + value: "{{ ansible_local.local_facts.iiab_recent_tag }}" + - option: install_date + value: "{{ ansible_date_time.iso8601 }}" diff --git a/roles/0-init/tasks/hostname.yml b/roles/0-init/tasks/hostname.yml index 3d323b3cc..9e3e22214 100644 --- a/roles/0-init/tasks/hostname.yml +++ b/roles/0-init/tasks/hostname.yml @@ -1,3 +1,8 @@ +- name: "Set 'iiab_fqdn: {{ iiab_hostname }}.{{ iiab_domain }}'" + set_fact: + iiab_fqdn: "{{ iiab_hostname }}.{{ iiab_domain }}" + FQDN_changed: False + - name: Does /etc/cloud/cloud.cfg exist e.g. is this Ubuntu Server 18+ ? stat: path: /etc/cloud/cloud.cfg @@ -17,24 +22,23 @@ # 2021-08-31: Periods in /etc/hostname fail with some WiFi routers (#2904) # command: hostnamectl set-hostname "{{ iiab_hostname }}.{{ iiab_domain }}" -#- name: Install /etc/sysconfig/network from template (redhat) -# template: -# src: roles/network/templates/network/sysconfig.network.j2 -# dest: /etc/sysconfig/network -# owner: root -# group: root -# mode: 0644 -# when: is_redhat - -# roles/network/tasks/hosts.yml [no longer in use] ALSO did this: +# 2022-07-11: Should the first entry match just hostname and domain move to +# after localhost? See PR's #1 & #8 -- with discussion on #3302 -- and also: +# 1. /etc/hosts -- #1815 solved by PR #1847 +# 2. /etc/hostname -- #2904 solved by PR #2973 - name: 'Put FQDN & hostnames in /etc/hosts: "127.0.0.1 {{ iiab_hostname }}.{{ iiab_domain }} localhost.localdomain localhost {{ iiab_hostname }} box box.lan"' lineinfile: path: /etc/hosts regexp: '^127\.0\.0\.1' line: '127.0.0.1 {{ iiab_hostname }}.{{ iiab_domain }} localhost.localdomain localhost {{ iiab_hostname }} box box.lan' - #owner: root - #group: root - #mode: 0644 + +# 2021-07-30: FQDN_changed isn't used as in the past -- its remaining use is +# for {named, dhcpd, squid} in roles/network/tasks/main.yml -- possibly it +# should be reconsidered? See PR #2876: roles/network might become optional? +- name: "Also set 'FQDN_changed: True' -- if iiab_fqdn != ansible_fqdn ({{ ansible_fqdn }})" + set_fact: + FQDN_changed: True + when: iiab_fqdn != ansible_fqdn #- name: Re-configuring httpd - not initial install # include_tasks: roles/httpd/tasks/main.yml diff --git a/roles/0-init/tasks/main.yml b/roles/0-init/tasks/main.yml index 8d93f2441..8eb1668eb 100644 --- a/roles/0-init/tasks/main.yml +++ b/roles/0-init/tasks/main.yml @@ -7,17 +7,14 @@ # Higher-level purpose explained at the bottom of: # https://github.com/iiab/iiab/blob/master/vars/default_vars.yml -- name: "Ansible just ran /etc/ansible/facts.d/local_facts.fact to set 11 vars -- here we extract 3 of those -- rpi_model: {{ ansible_local.local_facts.rpi_model }}, devicetree_model: {{ ansible_local.local_facts.devicetree_model }}, iiab_stage: {{ ansible_local.local_facts.stage }}" +- name: "Ansible just ran /etc/ansible/facts.d/local_facts.fact to set 15 vars -- here we extract 6 of those -- iiab_stage: {{ ansible_local.local_facts.stage }}, rpi_model: {{ ansible_local.local_facts.rpi_model }}, devicetree_model: {{ ansible_local.local_facts.devicetree_model }}, os_ver: {{ ansible_local.local_facts.os_ver }}, python_version: {{ ansible_local.local_facts.python_version }}, php_version: {{ ansible_local.local_facts.php_version }}" set_fact: + iiab_stage: "{{ ansible_local.local_facts.stage }}" rpi_model: "{{ ansible_local.local_facts.rpi_model }}" devicetree_model: "{{ ansible_local.local_facts.devicetree_model }}" - #xo_model: "{{ ansible_local.local_facts.xo_model }}" - iiab_stage: "{{ ansible_local.local_facts.stage }}" - -# 2020-10-29: Appears no longer nec (see 3 above ansible_local.local_facts.*) -#- name: Re-read local_facts.facts from /etc/ansible/facts.d -# setup: -# filter: ansible_local + os_ver: "{{ ansible_local.local_facts.os_ver }}" + python_version: "{{ ansible_local.local_facts.python_version }}" + php_version: "{{ ansible_local.local_facts.php_version }}" # Initialize /etc/iiab/iiab.ini writing the 'location' and 'version' sections # once and only once, to preserve the install date and git hash. @@ -26,10 +23,9 @@ when: not iiab_ini_test.stat.exists # 2021-07-30: The 'first_run' flag isn't much used anymore. In theory it's -# still used in these 2 places: -# (1) roles/1-prep/tasks/main.yml for raspberry_pi.yml -# (2) roles/network/tasks/named.yml for "Stop named before copying files" -# In practice however, it's no longer important, and might be reconsidered? +# still used in 1-prep/tasks/hardware.yml for raspberry_pi.yml +# +# This needs to be reworked for 0-init speed, and overall understandability. - name: Set first_run flag set_fact: first_run: True @@ -38,11 +34,23 @@ # Copies the latest/known version of iiab-diagnostics into /usr/bin (so it can # be run even if local source tree /opt/iiab/iiab is deleted to conserve disk). -- name: Copy /opt/iiab/iiab/scripts/iiab-diagnostics to /usr/bin/iiab-diagnostics +- name: Copy iiab-update & iiab-summary & iiab-diagnostics & iiab-root-login from /opt/iiab/iiab/scripts/ to /usr/bin/ copy: - src: "{{ iiab_dir }}/scripts/iiab-diagnostics" + src: "{{ iiab_dir }}/scripts/{{ item }}" dest: /usr/bin/ mode: '0755' + with_items: + - iiab-update + - iiab-summary + - iiab-diagnostics + - iiab-root-login + +- name: Symlink /usr/bin/iiab-upgrade -> /usr/bin/iiab-update + file: + src: /usr/bin/iiab-update + path: /usr/bin/iiab-upgrade + state: link + #force: yes - name: Create globally-writable directory /etc/iiab/diag (0777) so non-root users can run 'iiab-diagnostics' file: @@ -53,13 +61,14 @@ - name: Pre-check that IIAB's "XYZ_install" + "XYZ_enabled" vars (1) are defined, (2) are boolean-not-string variables, and (3) contain plausible values. Also checks that "XYZ_install" is True when "XYZ_installed" is defined. include_tasks: validate_vars.yml + when: not (rpi_model | regex_search('\\bW\\b')) # Ansible require double backslashes, e.g. with \b "word boundary" anchors: https://www.regular-expressions.info/wordboundaries.html https://stackoverflow.com/questions/56869119/ansible-regular-expression-to-match-a-string-and-extract-the-line/56869801#56869801 -- name: "Time Zone / TZ: Set symlink /etc/localtime to UTC if it doesn't exist?" - include_tasks: tz.yml - -- name: Test Gateway + Test Internet + Set new hostname/domain (hostname.yml) if nec + Set 'gui_port' to 80 or 443 for Admin Console - include_tasks: network.yml +# 2022-12-30: Functionality moved to www_options/tasks/php-settings.yml +# - name: "Time Zone / TZ: Set symlink /etc/localtime to UTC if it doesn't exist?" +# include_tasks: tz.yml +- name: Set hostname / domain (etc) in various places + include_tasks: hostname.yml - name: Add 'runtime' variable values to {{ iiab_ini_file }} ini_file: @@ -74,10 +83,14 @@ value: "{{ iiab_base_ver }}" - option: iiab_revision value: "{{ iiab_revision }}" + - option: iiab_remote_url + value: "{{ ansible_local.local_facts.iiab_remote_url }}" - option: runtime_branch value: "{{ ansible_local.local_facts.iiab_branch }}" - option: runtime_commit value: "{{ ansible_local.local_facts.iiab_commit }}" + - option: iiab_recent_tag + value: "{{ ansible_local.local_facts.iiab_recent_tag }}" - option: runtime_date value: "{{ ansible_date_time.iso8601 }}" - option: ansible_version @@ -88,24 +101,22 @@ value: "{{ ansible_memtotal_mb }}" - option: swap_mb value: "{{ ansible_swaptotal_mb }}" - - option: gw_active - value: "{{ gw_active }}" - - option: internet_available - value: "{{ internet_available }}" - option: rpi_model value: "{{ rpi_model }}" - option: devicetree_model value: "{{ devicetree_model }}" + - option: os_ver + value: "{{ os_ver }}" + - option: python_version + value: "{{ python_version }}" + - option: php_version + value: "{{ php_version }}" - option: first_run value: "{{ first_run }}" - - option: local_tz # e.g. 'EDT' (summer) or 'EST' (winter) after Ansible interprets symlink /etc/localtime -- or 'UTC' if /etc/localtime doesn't exist - value: "{{ local_tz }}" - - option: etc_localtime.stdout # e.g. 'America/New_York' direct from symlink /etc/localtime -- or '' if /etc/localtime doesn't exist - value: "{{ etc_localtime.stdout }}" - #- option: no_NM_reload - # value: "{{ no_NM_reload }}" - #- option: is_F18 - # value: "{{ is_F18 }}" + # - option: local_tz # e.g. 'EDT' (summer) or 'EST' (winter) after Ansible interprets symlink /etc/localtime -- or 'UTC' if /etc/localtime doesn't exist + # value: "{{ local_tz }}" + # - option: etc_localtime.stdout # e.g. 'America/New_York' direct from symlink /etc/localtime -- or '' if /etc/localtime doesn't exist + # value: "{{ etc_localtime.stdout }}" - option: FQDN_changed value: "{{ FQDN_changed }}" diff --git a/roles/0-init/tasks/network.yml b/roles/0-init/tasks/network.yml deleted file mode 100644 index c0d52ba68..000000000 --- a/roles/0-init/tasks/network.yml +++ /dev/null @@ -1,74 +0,0 @@ -- name: Do we have a gateway? If 'ip route' specifies a default route, Ansible parses details here... - debug: - var: ansible_default_ipv4 - -- name: "If above ansible_default_ipv4.gateway is defined, set WAN candidate 'discovered_wan_iface: {{ ansible_default_ipv4.alias }}' -- using ansible_default_ipv4.alias" - set_fact: - discovered_wan_iface: "{{ ansible_default_ipv4.alias }}" - when: ansible_default_ipv4.gateway is defined - -- name: "Verify gateway active: ping -c4 {{ ansible_default_ipv4.gateway }} -- using ansible_default_ipv4.gateway" - shell: ping -c4 "{{ ansible_default_ipv4.gateway }}" | grep icmp_seq=4 | wc -l - register: gw_active_test - when: discovered_wan_iface != "none" - -- name: "If gateway responded, set 'gw_active: True' and 'iiab_wan_iface: {{ discovered_wan_iface }}' -- using discovered_wan_iface" - set_fact: - iiab_wan_iface: "{{ discovered_wan_iface }}" - gw_active: True - when: discovered_wan_iface != "none" and gw_active_test.stdout == "1" - - -- name: 'Test for Internet access, using: {{ iiab_download_url }}/heart-beat.txt' - get_url: - url: "{{ iiab_download_url }}/heart-beat.txt" - dest: /tmp/heart-beat.txt - #timeout: "{{ download_timeout }}" - # @jvonau recommends: 100sec is too much (keep 10sec default) - ignore_errors: True - #async: 10 - #poll: 2 - register: internet_access_test - -- name: "Set 'internet_available: True' if above download succeeded AND not disregard_network" - set_fact: - internet_available: True # Initialized to 'False' in 0-init/defaults/main.yml - when: not internet_access_test.failed and not disregard_network - -- name: Remove downloaded Internet test file /tmp/heart-beat.txt - file: - path: /tmp/heart-beat.txt - state: absent - - -- name: "Set 'iiab_fqdn: {{ iiab_hostname }}.{{ iiab_domain }}'" - set_fact: - iiab_fqdn: "{{ iiab_hostname }}.{{ iiab_domain }}" - FQDN_changed: False - -- name: Set hostname / domain (etc) in various places -- if iiab_fqdn != ansible_fqdn ({{ ansible_fqdn }}) - include_tasks: hostname.yml - when: iiab_fqdn != ansible_fqdn - -# 2021-07-30: FQDN_changed isn't used as in the past -- its remaining use is -# for {named, dhcpd, squid} in roles/network/tasks/main.yml -- possibly it -# should be reconsidered? See PR #2876: roles/network might become optional? -- name: "Also set 'FQDN_changed: True' -- if iiab_fqdn != ansible_fqdn ({{ ansible_fqdn }})" - set_fact: - FQDN_changed: True - when: iiab_fqdn != ansible_fqdn - - -# 2021-08-17: (1) iiab-gen-iptables works better if gui_port is set directly in -# default_vars.yml and/or local_vars.yml (2) Admin Console's iiab-admin.yml -# and js-menu.yml set 'adm_cons_force_ssl: False' - -# - name: "Set 'gui_port: 80' for Admin Console if not adm_cons_force_ssl" -# set_fact: -# gui_port: 80 -# when: not adm_cons_force_ssl - -# - name: "Set 'gui_port: 443' for Admin Console if adm_cons_force_ssl" -# set_fact: -# gui_port: 443 -# when: adm_cons_force_ssl diff --git a/roles/0-init/tasks/tz.yml b/roles/0-init/tasks/tz.yml.unused similarity index 97% rename from roles/0-init/tasks/tz.yml rename to roles/0-init/tasks/tz.yml.unused index 017947a05..dc07f8bc4 100644 --- a/roles/0-init/tasks/tz.yml +++ b/roles/0-init/tasks/tz.yml.unused @@ -1,3 +1,5 @@ +# 2022-12-30: Functionality moved to www_options/tasks/php-settings.yml + - name: "'local_tz: {{ local_tz }}' was set by ansible_date_time.tz in /opt/iiab/iiab/vars/default_vars.yml -- e.g. if Ansible finds symlink /etc/localtime -> ../usr/share/zoneinfo/America/New_York -- it will simplify that to 'EDT' (in the summer) or 'EST' (in the winter)" command: echo diff --git a/roles/0-init/tasks/validate_vars.yml b/roles/0-init/tasks/validate_vars.yml index f29525daf..dee75addd 100644 --- a/roles/0-init/tasks/validate_vars.yml +++ b/roles/0-init/tasks/validate_vars.yml @@ -63,38 +63,29 @@ # # 2020-11-04: Fix validation of 5 [now 4] core dependencies, for ./runrole etc -- name: Set vars_checklist for 44 + 44 + 40 vars ("XYZ_install" + "XYZ_enabled" + "XYZ_installed") to be checked + +- name: Set vars_checklist for 45 + 45 + 40 vars ("XYZ_install" + "XYZ_enabled" + "XYZ_installed") to be checked set_fact: vars_checklist: - hostapd - - dhcpd - - named - dnsmasq - bluetooth - #- wondershaper # Unmaintained - sshd - - openvpn + #- openvpn # Deprecated + - tailscale - remoteit - admin_console #- nginx # MANDATORY #- apache # Unmaintained - former dependency - #- mysql # MANDATORY - squid - #- dansguardian # Unmaintained - cups - samba - usb_lib - #- xo_services # Unmaintained - #- activity_server # Unmaintained - #- ejabberd_xs # Unmaintained - #- idmgr # Unmaintained - azuracast - #- dokuwiki # Unmaintained - #- ejabberd # Unmaintained - #- elgg # Unmaintained - gitea - jupyterhub - lokole + - mysql # Dependency - excluded from _installed check below - mediawiki - mosquitto - nodejs # Dependency - excluded from _installed check below @@ -111,6 +102,7 @@ - osm_vector_maps - transmission - awstats + - matomo - monit - munin - phpmyadmin @@ -122,6 +114,7 @@ - calibreweb - calibre - pbx + - network - name: Assert that {{ vars_checklist | length }} "XYZ_install" vars are all... defined assert: @@ -163,5 +156,41 @@ that: "{{ item }}_install or {{ item }}_installed is undefined" fail_msg: "DISALLOWED: '{{ item }}_install: False' (e.g. in /etc/iiab/local_vars.yml) WHEN '{{ item }}_installed' is defined (e.g. in /etc/iiab/iiab_state.yml) -- IIAB DOES NOT SUPPORT UNINSTALLS -- please verify those 2 files especially, and other places variables are defined?" quiet: yes - when: item != 'nodejs' and item != 'postgresql' and item != 'mongodb' and item != 'yarn' # Exclude auto-installed dependencies + when: item != 'mysql' and item != 'postgresql' and item != 'mongodb' and item != 'nodejs' and item != 'yarn' # Exclude auto-installed dependencies loop: "{{ vars_checklist }}" + + +- name: Set vars_deprecated_list for 4+ vars ("XYZ_install") to be checked + set_fact: + vars_deprecated_list: + - dhcpd # Deprecated + - named # Deprecated + - wondershaper # Deprecated + - dansguardian # Deprecated + #- xo_services # Unmaintained + #- activity_server # Unmaintained + #- ejabberd_xs # Unmaintained + #- idmgr # Unmaintained + #- dokuwiki # Unmaintained + #- ejabberd # Unmaintained + #- elgg # Unmaintained + +- name: 'DISALLOW "XYZ_install: True" if deprecated' + assert: + that: "{{ item }}_install is undefined or not {{ item }}_install" + fail_msg: "DISALLOWED: '{{ item }}_install: True' (e.g. in /etc/iiab/local_vars.yml)" + quiet: yes + loop: "{{ vars_deprecated_list }}" + # 2023-12-04: ansible-core 2.16.1 suddenly no longer allows 'assert' with + # 'with_items' below (whereas 'loop' construct above works!) BACKGROUND: + # + # 'due to mitigation of security issue CVE-2023-5764 in ansible-core 2.16.1, + # conditional expressions with embedded template blocks can fail with the + # message β€œConditional is marked as unsafe, and cannot be evaluated.”' + # https://docs.ansible.com/ansible-core/2.16/porting_guides/porting_guide_core_2.16.html#playbook + # + # with_items: + # - dhcpd # Deprecated + # - named # Deprecated + # - wondershaper # Deprecated + # - dansguardian # Deprecated diff --git a/roles/1-prep/README.adoc b/roles/1-prep/README.adoc index cdbd75142..997ec812b 100644 --- a/roles/1-prep/README.adoc +++ b/roles/1-prep/README.adoc @@ -6,7 +6,7 @@ https://github.com/iiab/iiab/wiki/IIAB-Contributors-Guide#ansible[stage] hardware, low-level OS quirks, and basic security: * SSHD -* OpenVPN if/as needed later for remote support +* Tailscale if/as needed later for remote support * https://github.com/iiab/iiab/tree/master/roles/iiab-admin#iiab-admin-readme[iiab-admin] username and group, to log into Admin Console * dnsmasq (install now, configure later!) @@ -14,17 +14,16 @@ username and group, to log into Admin Console * Ubermix (distro) needs /etc/tmpfiles.d/iiab.conf to create essential /var/log subdirs on each boot * *_Hardware actions:_* + ** link:tasks/install-expand-rootfs.yml[*_install-expand-rootfs.yml_*]: + *** Install https://en.wikipedia.org/wiki/APT_(software)[apt] packages parted (reveals last partition) and cloud-guest-utils (for growpart) + *** Install link:templates/iiab-expand-rootfs[/usr/sbin/iiab-expand-rootfs] that acts on flag flag `/.expand-rootfs` + *** Enable iiab-expand-rootfs.service so this can happen during any future boot-up ** link:tasks/raspberry_pi.yml[*_raspberry_pi.yml_*]: *** RTC (real-time clock): install udev rule, configure, enable - *** *_Install packages related to:_* - **** growpart - **** swapfile - **** fake-hwclock (as RTC is often missing or dead!) - **** Wi-Fi - *** Increase swap file size - *** https://github.com/iiab/iiab/blob/master/roles/1-prep/templates/iiab-rpi-max-rootfs.sh[rootfs - auto-resizing] + *** Install apt packages fake-hwclock (as above RTC is often missing or dead!) and dphys-swapfile (for swap file below) + *** Increase swap file size (to `pi_swap_file_size`) ** NUC 6 Wi-Fi firmware + ** Check for WiFi devices (if so, set `has_wifi_device`) Recap: Similar to 0-init, 2-common, 3-base-server, 4 server-options and 5-xo-services β€” this 1st stage installs core server infra (that is not diff --git a/roles/1-prep/tasks/hardware.yml b/roles/1-prep/tasks/hardware.yml index 2650c7217..52ef34a97 100644 --- a/roles/1-prep/tasks/hardware.yml +++ b/roles/1-prep/tasks/hardware.yml @@ -1,17 +1,37 @@ -## DISCOVER PLATFORMS ###### -# Put conditional actions for hardware platforms here +- include_tasks: install-expand-rootfs.yml + + +# Conditional hardware actions below: - include_tasks: raspberry_pi.yml when: first_run and rpi_model != "none" -- name: Check if the identifier for Intel's NUC6 built-in WiFi is present - shell: "lsusb | grep 8087:0a2b | wc | awk '{print $1}'" - register: usb_NUC6 - ignore_errors: True -- name: Download {{ iiab_download_url }}/iwlwifi-8000C-13.ucode to /lib/firmware for built-in WiFi on NUC6 # iiab_download_url is http://download.iiab.io/packages - get_url: - url: "{{ iiab_download_url }}/iwlwifi-8000C-13.ucode" - dest: /lib/firmware - timeout: "{{ download_timeout }}" - when: usb_NUC6.stdout|int > 0 +# 2024-02-09: Code below appears stale for Shanti's #3707 hardware +#- name: Check if the identifier for Intel's NUC6 built-in WiFi is present +# shell: "lsusb | grep 8087:0a2b | wc | awk '{print $1}'" +# register: usb_NUC6 +# ignore_errors: True +# +#- name: Download {{ iiab_download_url }}/iwlwifi-8000C-13.ucode to /lib/firmware for built-in WiFi on NUC6 +# get_url: +# url: "{{ iiab_download_url }}/Old/iwlwifi-8000C-13.ucode" # https://download.iiab.io/packages +# dest: /lib/firmware +# timeout: "{{ download_timeout }}" +# when: usb_NUC6.stdout|int > 0 + + +- name: "Look for any WiFi devices present: ls -la /sys/class/net/*/phy80211 | cut -d/ -f5" + shell: ls -la /sys/class/net/*/phy80211 | cut -d/ -f5 + register: wifi_devices + ignore_errors: True + changed_when: False + +- name: "Set has_wifi_device: True, if output (from above) shows device(s) here: {{ wifi_devices.stdout_lines }}" + set_fact: + has_wifi_device: True + when: wifi_devices is defined and wifi_devices.stdout_lines | length > 0 + # when: wifi_devices is defined and wifi_devices.stdout | trim != "" + +- debug: + var: has_wifi_device diff --git a/roles/1-prep/tasks/install-expand-rootfs.yml b/roles/1-prep/tasks/install-expand-rootfs.yml new file mode 100644 index 000000000..b5296e5c1 --- /dev/null +++ b/roles/1-prep/tasks/install-expand-rootfs.yml @@ -0,0 +1,20 @@ +- name: Install packages 'parted' and 'cloud-guest-utils' (for /usr/bin/growpart, though raspi-config uses fdisk) + package: + name: + - parted # 2022-03-15: RasPiOS and Ubuntu install this regardless -- so rarely nec, but just in case. + - cloud-guest-utils # 2022-04-02: For growpart command -- whereas RasPiOS's 'raspi-config --expand-rootfs' instead uses fdisk (requiring a reboot, see do_expand_rootfs() in https://github.com/RPi-Distro/raspi-config/blob/master/raspi-config). FYI Ubuntu pre-installs cloud-guest-utils, for use with cloud-init. + state: present + +- name: "Install from templates: /usr/sbin/iiab-expand-rootfs, /etc/systemd/system/iiab-expand-rootfs.service" + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + with_items: + - { src: 'iiab-expand-rootfs', dest: '/usr/sbin/', mode: '0755' } + - { src: 'iiab-expand-rootfs.service', dest: '/etc/systemd/system/', mode: '0644' } + +- name: Enable iiab-expand-rootfs.service + systemd: + name: iiab-expand-rootfs + enabled: yes diff --git a/roles/1-prep/tasks/main.yml b/roles/1-prep/tasks/main.yml index 0732c6dd8..16cf5976e 100644 --- a/roles/1-prep/tasks/main.yml +++ b/roles/1-prep/tasks/main.yml @@ -3,33 +3,47 @@ - name: ...IS BEGINNING ============================================ meta: noop -- name: SSHD -- required by OpenVPN below -- also run by roles/4-server-options/tasks/main.yml +- name: SSHD include_role: name: sshd when: sshd_install -- name: OPENVPN +- name: TAILSCALE (VPN) include_role: - name: openvpn - when: openvpn_install + name: tailscale + when: tailscale_install - name: REMOTE.IT include_role: name: remoteit when: remoteit_install -- name: IIAB-ADMIN -- includes roles/iiab-admin/tasks/access.yml +- name: IIAB-ADMIN -- includes {lynx, screen, sudo-prereqs.yml, admin-user.yml, pwd-warnings.yml} include_role: name: iiab-admin #when: iiab_admin_install # Flag might be created in future? -- name: Install dnsmasq -- configure LATER in 'network', after Stage 9 - include_tasks: roles/network/tasks/dnsmasq.yml - #when: dnsmasq_install # Flag might be used in future? +- name: Copy iiab-apps-to-be-installed from {{ iiab_dir }}/scripts to /usr/bin/ + copy: + src: "{{ iiab_dir }}/scripts/iiab-apps-to-be-installed" # /opt/iiab/iiab + dest: /usr/bin/ + mode: '0755' + +- name: Copy iiab-network from {{ iiab_dir }}/scripts to /usr/local/bin/ + copy: + src: "{{ iiab_dir }}/scripts/iiab-network" + dest: /usr/local/bin/ + mode: '0755' + +- name: Install ~12 network/wifi/related packages + Squid if necessary + configure /etc/sysctl.conf -- full configuration LATER in 'network', after Stage 9 + include_tasks: roles/network/tasks/install.yml + when: network_install and network_installed is undefined - include_tasks: uuid.yml - include_tasks: ubermix.yml -- include_tasks: hardware.yml # Can run raspberry_pi.yml + +- name: install-expand-rootfs.yml, raspberry_pi.yml, NUC6 WiFi firmware, check for WiFi devices + include_tasks: hardware.yml # Debian 10 "Buster" is apparently enabling AppArmor in 2019: @@ -60,7 +74,10 @@ # when: not is_debuntu and selinux_disabled is defined and selinux_disabled.changed -- name: Recording STAGE 1 HAS COMPLETED ============================ +- name: Install {{ iiab_env_file }} from template -- FYI this file can be run as a script if absolutely nec -- e.g. 'source /etc/iiab/iiab.env && echo $WWWROOT' template: src: roles/1-prep/templates/iiab.env.j2 - dest: "{{ iiab_env_file }}" # Can also be run as a script if absolutely nec, e.g. 'source /etc/iiab/iiab.env && echo $WWWROOT' + dest: "{{ iiab_env_file }}" + +- name: Recording STAGE 1 HAS COMPLETED ============================ + meta: noop diff --git a/roles/1-prep/tasks/raspberry_pi.yml b/roles/1-prep/tasks/raspberry_pi.yml index bc54f58af..fbc8cc784 100644 --- a/roles/1-prep/tasks/raspberry_pi.yml +++ b/roles/1-prep/tasks/raspberry_pi.yml @@ -4,9 +4,6 @@ template: src: 92-rtc-i2c.rules dest: /etc/udev/rules.d/92-rtc-i2c.rules - #owner: root - #group: root - #mode: 0644 when: rtc_id is defined and rtc_id != "none" # RTC requires a change to the device tree (and reboot) @@ -24,39 +21,14 @@ state: present when: rtc_id is defined and rtc_id != "none" and is_ubuntu # CLARIF: Ubuntu runs increasingly well on RPi hardware, starting in 2020 especially -#- name: Enable bluetooth in /boot/firmware/syscfg.txt on Ubuntu (needs reboot) -# lineinfile: -# path: /boot/firmware/syscfg.txt -# regexp: '^include*' -# line: 'include btcfg.txt' -# when: is_ubuntu - -- name: '2021-07-27: SEE ALSO ~4 networking packages LATER installed by https://github.com/iiab/iiab/blob/master/roles/2-common/tasks/packages.yml' - meta: noop - -- name: '2021-07-27: SEE ALSO 4-5 networking packages LATER installed by https://github.com/iiab/iiab/blob/master/roles/2-common/tasks/network.yml' - meta: noop - -# 2021-07-27 explanation from @jvonau: The 3 BELOW (iw, rfkill, wireless-tools) -# are provided by RaspiOS. Ubuntu|Debian on the other hand are hit or miss: -# desktops might have some/all 3 preinstalled, while servers tend not to have -# these present at all, but are needed to be installed if you want to take full -# advantage of WiFi on Ubuntu and friends -- but it's only enforced on RPi -# hardware where we know in advance of the likelihood of WiFi being present. - -- name: 'Install packages: cloud-guest-utils, dphys-swapfile, fake-hwclock, iw, rfkill, wireless-tools' +- name: 'Install packages: fake-hwclock, dphys-swapfile' package: name: - - cloud-guest-utils # Contains 'growpart' for resizing a partition during boot, which is normally done with the aid of cloud-init - - dphys-swapfile # 2021-07-27: RaspiOS installs this regardless -- autogenerate and use a swap file - - fake-hwclock # 2021-07-27: RaspiOS installs this regardless -- save/restore system clock on machines without working RTC hardware - - iw # 2021-07-27: RaspiOS installs this regardless -- configure Linux wireless devices -- hard dependence for ap0 creation, SEE https://github.com/iiab/iiab/blob/master/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 - - rfkill # 2021-07-27: RaspiOS installs this regardless -- enable & disable wireless devices - - wireless-tools # 2021-07-27: RaspiOS installs this regardless -- manipulate Linux Wireless Extensions + - fake-hwclock # 2021-03-15: Missing on Ubuntu etc. RasPiOS installs this regardless -- to save/restore system clock on machines w/o working RTC (above). + - dphys-swapfile # 2021-03-15: Missing on Ubuntu etc. RasPiOS installs this regardless -- to autogenerate and use a swap file (below). state: present - - name: Increase swap file size (to CONF_SWAPSIZE={{ pi_swap_file_size }} in /etc/dphys-swapfile) as kalite pip download fails lineinfile: path: /etc/dphys-swapfile @@ -70,18 +42,9 @@ state: restarted -- name: Install RPi rootfs resizing (/usr/sbin/iiab-rpi-max-rootfs.sh) and its systemd service (/etc/systemd/system/iiab-rpi-root-resize.service), from templates (root:root by default) - template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - #owner: root - #group: root - mode: "{{ item.mode }}" - with_items: - - { src: 'iiab-rpi-max-rootfs.sh', dest: '/usr/sbin/', mode: '0755' } - - { src: 'iiab-rpi-root-resize.service', dest: '/etc/systemd/system/', mode: '0644' } - -- name: Enable RPi rootfs resizing (systemd service iiab-rpi-root-resize.service) - systemd: - name: iiab-rpi-root-resize - enabled: yes +#- name: Enable bluetooth in /boot/firmware/syscfg.txt on Ubuntu (needs reboot) +# lineinfile: +# path: /boot/firmware/syscfg.txt +# regexp: '^include*' +# line: 'include btcfg.txt' +# when: is_ubuntu diff --git a/roles/1-prep/templates/iiab-expand-rootfs b/roles/1-prep/templates/iiab-expand-rootfs new file mode 100644 index 000000000..89d2bd552 --- /dev/null +++ b/roles/1-prep/templates/iiab-expand-rootfs @@ -0,0 +1,72 @@ +#!/bin/bash -xe + +# Expand rootfs partition to its maximum size, if /.expand-rootfs exists. +# Used by /etc/systemd/system/iiab-expand-rootfs.service on IIAB boot. + +# Should work with all Linux OS's boot disks -- regardless whether Raspberry Pi +# microSD cards, external USB drives, internal spinning disks or SSD's, etc. + +# Verifies that rootfs is the last partition. + +# RELATED: +# 1. https://github.com/iiab/iiab-factory/blob/master/box/rpi/min-sd +# 2. https://github.com/iiab/iiab-factory/blob/master/box/rpi/cp-sd +# 3. https://github.com/iiab/iiab-factory/blob/master/box/rpi/xz-json-sd +# OR https://github.com/iiab/iiab-factory/blob/master/box/rpi/exp-sd + +if [ -f /.expand-rootfs ] || [ -f /.resize-rootfs ]; then + echo "$0: Expanding rootfs partition" + + if [ -x /usr/bin/raspi-config ]; then # Raspberry Pi OS -- WARNING: their fdisk-centric approach of course FAILS with "Hybrid MBR" or GPT partition tables, as required by any drive > 2TB :/ + # 2022-02-17: Uses do_expand_rootfs() from: + # https://github.com/RPi-Distro/raspi-config/blob/master/raspi-config + # 2023-10-05: Official new RPi instructions: + # sudo raspi-config nonint do_expand_rootfs + # https://www.raspberrypi.com/documentation/computers/configuration.html#expand-filesystem-nonint + raspi-config --expand-rootfs # REQUIRES A REBOOT + rm -f /.expand-rootfs /.resize-rootfs + reboot # In future, we might warn interactive users that a reboot is coming? + else # REQUIRES NO REBOOT; BEWARE iiab-expand-rootfs.service RACE CONDITION WITH fsck (PR #2522 & #3325) + # 2022-03-15: Borrows from above raspi-config URL's do_expand_rootfs() + ROOT_PART="$(findmnt / -o SOURCE -n)" # e.g. /dev/sda2 or /dev/mmcblk0p2 + ROOT_DEV="/dev/$(lsblk -no pkname "$ROOT_PART")" # e.g. /dev/sda or /dev/mmcblk0 + + ROOT_PART_NUM="$(echo "$ROOT_PART" | grep -o "[[:digit:]]*$")" # e.g. 2 + # SLOW (~10 seconds) but it works! + LAST_PART_NUM=$(parted "$ROOT_DEV" -ms unit s p | tail -n 1 | cut -f 1 -d:) + + if [ $ROOT_PART_NUM -ne $LAST_PART_NUM ]; then + echo "ERROR: $ROOT_PART partition ($ROOT_PART_NUM) is not the last partition ($LAST_PART_NUM). Don't know how to expand." + exit 1 + fi + + # Expand partition + growpart $ROOT_DEV $ROOT_PART_NUM || true # raspi-config instead uses fdisk (assuming MBR). They really should transition to gdisk, as required by any drive > 2TB. WARNING: growpart RC 2 is more severe than RC 1, and should possibly be handled separately in future? + rc=$? # Make Return Code visible, for 'bash -x' + resize2fs $ROOT_PART + rc=$? # Make RC visible (as above) + + # 2022-03-15: Legacy code below worked with Raspberry Pi microSD cards + # but *not* with USB boot drives, internal spinning disks/SSD's, etc. + + # # ASSUMES SD CARD STYLE PARTITION NAME LIKE p + # # e.g. /dev/mmcblk0p2 mounts at / (typical RasPiOS microSD) + # # BUT /dev/sda2 mounts at /media/usb1 (RasPiOS USB boot disk... + # # ...WON'T WORK BELOW; recap @ PR #3121) + + # # Calculate root partition + # root_part=`lsblk -aP -o NAME,MOUNTPOINT | grep 'MOUNTPOINT="/"' | awk -F\" '{ print $2 }'` # e.g. mmcblk0p2 + # root_dev=${root_part:0:-2} # e.g. mmcblk0 + # # bash substring expansion: "negative offset [below, but not above] + # # must be separated from the colon by at least one space to avoid + # # being confused with the β€˜:-’ expansion" + # # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html + # root_part_no=${root_part: -1} # e.g. 2 + + # # Resize partition + # growpart /dev/$root_dev $root_part_no + # resize2fs /dev/$root_part + + rm -f /.expand-rootfs /.resize-rootfs + fi +fi diff --git a/roles/1-prep/templates/iiab-expand-rootfs.service b/roles/1-prep/templates/iiab-expand-rootfs.service new file mode 100644 index 000000000..91de4cc5b --- /dev/null +++ b/roles/1-prep/templates/iiab-expand-rootfs.service @@ -0,0 +1,24 @@ +[Unit] +Description=Root Filesystem Auto-Expander +DefaultDependencies=no +# 2022-08-08: IIAB's 4 core OS's have 'After=systemd-fsck-root.service' WITHIN +# systemd-remount-fs.service, allowing us to avoid #3325 race condition w/ fsck +After=systemd-remount-fs.service +# 2022-08-08: While dphys-swapfile.service doesn't exist on Ubuntu, Mint +# and pure Debian, the following line may still serve a purpose on RasPiOS: +Before=dphys-swapfile.service + +[Service] +Environment=TERM=linux +Type=oneshot +ExecStart=/usr/sbin/iiab-expand-rootfs +# 2022-08-08: By default, systemd dangerously kills rootfs expansion after just +# 90s (1TB microSD cards take ~8 min to expand). Let's remove the time limit: +TimeoutSec=infinity +# "Standard output type syslog is obsolete" +# StandardError=syslog +# WHEREAS StandardError=journal is the default, per https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput= +RemainAfterExit=yes + +[Install] +WantedBy=local-fs.target diff --git a/roles/1-prep/templates/iiab-rpi-max-rootfs.sh b/roles/1-prep/templates/iiab-rpi-max-rootfs.sh deleted file mode 100644 index d24788602..000000000 --- a/roles/1-prep/templates/iiab-rpi-max-rootfs.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -x -# Resize rootfs and its partition on the rpi SD card to maximum size -# To be used by systemd service on boot -# Only resizes if /.resize-rootfs exists -# Assumes root is last partition -# Only works on F22 + where resizepart command exists -# Assumes sd card style partition name like p - -if [ -f /.resize-rootfs ];then - echo "$0: maximizing rootfs partion" - # Calculate root partition - root_part=`lsblk -aP -o NAME,MOUNTPOINT|grep 'MOUNTPOINT="/"' |awk -F\" '{ print $2 }'` - root_dev=${root_part:0:-2} - root_part_no=${root_part: (-1)} - - # Resize partition - growpart /dev/$root_dev $root_part_no - resize2fs /dev/$root_part - rm /.resize-rootfs -fi diff --git a/roles/1-prep/templates/iiab-rpi-root-resize.service b/roles/1-prep/templates/iiab-rpi-root-resize.service deleted file mode 100644 index 2cd33ec11..000000000 --- a/roles/1-prep/templates/iiab-rpi-root-resize.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Root Filesystem Auto-Resizer - -[Service] -Environment=TERM=linux -Type=oneshot -ExecStart=/usr/sbin/iiab-rpi-max-rootfs.sh -StandardError=syslog -RemainAfterExit=no - -[Install] -WantedBy=multi-user.target diff --git a/roles/2-common/README.adoc b/roles/2-common/README.adoc index 83943e761..3397bf2a3 100644 --- a/roles/2-common/README.adoc +++ b/roles/2-common/README.adoc @@ -9,10 +9,8 @@ https://internet-in-a-box.org/[Internet-in-a-Box (IIAB)] server. These are (partially) put in place: * IIAB directory structure (link:tasks/fl.yml[file layout]) -* Common https://en.wikipedia.org/wiki/APT_(software)[apt] software -packages -* Networking (including the -https://en.wikipedia.org/wiki/Iptables[iptables] firewall) +* Common https://en.wikipedia.org/wiki/APT_(software)[apt] software packages +* Networking apt packages (including many WiFi tools, and also iptables-persistent for the https://en.wikipedia.org/wiki/Iptables[iptables] firewall) * link:tasks/iiab-startup.yml[/usr/libexec/iiab-startup.sh] similar to AUTOEXEC.BAT and /etc/rc.local, in order to run jobs on boot diff --git a/roles/2-common/tasks/fl.yml b/roles/2-common/tasks/fl.yml index 0235c2522..829b8dfbf 100644 --- a/roles/2-common/tasks/fl.yml +++ b/roles/2-common/tasks/fl.yml @@ -1,6 +1,6 @@ # fl.yml signifies "file layout" -- name: "File Layout - Create directories: 1 in /etc, 1 in {{ py3_dist_path }}, 3 in {{ iiab_base }}, 17 in {{ content_base }}" # iiab_base: /opt/iiab +- name: "File Layout - Create directories: 1 in {{ py3_dist_path }}, 2 in {{ iiab_base }}, 17 in {{ content_base }}" # iiab_base: /opt/iiab file: path: "{{ item }}" # owner: root @@ -8,11 +8,11 @@ # mode: '0755' state: directory with_items: - - /etc/sysconfig/olpc-scripts/setup.d/installed/ + #- /etc/sysconfig/olpc-scripts/setup.d/installed/ - "{{ py3_dist_path }}/iiab" # /usr/lib/python3/dist-packages - - "{{ yum_packages_dir }}" # /opt/iiab/yum-packages + #- "{{ yum_packages_dir }}" # /opt/iiab/yum-packages - "{{ pip_packages_dir }}" # /opt/iiab/pip-packages - - "{{ downloads_dir }}" # /opt/iiab/downloads -- generally already done by Stage 1's roles/remoteit/tasks/install.yml + - "{{ downloads_dir }}" # /opt/iiab/downloads #- "{{ content_base }}/downloads" # /library/downloads auto-created just below - "{{ content_base }}/downloads/zims" - "{{ content_base }}/downloads/maps" diff --git a/roles/2-common/tasks/main.yml b/roles/2-common/tasks/main.yml index a89928992..c6fb3f21c 100644 --- a/roles/2-common/tasks/main.yml +++ b/roles/2-common/tasks/main.yml @@ -8,8 +8,14 @@ - include_tasks: packages.yml -- name: "Network prep, including partial setup of iptables (firewall) -- SEE ALSO: 1-prep/tasks/raspberry_pi.yml" - include_tasks: network.yml +- name: "Use 'sysctl' to set 'kernel.core_uses_pid: 1' in /etc/sysctl.conf" + sysctl: # Places these settings in /etc/sysctl.conf, to survive reboot + name: "{{ item.name }}" + value: "{{ item.value }}" + with_items: + #- { name: 'kernel.sysrq', value: '1' } # OS values differ, Ok? + - { name: 'kernel.core_uses_pid', value: '1' } + #- { name: 'kernel.shmmax', value: '268435456' } # OS values differ, Ok? - include_tasks: iiab-startup.yml diff --git a/roles/2-common/tasks/network.yml b/roles/2-common/tasks/network.yml deleted file mode 100644 index 435c0bb1f..000000000 --- a/roles/2-common/tasks/network.yml +++ /dev/null @@ -1,45 +0,0 @@ -- name: '2021-07-27: SEE ALSO ~3 networking packages EARLIER installed by https://github.com/iiab/iiab/blob/master/roles/1-prep/tasks/raspberry_pi.yml' - meta: noop - -- name: '2021-07-27: SEE ALSO ~4 networking packages EARLIER installed by https://github.com/iiab/iiab/blob/master/roles/2-common/tasks/packages.yml' - meta: noop - -- name: Install package networkd-dispatcher (OS's other than RaspiOS) - package: - name: networkd-dispatcher # Dispatcher service for systemd-networkd connection status changes - state: present - when: not is_raspbian - -- name: 'Install network packages: hostapd, iproute2, iptables-persistent, netmask -- later used by https://github.com/iiab/iiab/tree/master/roles/network' - package: - name: - - hostapd # IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator -- has its service masked out of the box, and only used when IIAB's network roles detects the presence of WiFi and an AP is desired - - iproute2 # 2021-07-27: RaspiOS installs this regardless -- the new networking and traffic control tools, meant to replace net-tools - - iptables-persistent # Boot-time loader for netfilter rules, iptables (firewall) plugin -- however Netfilter / nftables is ever moving forward so keep an eye on it! - - netmask # Handy utility -- helps determine network masks - state: present - -# 2021-08-17: Debian ignores this, according to 2013 post: -# https://serverfault.com/questions/511099/debian-ignores-etc-network-if-pre-up-d-iptables -# - name: Install /etc/network/if-pre-up.d/iptables from template (0755) -# template: -# src: iptables -# dest: /etc/network/if-pre-up.d/iptables -# mode: '0755' - -# Ongoing rework (e.g. PR #2652) arising from ansible.posix collection changes: -- name: "Use 'sysctl' to set 'kernel.core_uses_pid: 1' + 4 network settings in /etc/sysctl.conf -- e.g. disabling IPv6 (this might be overkill, as IPv6 should really only be disabled on the LAN side, i.e. br0)" - sysctl: # Places these settings in /etc/sysctl.conf, to survive reboot - name: "{{ item.name }}" - value: "{{ item.value }}" - with_items: - - { name: 'net.ipv4.ip_forward', value: '1' } # Masquerading LAN->Internet - - { name: 'net.ipv4.conf.default.rp_filter', value: '1' } - - { name: 'net.ipv4.conf.default.accept_source_route', value: '0' } - #- { name: 'kernel.sysrq', value: '1' } # OS values differ, Ok? - - { name: 'kernel.core_uses_pid', value: '1' } - #- { name: 'net.ipv4.tcp_syncookies', value: '1' } # Very standard in 2020 - #- { name: 'kernel.shmmax', value: '268435456' } # OS values differ, Ok? - - { name: 'net.ipv6.conf.all.disable_ipv6', value: '1' } # IPv6 disabled - #- { name: 'net.ipv6.conf.default.disable_ipv6', value: '1' } # AUTO-SET - #- { name: 'net.ipv6.conf.lo.disable_ipv6', value: '1' } # BY ABOVE diff --git a/roles/2-common/tasks/packages.yml b/roles/2-common/tasks/packages.yml index 81bc35c94..681d8b83f 100644 --- a/roles/2-common/tasks/packages.yml +++ b/roles/2-common/tasks/packages.yml @@ -1,47 +1,39 @@ -- name: '2021-07-27: SEE ALSO ~3 networking packages EARLIER installed by https://github.com/iiab/iiab/blob/master/roles/1-prep/tasks/raspberry_pi.yml' - meta: noop +# 2022-03-16: 'apt show | grep Size' revealed download sizes, on 64-bit RasPiOS with desktop. -- name: '2021-07-27: SEE ALSO 4-5 networking packages LATER installed by https://github.com/iiab/iiab/blob/master/roles/2-common/tasks/network.yml' - meta: noop - -- name: "Install 20 common packages: acpid, avahi-daemon, bzip2, curl, gawk, htop, i2c-tools, libnss-mdns, logrotate, mlocate, net-tools, pandoc, pastebinit, rsync, sqlite3, tar, unzip, usbutils, wget, wpasupplicant" +- name: "Install 19 common packages: acpid, bzip2, cron, curl, gawk, gpg, htop, i2c-tools, logrotate, lshw, pandoc, pastebinit, plocate, rsync, sqlite3, tar, unzip, usbutils, wget" package: name: - - acpid # Daemon for ACPI (power mgmt) events - - avahi-daemon # 2021-07-27: RaspiOS (and package libnss-mnds, below) install this regardless -- holdover from the XO days and used to advertise ssh/admin-console being available via avahi-daemon -- used with https://github.com/iiab/iiab/blob/master/roles/network/tasks/avahi.yml - #- avahi-discover # 2021-07-27: Commented out long ago - - bzip2 # 2021-04-26: Prob not used, but can't hurt? - - curl # Used to install roles/nodejs and roles/nodered - #- etckeeper # "nobody is really using etckeeper and it's bloating the filesystem every time apt runs" per @jvonau at https://github.com/iiab/iiab/issues/1146 - #- exfat-fuse # 2021-07-27: Should no longer be nec with 5.4+ kernels, so let's try commenting it out - #- exfat-utils # Ditto! See also 'ntfs-3g' below - - gawk - - htop - - i2c-tools # Low-level bus/chip/register/EEPROM tools e.g. for RTC - #- inetutils-syslogd # 2021-07-27: Error logging facility -- holdover from the XO days, journalctl has replaced this in newer distros - #- iproute2 # Installed by roles/2-common/tasks/network.yml - - logrotate - - libnss-mdns # 2021-07-27: RaspiOS (and package avahi-daemon, above) install this regardless -- client-side library -- provides name resolution via mDNS (Multicast DNS) using Zeroconf/Bonjour e.g. Avahi - #- lynx # Installed by 1-prep's roles/iiab-admin/tasks/access.yml - #- make # 2021-07-27: Currently used by roles/pbx and no other roles - - mlocate - - net-tools # 2021-04-26: @jvonau suggests possibly deleting this...unless oldtimers really want these older commands in iiab-diagnostics output? - #- ntfs-3g # 2021-07-31: RaspiOS installs this regardless -- but this should no longer be nec with 5.4+ kernels, similar to exfat packages above -- however, see also this symlink warning: https://superuser.com/questions/1050544/mount-with-kernel-ntfs-and-not-ntfs-3g -- and upcoming kernel 5.15 improvements: https://www.phoronix.com/scan.php?page=news_item&px=New-NTFS-Likely-For-Linux-5.15 - #- openssh-server # ssh (Raspbian) or openssh-server (other OS's) already installed by 1-prep's roles/sshd/tasks/main.yml - - pandoc # For /usr/bin/iiab-refresh-wiki-docs - - pastebinit # For /usr/bin/iiab-diagnostics - #- python3-pip # 2021-07-29: Already installed by /opt/iiab/iiab/scripts/ansible -- this auto-installs 'python3-setuptools' and 'python3' etc - #- python3-venv # 2021-07-30: For Ansible module 'pip' used in roles like {calibre-web, jupyterhub, lokole} -- whereas roles/kalite uses (virtual) package 'virtualenv' for Python 2 -- all these 3+1 IIAB roles install 'python3-venv' for themselves. FYI: Debian 11 auto-installs 'python3-venv' when you install 'python3' -- whereas Ubuntu (e.g. 20.04 & 21.10) and RaspiOS 10 do not. - - rsync - #- screen # Installed by 1-prep's roles/iiab-admin/tasks/access.yml - - sqlite3 - #- sudo # (1) Should be installed prior to installing IIAB, (2) Can also be installed by roles/1-prep's roles/openvpn/tasks/install.yml, (3) Is definitely installed by 1-prep's roles/iiab-admin/tasks/sudo-prereqs.yml - - tar - - unzip - #- usbmount # Moved to roles/usb_lib/tasks/install.yml - - usbutils # 2021-07-27: RaspiOS installs this regardless -- move to roles/usb_lib/tasks/install.yml ? - - wget - - wpasupplicant # 2021-07-27: RaspiOS installs this regardless -- client library for connections to a WiFi AP + - acpid # 55kB download: Daemon for ACPI (power mgmt) events + - bzip2 # 47kB download: RasPiOS installs this regardless -- 2021-04-26: Prob not used, but can't hurt? + - cron # 98kB download: RasPiOS installs this regardless -- 2022-10-13: Debian 12 needs this added (for now?) + - curl # 254kB download: RasPiOS installs this regardless -- Used to install roles/nodejs and roles/nodered + #- etckeeper # 54kB download: "nobody is really using etckeeper and it's bloating the filesystem every time apt runs" per @jvonau at https://github.com/iiab/iiab/issues/1146 + #- exfat-fuse # 28kB download: 2021-07-27: Should no longer be nec with 5.4+ kernels, so let's try commenting it out + #- exfat-utils # 41kB download: Ditto! See also 'ntfs-3g' below + - gawk # 533kB download + - gpg # 884kB download: Debian 12+ (especially!) require this for apt installs of gitea, kolibri, mongodb, yarn + - htop # 109kB download: RasPiOS installs this regardless + - i2c-tools # 78kB download: Low-level bus/chip/register/EEPROM tools e.g. for RTC + - logrotate # 67kB download: RasPiOS installs this regardless + - lshw # 257kB download: For 'lshw -C network' in iiab-diagnostics + #- lynx # 505kB download: Installed by 1-prep's roles/iiab-admin/tasks/main.yml + #- make # 376kB download: 2021-07-27: Currently used by roles/pbx and no other roles + #- ntfs-3g # 379kB download: RasPiOS installs this regardless -- 2021-07-31: But this should no longer be nec with 5.4+ kernels, similar to exfat packages above -- however, see also this symlink warning: https://superuser.com/questions/1050544/mount-with-kernel-ntfs-and-not-ntfs-3g -- and upcoming kernel 5.15 improvements: https://www.phoronix.com/scan.php?page=news_item&px=New-NTFS-Likely-For-Linux-5.15 + #- openssh-server # 318kB download: RasPiOS installs this regardless -- this is also installed by 1-prep's roles/sshd/tasks/main.yml to cover all OS's + - pandoc # 19kB download: For /usr/bin/iiab-refresh-wiki-docs + - pastebinit # 47kB download: For /usr/bin/iiab-diagnostics + #- mlocate # 92kB download + - plocate # 97kB download: Faster & smaller than locate & mlocate + #- python3-pip # 337kB download: 2023-03-22: Used to be installed by /opt/iiab/iiab/scripts/ansible -- which would auto-install 'python3-setuptools' and 'python3' etc + #- python3-venv # 1188kB download: 2023-03-22: Already installed by /opt/iiab/iiab/scripts/ansible -- used by roles like {calibre-web, jupyterhub, lokole} -- whereas roles/kalite uses (virtual) package 'virtualenv' for Python 2 -- all these 3+1 IIAB roles install 'python3-venv' for themselves. FYI: Debian 11 no longer auto-installs 'python3-venv' when you install 'python3' + - rsync # 351kB download: RasPiOS installs this regardless + #- screen # 551kB download: Installed by 1-prep's roles/iiab-admin/tasks/main.yml + - sqlite3 # 1054kB download + - tar # 799kB download: RasPiOS installs this regardless + - unzip # 151kB download: RasPiOS installs this regardless + #- usbmount # 18kB download: Moved to roles/usb_lib/tasks/install.yml + - usbutils # 67kB download: RasPiOS installs this regardless -- 2021-07-27: move to roles/usb_lib/tasks/install.yml ? + - wget # 922kB download: RasPiOS installs this regardless state: present #- name: "Install 10 yum/dnf packages: avahi, avahi-tools, createrepo, linux-firmware, nss-mdns, openssl, syslog, wpa_supplicant, xml-common, yum-utils (redhat)" diff --git a/roles/3-base-server/README.rst b/roles/3-base-server/README.rst index e458d7be0..1f22db3a2 100644 --- a/roles/3-base-server/README.rst +++ b/roles/3-base-server/README.rst @@ -1,10 +1,21 @@ +.. |ss| raw:: html + + + +.. |se| raw:: html + + + +.. |nbsp| unicode:: 0xA0 + :trim: + ==================== 3-base-server README ==================== This 3rd `stage `_ installs base server infra that `Internet-in-a-Box (IIAB) `_ requires, including: -- `MySQL `_ (database underlying many/most user-facing apps). This IIAB role also installs apt package: +- |ss| `MySQL `_ (database underlying many/most user-facing apps). |se| |nbsp| *As of 2023-11-05, MySQL / MariaDB is NO LONGER INSTALLED by 3-base-server β€” instead it's installed on-demand β€” as a dependency of Matomo, MediaWiki, Nextcloud, PBX (for FreePBX), WordPress &/or Admin Console.* This IIAB role (roles/mysql) also installs apt package: - **php{{ php_version }}-mysql** β€” which forcibly installs **php{{ php_version }}-common** - `NGINX `_ web server (with Apache in some lingering cases). This IIAB role also installs apt package: - **php{{ php_version }}-fpm** β€” which forcibly installs **php{{ php_version }}-cli**, **php{{ php_version }}-common** and **libsodium23** diff --git a/roles/3-base-server/tasks/main.yml b/roles/3-base-server/tasks/main.yml index 5e2e7355d..efe1c93e2 100644 --- a/roles/3-base-server/tasks/main.yml +++ b/roles/3-base-server/tasks/main.yml @@ -3,10 +3,13 @@ - name: ...IS BEGINNING ===================================== meta: noop -- name: MYSQL + CORE PHP - include_role: - name: mysql - #when: mysql_install +# 2023-11-05: MySQL (actually MariaDB) had been mandatory, installed on every +# IIAB by 3-base-server. Now installed on demand -- as a dependency of Matomo, +# MediaWiki, Nextcloud, PBX (for FreePBX), WordPress &/or Admin Console. +# - name: MYSQL + CORE PHP +# include_role: +# name: mysql +# #when: mysql_install # 2021-05-21: Apache role 'httpd' is installed as nec by any of these 6 roles: # diff --git a/roles/4-server-options/README.rst b/roles/4-server-options/README.rst index 6355f85e7..11458d97e 100644 --- a/roles/4-server-options/README.rst +++ b/roles/4-server-options/README.rst @@ -2,7 +2,7 @@ 4-server-options README ======================= -Whereas 3-base-server installs critical packages needed by all, this 4th `stage `_ installs a broad array of *options* ⁠— depending on which server apps will be installed in later stages ⁠— as specified in `/etc/iiab/local_vars.yml `_ +Whereas 3-base-server installs critical packages needed by all, this 4th `stage `_ installs a broad array of *options* ⁠— depending on which server apps will be installed in later stages ⁠— as specified in `/etc/iiab/local_vars.yml `_ This includes more networking fundamentals, that may further be configured later on. @@ -11,7 +11,7 @@ Specifically, these might be installed: - Python libraries - SSH daemon - Bluetooth for Raspberry Pi -- Instant-sharing of `USB stick content `_ +- Instant-sharing of `USB stick content `_ - CUPS Printing - Samba for Windows filesystems - `www_options `_ diff --git a/roles/4-server-options/tasks/main.yml b/roles/4-server-options/tasks/main.yml index 8ccf6b88b..583cb763d 100644 --- a/roles/4-server-options/tasks/main.yml +++ b/roles/4-server-options/tasks/main.yml @@ -19,28 +19,6 @@ #when: pylibs_installed is undefined #when: pylibs_install # Flag might be created in future? -- name: SSHD -- also run by roles/1-prep/tasks/main.yml as required by OpenVPN - include_role: - name: sshd - when: sshd_install - - -# UNMAINTAINED -- name: Install named / BIND - include_tasks: roles/network/tasks/named.yml - when: named_install is defined and named_install - -# UNMAINTAINED -- name: Install dhcpd - include_tasks: roles/network/tasks/dhcpd.yml - when: dhcpd_install is defined and dhcpd_install - -# LESS MAINTAINED -- name: Install Squid - include_tasks: roles/network/tasks/squid.yml - when: squid_install and squid_installed is undefined - - - name: Install Bluetooth - only on Raspberry Pi include_role: name: bluetooth diff --git a/roles/6-generic-apps/tasks/main.yml b/roles/6-generic-apps/tasks/main.yml index f241095f6..f43e878f3 100644 --- a/roles/6-generic-apps/tasks/main.yml +++ b/roles/6-generic-apps/tasks/main.yml @@ -3,11 +3,6 @@ - name: ...IS BEGINNING ==================================== meta: noop -- name: AZURACAST - include_role: - name: azuracast - when: azuracast_install is defined and azuracast_install - # UNMAINTAINED - name: DOKUWIKI include_role: @@ -36,10 +31,11 @@ name: jupyterhub when: jupyterhub_install +# UNMAINTAINED - name: LOKOLE include_role: name: lokole - when: lokole_install + when: lokole_install is defined and lokole_install - name: MEDIAWIKI include_role: diff --git a/roles/7-edu-apps/tasks/main.yml b/roles/7-edu-apps/tasks/main.yml index 8f223b1fd..69d1b0788 100644 --- a/roles/7-edu-apps/tasks/main.yml +++ b/roles/7-edu-apps/tasks/main.yml @@ -6,12 +6,13 @@ - name: KALITE include_role: name: kalite - when: kalite_install + when: kalite_install and (is_ubuntu_2204 or is_ubuntu_2310 or is_debian_12) # Also covers is_linuxmint_21 and is_raspbian_12 - name: KOLIBRI include_role: name: kolibri when: kolibri_install + #when: kolibri_install and python_version is version('3.12', '<') # Debian 13 still uses Python 3.11 (for now!) so really this just avoids Ubuntu 24.04 and 24.10 pre-releases during initial iiab-install. CLARIF: This is all TEMPORARY until learningequality/kolibri#11316 brings Python 3.12 support to Kolibri 0.17 pre-releases (expected very soon). - name: KIWIX include_role: @@ -40,10 +41,23 @@ name: pathagar when: pathagar_install is defined and pathagar_install +# WARNING: Since March 2023, 32-bit RasPiOS can act as 64-bit on RPi 4 and +# RPi 400 (unlike RPi 3!) SEE: https://github.com/iiab/iiab/pull/3422 and #3516 +- name: Run command 'dpkg --print-architecture' to identify OS architecture (CPU arch as revealed by ansible_architecture ~= ansible_machine is NO LONGER enough!) + command: dpkg --print-architecture + register: dpkg_arch + when: sugarizer_install + +- name: Explain bypassing of Sugarizer install if 32-bit OS + fail: # FORCE IT RED THIS ONCE! + msg: "BYPASSING SUGARIZER INSTALL ATTEMPT, as Sugarizer Server 1.5.0 requires MongoDB 3.2+ which is NO LONGER SUPPORTED on 32-bit Raspberry Pi OS. 'dpkg --print-architecture' output for your OS: {{ dpkg_arch.stdout }}" + when: sugarizer_install and not dpkg_arch.stdout is search("64") + ignore_errors: True + - name: SUGARIZER include_role: name: sugarizer - when: sugarizer_install + when: sugarizer_install and dpkg_arch.stdout is search("64") - name: Recording STAGE 7 HAS COMPLETED ======================== lineinfile: diff --git a/roles/8-mgmt-tools/tasks/main.yml b/roles/8-mgmt-tools/tasks/main.yml index e75f97e23..c6d497f15 100644 --- a/roles/8-mgmt-tools/tasks/main.yml +++ b/roles/8-mgmt-tools/tasks/main.yml @@ -6,23 +6,23 @@ - name: TRANSMISSION include_role: name: transmission - when: transmission_install + when: transmission_install and not (is_ubuntu_2404 or is_ubuntu_2410 or is_ubuntu_2504) # Also excludes is_linuxmint_22, for #3756 (whereas Debian 13 works great!) - name: AWSTATS include_role: name: awstats when: awstats_install - + +- name: MATOMO + include_role: + name: matomo + when: matomo_install + - name: MONIT include_role: name: monit when: monit_install -- name: MUNIN - include_role: - name: munin - when: munin_install - - name: PHPMYADMIN include_role: name: phpmyadmin diff --git a/roles/9-local-addons/tasks/main.yml b/roles/9-local-addons/tasks/main.yml index 54420a743..337a74445 100644 --- a/roles/9-local-addons/tasks/main.yml +++ b/roles/9-local-addons/tasks/main.yml @@ -3,16 +3,34 @@ - name: ...IS BEGINNING ==================================== meta: noop -# Is porting to Python 3 complete, and if so does this belong elsewhere? +- name: AZURACAST + include_role: + name: azuracast + when: azuracast_install + +# Porting to Python 3 is complete: does this belong elsewhere? - name: CAPTIVE PORTAL include_role: name: captiveportal when: captiveportal_install +# WARNING: Since March 2023, 32-bit RasPiOS can act as 64-bit on RPi 4 and +# RPi 400 (unlike RPi 3!) SEE: https://github.com/iiab/iiab/pull/3516 +- name: Run command 'dpkg --print-architecture' to identify OS architecture (CPU arch as revealed by ansible_architecture ~= ansible_machine is NO LONGER enough!) + command: dpkg --print-architecture + register: dpkg_arch + when: internetarchive_install + +- name: Explain bypassing of Internet Archive install if 32-bit OS + fail: # FORCE IT RED THIS ONCE! + msg: "BYPASSING INTERNET ARCHIVE PER https://github.com/iiab/iiab/issues/3641 -- 'dpkg --print-architecture' output for your OS: {{ dpkg_arch.stdout }}" + when: internetarchive_install and not dpkg_arch.stdout is search("64") + ignore_errors: True + - name: INTERNETARCHIVE include_role: name: internetarchive - when: internetarchive_install + when: internetarchive_install and dpkg_arch.stdout is search("64") - name: MINETEST include_role: @@ -37,12 +55,46 @@ name: pbx when: pbx_install -- name: "2021-06-27 TEMPORARY CODE TO INSTALL 'php-pear' UNTIL ADMIN CONSOLE DECLARES ITS OWN DEPENDENCY FOR: https://github.com/iiab/iiab-admin-console/blob/master/roles/cmdsrv/tasks/main.yml#L19" - package: - name: php-pear # WARNING: this also drags in 'php{{ php_version }}-xml' (also installed by MediaWiki, Nextcloud, roles/pbx's FreePBX, WordPress) AND 'php{{ php_version }}-cgi' (also installed by roles/pbx's FreePBX) - state: present + +- name: '2023-11-05 / TEMPORARY UNTIL ADMIN CONSOLE DECLARES ITS DEPENDENCY: Install MySQL (MariaDB) if admin_console_install (for setup-feedback and record_feedback.php)' + set_fact: + mysql_install: True + mysql_enabled: True when: admin_console_install +- name: '2023-11-05 / TEMPORARY UNTIL ADMIN CONSOLE DECLARES ITS DEPENDENCY: Install MySQL (MariaDB) if admin_console_install (for setup-feedback and record_feedback.php)' + include_role: + name: mysql + when: admin_console_install + +- name: '2023-11-05 / TEMPORARY UNTIL ADMIN CONSOLE DECLARES ITS DEPENDENCY: Install MySQL (MariaDB) if admin_console_install (for setup-feedback and record_feedback.php)' + fail: + msg: "Admin Console install cannot proceed, as MySQL / MariaDB is not installed." + when: admin_console_install and mysql_installed is undefined + + +# 2023-11-05: Moved from Stage 8, as it acts on mysql_installed (that might be set just above!) +- name: MUNIN + include_role: + name: munin + when: munin_install + + +- name: Read 'disk_used_a_priori' from /etc/iiab/iiab.ini + set_fact: + df1: "{{ lookup('ansible.builtin.ini', 'disk_used_a_priori', section='summary', file=iiab_ini_file) }}" + +- name: Record currently used disk space, to compare with original 'disk_used_a_priori' + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add ESTIMATED 'iiab_software_disk_usage = {{ df2.stdout|int - df1|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: summary + option: iiab_software_disk_usage + value: "{{ df2.stdout|int - df1|int }}" + - name: Recording STAGE 9 HAS COMPLETED ==================== lineinfile: path: "{{ iiab_env_file }}" diff --git a/roles/awstats/tasks/install.yml b/roles/awstats/tasks/install.yml index 905ef68e7..24a005c74 100644 --- a/roles/awstats/tasks/install.yml +++ b/roles/awstats/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: 'Install package: awstats' package: name: awstats @@ -83,7 +88,7 @@ # when: awstats_enabled and not is_debuntu - name: "Summarize logs up to now: /usr/bin/perl /usr/lib/cgi-bin/awstats.pl -config=schoolserver -update" - shell: /usr/bin/perl /usr/lib/cgi-bin/awstats.pl -config=schoolserver -update + command: /usr/bin/perl /usr/lib/cgi-bin/awstats.pl -config=schoolserver -update - name: Install /etc/nginx/cgi-bin.php from template template: @@ -93,6 +98,17 @@ # RECORD AWStats AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'awstats_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: awstats + option: awstats_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'awstats_installed: True'" set_fact: awstats_installed: True diff --git a/roles/awstats/tasks/main.yml b/roles/awstats/tasks/main.yml index 79615d71a..47ae7b247 100644 --- a/roles/awstats/tasks/main.yml +++ b/roles/awstats/tasks/main.yml @@ -19,27 +19,34 @@ quiet: yes -- name: Install AWStats if 'awstats_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: awstats_installed is undefined +- block: + - name: Install AWStats if 'awstats_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: awstats_installed is undefined -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + - name: Enable/Disable/Restart NGINX + include_tasks: nginx.yml + - name: Add 'awstats' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: awstats + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: AWStats + - option: description + value: '"AWStats (originally known as Advanced Web Statistics) is a package written in Perl which generates static or dynamic html summaries based upon web server logs."' + - option: awstats_install + value: "{{ awstats_install }}" + - option: awstats_enabled + value: "{{ awstats_enabled }}" -- name: Add 'awstats' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: awstats - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: AWStats - - option: description - value: '"AWStats (originally known as Advanced Web Statistics) is a package written in Perl which generates static or dynamic html summaries based upon web server logs."' - - option: awstats_install - value: "{{ awstats_install }}" - - option: awstats_enabled - value: "{{ awstats_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/awstats/templates/awstats.schoolserver.conf.j2 b/roles/awstats/templates/awstats.schoolserver.conf.j2 index 40816fef5..2a5e8802d 100644 --- a/roles/awstats/templates/awstats.schoolserver.conf.j2 +++ b/roles/awstats/templates/awstats.schoolserver.conf.j2 @@ -261,7 +261,7 @@ AllowToUpdateStatsFromBrowser=1 # 3 - Possible on CLI and CGI # Default: 2 # -AllowFullYearView=2 +AllowFullYearView=3 diff --git a/roles/azuracast/README.rst b/roles/azuracast/README.rst index 420bfb92d..24d1277da 100644 --- a/roles/azuracast/README.rst +++ b/roles/azuracast/README.rst @@ -1,19 +1,47 @@ -========== +================ AzuraCast README -========== +================ -This playbook adds `AzuraCast `_ to Internet-in-a-Box (IIAB) for network radio station functionality. With 'AzuraCast' you and your community can schedule podcasts, music, and even do live streaming of audio content. A variety of streaming formats are supported. +Install `AzuraCast `_ with your `Internet-in-a-Box (IIAB) `_ if you want a simple, self-hosted "web radio station" with a modern web UI/UX. You and your community can then schedule newscasts, podcasts, music, and even do live streaming of audio content (video streaming might also be possible in future!) -Please see AzuraCast's `screenshots `_. +As soon as you install AzuraCast with IIAB, it can stream MP3 files (and similar files) using `LiquidSoap `_ to help you schedule or randomize playback of MP3 songs (and similar). -As of 2019-08-04, this will only run on Ubuntu 18.04, and tentatively on Debian 10 "Buster" (`#1766 `_). Support for Raspberry Pi remains a goal for now β€” please if you can, consider helping us solve this critical challenge (`#1772 `_, `AzuraCast/AzuraCast#332 `_). +Please see AzuraCast's `screenshots `_ and `docs <./README.rst#azuracast-docs>`_. Community implementation examples: + +* https://twitter.com/internet_in_box/status/1564986581664014342 +* https://youtu.be/XfiFiOi46mk + +Optionally, live-streaming can also be made to work, e.g. if you install `Mixxx or BUTT `_ on your own. (If so, you have many options to configure streaming with `Icecast `_, `Shoutcast `_, etc.) + +Requirements +------------ + +AzuraCast recommends `2-to-4 GB RAM minimum `_. + +As of 2022-08-31, AzuraCast should run on Ubuntu 22.04 and **64-bit** Raspberry Pi OS: `#1772 `_, `AzuraCast/AzuraCast#332 `_, `PR #2946 `_ + +Other Linux distributions may also work, at your own risk, especially if Docker runs smoothly. + +NOTE: AzuraCast was designed to be installed *just once* on a fresh OS. So ``./runrole --reinstall azuracast`` is not supported in general. However, if you accidentally damage your AzuraCast software, IIAB has posted `technical tips <./tasks/install.yml>`_ *(use at your own risk!)* in case of emergency. Using It -------- -* Do a normal IIAB install (http://download.iiab.io), making sure to set both variables ``azuracast_install`` and ``azuracast_enabled`` to ``True`` when it prompts you to edit `/etc/iiab/local_vars.yml `_, as you begin the installation. -* When the IIAB software install completes, it will ask you to reboot, and AzuraCast's console will then be available at http://box.lan:10080 -* This console site will prompt you to complete AzuraCast's initial setup: user accounts, managing stations, radio streams, etc. +* Do a normal IIAB install (https://download.iiab.io), making sure to set both variables ``azuracast_install`` and ``azuracast_enabled`` to ``True`` when IIAB's installer prompts you to edit `/etc/iiab/local_vars.yml `_ +* When the IIAB software install completes, it will ask you to reboot, and AzuraCast's console will then be available at http://box.lan:12080 +* That console site will prompt you to complete AzuraCast's initial setup: user accounts, managing stations, radio streams, etc. * Finally, check out some `how-to videos `_ to learn to manage your own radio station! -Note: When creating a station using AzuraCast's console, its default streaming ports for ``station`` and ``autodj`` need to be in the `port range 10000-10100 `_. +NOTE: When creating a station using AzuraCast's console, its default streaming ports for ``station`` and ``autodj`` need to be in the `port range 10000-10499 `_ (ports 12080 and 12443 may also be required!) + +AzuraCast Docs +-------------- + +- https://docs.azuracast.com +- https://docs.azuracast.com/en/getting-started/installation/post-installation-steps +- https://docs.azuracast.com/en/getting-started/settings +- https://docs.azuracast.com/en/getting-started/updates (can *DAMAGE* AzuraCast as of 2022-09-28) +- https://docs.azuracast.com/en/user-guide/streaming-software +- https://docs.azuracast.com/en/user-guide/troubleshooting +- https://docs.azuracast.com/en/user-guide/logs +- https://docs.azuracast.com/en/administration/docker diff --git a/roles/azuracast/defaults/main.yml b/roles/azuracast/defaults/main.yml index 6e505649f..a3cd24908 100644 --- a/roles/azuracast/defaults/main.yml +++ b/roles/azuracast/defaults/main.yml @@ -1,15 +1,15 @@ -# A full-featured online radio station suite. -# Works on Ubuntu 18.04, Debian 9, 10. Uses docker +# A full-featured online radio station suite. Uses Docker. +# README: https://github.com/iiab/iiab/tree/master/roles/azuracast#readme # azuracast_install: False -# azuracast_enabled: False +# azuracast_enabled: False # This var is currently IGNORED -# azuracast_http_port: 10080 -# azuracast_https_port: 10443 +# azuracast_http_port: 12080 +# azuracast_https_port: 12443 -## AzuraCast needs many ports in the 8000:8100 range by default, but IIAB services -## conflict with those ports so this variable below sets a sane prefix. -## e.g. setting the below variable to 10 will result in port ranges 10000-10100 +## AzuraCast needs many ports in the 8000:8496 range by default, but IIAB +## services conflict, so this variable below sets a sane prefix. +## e.g. setting the below variable to 10 will result in port range 10000-10499 ## being reserved for AzuraCast: # azuracast_port_range_prefix: 10 diff --git a/roles/azuracast/templates/docker-compose.override.yml.j2 b/roles/azuracast/docker-compose.override.yml.j2.unused similarity index 100% rename from roles/azuracast/templates/docker-compose.override.yml.j2 rename to roles/azuracast/docker-compose.override.yml.j2.unused diff --git a/roles/azuracast/templates/env.j2 b/roles/azuracast/env.j2.unused similarity index 100% rename from roles/azuracast/templates/env.j2 rename to roles/azuracast/env.j2.unused diff --git a/roles/azuracast/tasks/install.yml b/roles/azuracast/tasks/install.yml index 9f1b1e2ab..bd25d96fb 100644 --- a/roles/azuracast/tasks/install.yml +++ b/roles/azuracast/tasks/install.yml @@ -1,23 +1,49 @@ +# 2022-09-29: './runrole --reinstall azuracast' is NOT supported! +# +# 1. But if you must, first completely uninstall Docker + WIPE AzuraCast data: +# +# apt purge docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-scan-plugin +# rm -rf /library/docker /var/lib/docker /var/lib/containerd +# +# Per https://docs.docker.com/engine/install/ubuntu/#uninstall-docker-engine +# +# 2. REBOOT to avoid later problems with 'systemctl status docker' -- if you +# don't reboot, Ansible will fail below when 'docker.sh install' fails to +# start docker.service -- likewise if you run './docker.sh install-docker' +# manually in /opt/azuracast. Either way, 'systemctl restart docker' won't +# work for ~2 minutes. (Rebooting avoids all these hassles!) +# +# 3. Just FYI the Docker install process will rebuild its 11 core directories +# in /var/lib/docker -> /library/docker: (as 'docker.sh install' begins) +# +# buildkit containers image network overlay2 plugins runtimes swarm tmp trust volumes +# +# 4. Just FYI both MySQL passwords (MYSQL_PASSWORD & MYSQL_ROOT_PASSWORD) will +# be WIPED from /opt/azuracast/azuracast.env (and new passwords +# auto-generated below, for use inside AzuraCast's Docker container). +# +# 5. Run './runrole --reinstall azuracast' in /opt/iiab/iiab + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: AzuraCast - Make config directory {{ azuracast_host_dir }} - file: + file: path: "{{ azuracast_host_dir }}" state: directory - name: AzuraCast - Install {{ azuracast_host_dir }}/.env from template template: - src: env.j2 + src: prod.env.j2 dest: "{{ azuracast_host_dir }}/.env" - #owner: root - #group: root - mode: 0644 -- name: AzuraCast - Install {{ azuracast_host_dir }}/docker-compose.override.yml from template +- name: AzuraCast - Install {{ azuracast_host_dir }}/azuracast.env for altered ports template: - src: docker-compose.override.yml.j2 - dest: "{{ azuracast_host_dir }}/docker-compose.override.yml" - #owner: root - #group: root - mode: 0644 + src: azuracast.env.j2 + dest: "{{ azuracast_host_dir }}/azuracast.env" - name: AzuraCast - Download {{ docker_sh_url }} to {{ azuracast_host_dir }} get_url: @@ -26,13 +52,6 @@ mode: 0755 timeout: "{{ download_timeout }}" -- name: AzuraCast - Download AzuraCast's docker-compose.yml sample from GitHub to {{ azuracast_host_dir }} - get_url: - url: "{{ docker_compose_url }}" - dest: "{{ azuracast_host_dir }}/docker-compose.yml" - mode: 0755 - timeout: "{{ download_timeout }}" - #- name: AzuraCast - Make changes to docker.sh script so it runs headless # lineinfile: # path: "{{ azuracast_host_dir }}/docker.sh" @@ -40,27 +59,45 @@ # line: "\\1reply='Y'" # backrefs: yes +# 2022-09-28: https://docs.azuracast.com/en/getting-started/installation/docker +# (& testing) confirm this is done automatically by 'docker.sh install' below. +# +# - name: AzuraCast - Download AzuraCast's docker-compose.yml sample from GitHub to {{ azuracast_host_dir }} +# get_url: +# url: "{{ docker_compose_url }}" +# dest: "{{ azuracast_host_dir }}/docker-compose.yml" +# timeout: "{{ download_timeout }}" + +#- name: AzuraCast - Install {{ azuracast_host_dir }}/docker-compose.override.yml from template +# template: +# src: docker-compose.override.yml.j2 +# dest: "{{ azuracast_host_dir }}/docker-compose.override.yml" + +#- name: Change default port number range 8xxx:8xxx to {{ azuracast_port_range_prefix }}xxx:{{ azuracast_port_range_prefix }}xxx icecast-stations in docker-compose.yml +# replace: +# path: "{{ azuracast_host_dir }}/docker-compose.yml" +# regexp: "^( *- \\')8([0-9]{3})\\:8([0-9]{3}\\'.*)$" +# replace: "\\g<1>{{ azuracast_port_range_prefix }}\\g<2>:{{ azuracast_port_range_prefix }}\\g<3>" + - name: AzuraCast - Make directory {{ docker_container_dir }} - file: + file: path: "{{ docker_container_dir }}" state: directory - + - name: AzuraCast - Symlink /var/lib/docker -> {{ docker_container_dir }} file: src: "{{ docker_container_dir }}" path: /var/lib/docker - state: link + state: link -- name: Change default port number range 8xxx:8xxx to {{ azuracast_port_range_prefix }}xxx:{{ azuracast_port_range_prefix }}xxx icecast-stations in docker-compose.yml - replace: - path: "{{ azuracast_host_dir }}/docker-compose.yml" - regexp: "^( *- \\')8([0-9]{3})\\:8([0-9]{3}\\'.*)$" - replace: "\\g<1>{{ azuracast_port_range_prefix }}\\g<2>:{{ azuracast_port_range_prefix }}\\g<3>" - -- name: AzuraCast - Setup for stable channel install - shell: "yes 'Y' | /bin/bash docker.sh setup-release" - args: - chdir: "{{ azuracast_host_dir }}" +# 2022-09-28: "yes 'Y'" toggled whatever it found in /opt/azuracast/.env (e.g. +# AZURACAST_VERSION=stable from templates/prod.env.j2) to the opposite (e.g. +# AZURACAST_VERSION=latest). Let's not modify /opt/azuracast/.env unless nec! +# +# - name: AzuraCast - Setup for stable channel install +# shell: "yes 'Y' | /bin/bash docker.sh setup-release" +# args: +# chdir: "{{ azuracast_host_dir }}" - name: AzuraCast - Run the installer shell: "yes '' | /bin/bash docker.sh install" @@ -70,6 +107,17 @@ # RECORD AzuraCast AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'azuracast_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: azuracast + option: azuracast_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'azuracast_installed: True'" set_fact: azuracast_installed: True diff --git a/roles/azuracast/tasks/main.yml b/roles/azuracast/tasks/main.yml index ef9c28914..6bc11b878 100644 --- a/roles/azuracast/tasks/main.yml +++ b/roles/azuracast/tasks/main.yml @@ -19,25 +19,32 @@ quiet: yes -- name: Install AzuraCast if 'azuracast_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: azuracast_installed is undefined +- block: + - name: Install AzuraCast if 'azuracast_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: azuracast_installed is undefined -# TODO figure out what to turn off/on for AzuraCast -# - include_tasks: enable-or-disable.yml + # TODO figure out what to turn off/on for AzuraCast + # - include_tasks: enable-or-disable.yml + - name: Add 'azuracast' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: azuracast + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: azuracast + - option: description + value: '"AzuraCast is simple, self-hosted web radio. Use it to schedule student newscasts, podcasts, music (e.g. MP3''s and similar) and even do live-streaming."' + - option: enabled + value: "{{ azuracast_enabled }}" -- name: Add 'azuracast' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: azuracast - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: azuracast - - option: description - value: '"AzuraCast is a self-hosted, all-in-one radio station platform. Use AzuraCast to schedule podcasts, music, and even do live streaming of audio content. A variety of streaming formats are supported."' - - option: enabled - value: "{{ azuracast_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/azuracast/templates/azuracast-nginx.conf.j2.unused b/roles/azuracast/templates/azuracast-nginx.conf.j2.unused new file mode 100644 index 000000000..33ae25476 --- /dev/null +++ b/roles/azuracast/templates/azuracast-nginx.conf.j2.unused @@ -0,0 +1,16 @@ +# work in progress might never be ready as the web interface has setting that would need to match +location /azuracast/ + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Script-Name /azureacast; + proxy_pass http://127.0.0.1:{{ azuracast_http_port }}; +} + +location /radio/ { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Script-Name /radio; + proxy_pass http://127.0.0.1:{{ azuracast_http_port }}; +} diff --git a/roles/azuracast/templates/azuracast.env.j2 b/roles/azuracast/templates/azuracast.env.j2 new file mode 100644 index 000000000..313fffc59 --- /dev/null +++ b/roles/azuracast/templates/azuracast.env.j2 @@ -0,0 +1,155 @@ +# IIAB version for altered ports +# +# AzuraCast Customization +# + +# The application environment. +# Valid options: production, development, testing +APPLICATION_ENV=production + +# Manually modify the logging level. +# This allows you to log debug-level errors temporarily (for problem-solving) or reduce +# the volume of logs that are produced by your installation, without needing to modify +# whether your installation is a production or development instance. +# Valid options: debug, info, notice, warning, error, critical, alert, emergency +# LOG_LEVEL=notice + +# Enable the composer "merge" functionality to combine the main application's +# composer.json file with any plugins' composer files. +# This can have performance implications, so you should only use it if +# you use one or more plugins with their own Composer dependencies. +# Valid options: true, false +COMPOSER_PLUGIN_MODE=false + +# The minimum port number to use when automatically assigning ports to a station. +# By default, this matches the first forwarded port on the "stations" container. +# You can modify this variable if your station port range is different. +# Be sure to also forward the necessary ports via `docker-compose.yml` +# (and nginx, if you want to use the built-in port-80/443 proxy)! +AUTO_ASSIGN_PORT_MIN="{{ azuracast_port_range_prefix }}000" + +# The maximum port number to use when automatically assigning ports to a station. +# See AUTO_ASSIGN_PORT_MIN. +AUTO_ASSIGN_PORT_MAX="{{ azuracast_port_range_prefix }}499" + +# +# Database Configuration +# -- +# Once the database has been installed, DO NOT CHANGE these values! +# + +# The host to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: mariadb +MYSQL_HOST=mariadb + +# The port to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: 3306 +MYSQL_PORT=3306 + +# The username AzuraCast will use to connect to the database. +# Default: azuracast +MYSQL_USER=azuracast + +# The password AzuraCast will use to connect to the database. +# By default, the database is not exposed to the Internet at all and this is only +# an internal password used by the service itself. +# Default: azur4c457 +MYSQL_PASSWORD=azur4c457 + +# The name of the AzuraCast database. +# Default: azuracast +MYSQL_DATABASE=azuracast + +# Automatically generate a random root password upon the first database spin-up. +# This password will be visible in the mariadb container's logs. +# Default: yes +MYSQL_RANDOM_ROOT_PASSWORD=yes + +# Log slower queries for the purpose of diagnosing issues. Only turn this on when +# you need to, by uncommenting this and switching it to 1. +# To read the slow query log once enabled, run: +# docker-compose exec mariadb slow_queries +# Default: 0 +MYSQL_SLOW_QUERY_LOG=0 + +# Set the amount of allowed connections to the database. This value should be increased +# if you are seeing the `Too many connections` error in the logs. +# Default: 100 +MYSQL_MAX_CONNECTIONS=100 + +# +# Redis Configuration +# +# Uncomment these fields if you are using a third-party Redis host instead of the one provided with AzuraCast. +# Do not modify these fields if you are using the standard AzuraCast Redis host. +# + +# Whether to use the Redis cache; if set to false, will disable Redis and use flatfile cache instead. +# Default: true +# ENABLE_REDIS=true + +# Name of the Redis host. +# Default: redis +# REDIS_HOST=redis + +# Port to connect to on the Redis host. +# Default: 6379 +# REDIS_PORT=6379 + +# Database index to use on the Redis host. +# Default: 1 +# REDIS_DB=1 + +# +# Advanced Configuration +# + +# PHP's maximum POST body size and max upload filesize. +# PHP_MAX_FILE_SIZE=25M + +# PHP's maximum memory limit. +# PHP_MEMORY_LIMIT=128M + +# PHP's maximum script execution time (in seconds). +# PHP_MAX_EXECUTION_TIME=30 + +# The maximum execution time (and lock timeout) for the 15-second, 1-minute and 5-minute synchronization tasks. +# SYNC_SHORT_EXECUTION_TIME=600 + +# The maximum execution time (and lock timeout) for the 1-hour synchronization task. +# SYNC_LONG_EXECUTION_TIME=1800 + +# Maximum number of PHP-FPM worker processes to spawn. +# PHP_FPM_MAX_CHILDREN=5 + +# +# PHP-SPX profiling extension Configuration +# +# These environment variables allow you to enable and configure the PHP-SPX profiling extension +# which can be helpful when debugging resource issues in AzuraCast. +# +# The profiling dashboard can be accessed by visting https://yourdomain.com/?SPX_KEY=dev&SPX_UI_URI=/ +# If you change the PROFILING_EXTENSION_HTTP_KEY variable change the value for SPX_KEY accordingly. +# + +# Enable the profiling extension. +# Profiling data can be viewed by visiting http://your-azuracast-site/?SPX_KEY=dev&SPX_UI_URI=/ +# Default: 0 +# PROFILING_EXTENSION_ENABLED=0 + +# Profile ALL requests made to this account. +# This will have significant performance impact on your installation and should only be used in test circumstances. +# Default: 0 +# PROFILING_EXTENSION_ALWAYS_ON=0 + +# Configure the value for the SPX_KEY parameter needed to access the profiling dashboard +# Default: dev +# PROFILING_EXTENSION_HTTP_KEY=dev + +# Configure the IP whitelist for the profiling dashboard +# By default only localhost is allowed to access this page. +# Uncomment this line to enable access for you. +# Default: 127.0.0.1 +# PROFILING_EXTENSION_HTTP_IP_WHITELIST=* diff --git a/roles/azuracast/templates/azuracast.sample.env b/roles/azuracast/templates/azuracast.sample.env new file mode 100644 index 000000000..bc9ffc204 --- /dev/null +++ b/roles/azuracast/templates/azuracast.sample.env @@ -0,0 +1,155 @@ +# https://github.com/AzuraCast/AzuraCast/blob/main/azuracast.sample.env +# +# AzuraCast Customization +# + +# The application environment. +# Valid options: production, development, testing +APPLICATION_ENV=production + +# Manually modify the logging level. +# This allows you to log debug-level errors temporarily (for problem-solving) or reduce +# the volume of logs that are produced by your installation, without needing to modify +# whether your installation is a production or development instance. +# Valid options: debug, info, notice, warning, error, critical, alert, emergency +# LOG_LEVEL=notice + +# Enable the composer "merge" functionality to combine the main application's +# composer.json file with any plugins' composer files. +# This can have performance implications, so you should only use it if +# you use one or more plugins with their own Composer dependencies. +# Valid options: true, false +COMPOSER_PLUGIN_MODE=false + +# The minimum port number to use when automatically assigning ports to a station. +# By default, this matches the first forwarded port on the "stations" container. +# You can modify this variable if your station port range is different. +# Be sure to also forward the necessary ports via `docker-compose.yml` +# (and nginx, if you want to use the built-in port-80/443 proxy)! +AUTO_ASSIGN_PORT_MIN=8000 + +# The maximum port number to use when automatically assigning ports to a station. +# See AUTO_ASSIGN_PORT_MIN. +AUTO_ASSIGN_PORT_MAX=8499 + +# +# Database Configuration +# -- +# Once the database has been installed, DO NOT CHANGE these values! +# + +# The host to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: mariadb +MYSQL_HOST=mariadb + +# The port to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: 3306 +MYSQL_PORT=3306 + +# The username AzuraCast will use to connect to the database. +# Default: azuracast +MYSQL_USER=azuracast + +# The password AzuraCast will use to connect to the database. +# By default, the database is not exposed to the Internet at all and this is only +# an internal password used by the service itself. +# Default: azur4c457 +MYSQL_PASSWORD=azur4c457 + +# The name of the AzuraCast database. +# Default: azuracast +MYSQL_DATABASE=azuracast + +# Automatically generate a random root password upon the first database spin-up. +# This password will be visible in the mariadb container's logs. +# Default: yes +MYSQL_RANDOM_ROOT_PASSWORD=yes + +# Log slower queries for the purpose of diagnosing issues. Only turn this on when +# you need to, by uncommenting this and switching it to 1. +# To read the slow query log once enabled, run: +# docker-compose exec mariadb slow_queries +# Default: 0 +MYSQL_SLOW_QUERY_LOG=0 + +# Set the amount of allowed connections to the database. This value should be increased +# if you are seeing the `Too many connections` error in the logs. +# Default: 100 +MYSQL_MAX_CONNECTIONS=100 + +# +# Redis Configuration +# +# Uncomment these fields if you are using a third-party Redis host instead of the one provided with AzuraCast. +# Do not modify these fields if you are using the standard AzuraCast Redis host. +# + +# Whether to use the Redis cache; if set to false, will disable Redis and use flatfile cache instead. +# Default: true +# ENABLE_REDIS=true + +# Name of the Redis host. +# Default: redis +# REDIS_HOST=redis + +# Port to connect to on the Redis host. +# Default: 6379 +# REDIS_PORT=6379 + +# Database index to use on the Redis host. +# Default: 1 +# REDIS_DB=1 + +# +# Advanced Configuration +# + +# PHP's maximum POST body size and max upload filesize. +# PHP_MAX_FILE_SIZE=25M + +# PHP's maximum memory limit. +# PHP_MEMORY_LIMIT=128M + +# PHP's maximum script execution time (in seconds). +# PHP_MAX_EXECUTION_TIME=30 + +# The maximum execution time (and lock timeout) for the 15-second, 1-minute and 5-minute synchronization tasks. +# SYNC_SHORT_EXECUTION_TIME=600 + +# The maximum execution time (and lock timeout) for the 1-hour synchronization task. +# SYNC_LONG_EXECUTION_TIME=1800 + +# Maximum number of PHP-FPM worker processes to spawn. +# PHP_FPM_MAX_CHILDREN=5 + +# +# PHP-SPX profiling extension Configuration +# +# These environment variables allow you to enable and configure the PHP-SPX profiling extension +# which can be helpful when debugging resource issues in AzuraCast. +# +# The profiling dashboard can be accessed by visting https://yourdomain.com/?SPX_KEY=dev&SPX_UI_URI=/ +# If you change the PROFILING_EXTENSION_HTTP_KEY variable change the value for SPX_KEY accordingly. +# + +# Enable the profiling extension. +# Profiling data can be viewed by visiting http://your-azuracast-site/?SPX_KEY=dev&SPX_UI_URI=/ +# Default: 0 +# PROFILING_EXTENSION_ENABLED=0 + +# Profile ALL requests made to this account. +# This will have significant performance impact on your installation and should only be used in test circumstances. +# Default: 0 +# PROFILING_EXTENSION_ALWAYS_ON=0 + +# Configure the value for the SPX_KEY parameter needed to access the profiling dashboard +# Default: dev +# PROFILING_EXTENSION_HTTP_KEY=dev + +# Configure the IP whitelist for the profiling dashboard +# By default only localhost is allowed to access this page. +# Uncomment this line to enable access for you. +# Default: 127.0.0.1 +# PROFILING_EXTENSION_HTTP_IP_WHITELIST=* diff --git a/roles/azuracast/templates/prod.env.j2 b/roles/azuracast/templates/prod.env.j2 new file mode 100644 index 000000000..58fc11d3e --- /dev/null +++ b/roles/azuracast/templates/prod.env.j2 @@ -0,0 +1,54 @@ +# This file was automatically generated by AzuraCast and modified for IIAB +# You can modify it as necessary. To apply changes, restart the Docker containers. +# Remove the leading "#" symbol from lines to uncomment them. + +# (Docker Compose) All Docker containers are prefixed by this name. Do not change this after installation. +# Default: azuracast +COMPOSE_PROJECT_NAME=azuracast + +# (Docker Compose) The amount of time to wait before a Docker Compose operation fails. Increase this on lower performance computers. +# Default: 300 +COMPOSE_HTTP_TIMEOUT=300 + +# Release Channel +# Valid options: latest, stable +# Default: latest +AZURACAST_VERSION=stable + +NGINX_TIMEOUT=1800 +# HTTP Port +# The main port AzuraCast listens to for insecure HTTP connections. +# Default: 80 +AZURACAST_HTTP_PORT={{ azuracast_http_port }} + +# HTTPS Port +# The main port AzuraCast listens to for secure HTTPS connections. +# Default: 443 +AZURACAST_HTTPS_PORT={{ azuracast_https_port }} + +# SFTP Port +# The port AzuraCast listens to for SFTP file management connections. +# Default: 2022 +AZURACAST_SFTP_PORT=2022 + +# Station Ports +# The ports AzuraCast should listen to for station broadcasts and incoming DJ +# connections. +# Default: 8000,8005,8006,8010,8015,8016,8020,8025,8026,8030,8035,8036,8040,8045,8046,8050,8055,8056,8060,8065,8066,8070,8075,8076,8090,8095,8096,8100,8105,8106,8110,8115,8116,8120,8125,8126,8130,8135,8136,8140,8145,8146,8150,8155,8156,8160,8165,8166,8170,8175,8176,8180,8185,8186,8190,8195,8196,8200,8205,8206,8210,8215,8216,8220,8225,8226,8230,8235,8236,8240,8245,8246,8250,8255,8256,8260,8265,8266,8270,8275,8276,8280,8285,8286,8290,8295,8296,8300,8305,8306,8310,8315,8316,8320,8325,8326,8330,8335,8336,8340,8345,8346,8350,8355,8356,8360,8365,8366,8370,8375,8376,8380,8385,8386,8390,8395,8396,8400,8405,8406,8410,8415,8416,8420,8425,8426,8430,8435,8436,8440,8445,8446,8450,8455,8456,8460,8465,8466,8470,8475,8476,8480,8485,8486,8490,8495,8496 +AZURACAST_STATION_PORTS=10000,10005,10006,10010,10015,10016,10020,10025,10026,10030,10035,10036,10040,10045,10046,10050,10055,10056,10060,10065,10066,10070,10075,10076,10080,10085,10086,10090,10095,10096,10100,10105,10106,10110,10115,10116,10120,10125,10126,10130,10135,10136,10140,10145,10146,10150,10155,10156,10160,10165,10166,10170,10175,10176,10180,10185,10186,10190,10195,10196,10200,10205,10206,10210,10215,10216,10220,10225,10226,10230,10235,10236,10240,10245,10246,10250,10255,10256,10260,10265,10266,10270,10275,10276,10280,10285,10286,10290,10295,10296,10300,10305,10306,10310,10315,10316,10320,10325,10326,10330,10335,10336,10340,10345,10346,10350,10355,10356,10360,10365,10366,10370,10375,10376,10380,10385,10386,10390,10395,10396,10400,10405,10406,10410,10415,10416,10420,10425,10426,10430,10435,10436,10440,10445,10446,10450,10455,10456,10460,10465,10466,10470,10475,10476,10480,10485,10486,10490,10495,10496 + +# Docker User UID +# Set the UID of the user running inside the Docker containers. Matching this +# with your host UID can fix permission issues. +# Default: 1000 +AZURACAST_PUID=1000 + +# Docker User GID +# Set the GID of the user running inside the Docker containers. Matching this +# with your host GID can fix permission issues. +# Default: 1000 +AZURACAST_PGID=1000 + +# Advanced: Use Privileged Docker Settings +# Default: true +AZURACAST_COMPOSE_PRIVILEGED=true diff --git a/roles/azuracast/upstream/azuracast.sample.env b/roles/azuracast/upstream/azuracast.sample.env new file mode 100644 index 000000000..225b0fb4e --- /dev/null +++ b/roles/azuracast/upstream/azuracast.sample.env @@ -0,0 +1,161 @@ +# +# AzuraCast Customization +# + +# The application environment. +# Valid options: production, development, testing +APPLICATION_ENV=production + +# Manually modify the logging level. +# This allows you to log debug-level errors temporarily (for problem-solving) or reduce +# the volume of logs that are produced by your installation, without needing to modify +# whether your installation is a production or development instance. +# Valid options: debug, info, notice, warning, error, critical, alert, emergency +# LOG_LEVEL=notice + +# Enable the composer "merge" functionality to combine the main application's +# composer.json file with any plugins' composer files. +# This can have performance implications, so you should only use it if +# you use one or more plugins with their own Composer dependencies. +# Valid options: true, false +COMPOSER_PLUGIN_MODE=false + +# The minimum port number to use when automatically assigning ports to a station. +# By default, this matches the first forwarded port on the "stations" container. +# You can modify this variable if your station port range is different. +# Be sure to also forward the necessary ports via `docker-compose.yml` +# (and nginx, if you want to use the built-in port-80/443 proxy)! +AUTO_ASSIGN_PORT_MIN=8000 + +# The maximum port number to use when automatically assigning ports to a station. +# See AUTO_ASSIGN_PORT_MIN. +AUTO_ASSIGN_PORT_MAX=8499 + +# This allows you to debug Slim Application Errors you may encounter +# By default, this is disabled to prevent users from seeing privileged information +# Please report any Slim Application Error logs to the development team on GitHub +# Valid options: true, false +SHOW_DETAILED_ERRORS=false + + +# +# Database Configuration +# -- +# Once the database has been installed, DO NOT CHANGE these values! +# + +# The host to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: localhost +# MYSQL_HOST=localhost + +# The port to connect to. Leave this as the default value unless you're connecting +# to an external database server. +# Default: 3306 +# MYSQL_PORT=3306 + +# The username AzuraCast will use to connect to the database. +# Default: azuracast +# MYSQL_USER=azuracast + +# The password AzuraCast will use to connect to the database. +# By default, the database is not exposed to the Internet at all and this is only +# an internal password used by the service itself. +# Default: azur4c457 +MYSQL_PASSWORD=azur4c457 + +# The name of the AzuraCast database. +# Default: azuracast +# MYSQL_DATABASE=azuracast + +# Automatically generate a random root password upon the first database spin-up. +# This password will be visible in the mariadb container's logs. +# Default: yes +MYSQL_RANDOM_ROOT_PASSWORD=yes + +# Log slower queries for the purpose of diagnosing issues. Only turn this on when +# you need to, by uncommenting this and switching it to 1. +# To read the slow query log once enabled, run: +# docker-compose exec mariadb slow_queries +# Default: 0 +# MYSQL_SLOW_QUERY_LOG=0 + +# Set the amount of allowed connections to the database. This value should be increased +# if you are seeing the `Too many connections` error in the logs. +# Default: 100 +# MYSQL_MAX_CONNECTIONS=100 + +# +# Redis Configuration +# +# Uncomment these fields if you are using a third-party Redis host instead of the one provided with AzuraCast. +# Do not modify these fields if you are using the standard AzuraCast Redis host. +# + +# Whether to use the Redis cache; if set to false, will disable Redis and use flatfile cache instead. +# Default: true +# ENABLE_REDIS=true + +# Name of the Redis host. +# Default: localhost +# REDIS_HOST=localhost + +# Port to connect to on the Redis host. +# Default: 6379 +# REDIS_PORT=6379 + +# Database index to use on the Redis host. +# Default: 1 +# REDIS_DB=1 + +# +# Advanced Configuration +# + +# PHP's maximum POST body size and max upload filesize. +# PHP_MAX_FILE_SIZE=25M + +# PHP's maximum memory limit. +# PHP_MEMORY_LIMIT=128M + +# PHP's maximum script execution time (in seconds). +# PHP_MAX_EXECUTION_TIME=30 + +# The maximum execution time (and lock timeout) for the 15-second, 1-minute and 5-minute synchronization tasks. +# SYNC_SHORT_EXECUTION_TIME=600 + +# The maximum execution time (and lock timeout) for the 1-hour synchronization task. +# SYNC_LONG_EXECUTION_TIME=1800 + +# Maximum number of PHP-FPM worker processes to spawn. +# PHP_FPM_MAX_CHILDREN=5 + +# +# PHP-SPX profiling extension Configuration +# +# These environment variables allow you to enable and configure the PHP-SPX profiling extension +# which can be helpful when debugging resource issues in AzuraCast. +# +# The profiling dashboard can be accessed by visting https://yourdomain.com/?SPX_KEY=dev&SPX_UI_URI=/ +# If you change the PROFILING_EXTENSION_HTTP_KEY variable change the value for SPX_KEY accordingly. +# + +# Enable the profiling extension. +# Profiling data can be viewed by visiting http://your-azuracast-site/?SPX_KEY=dev&SPX_UI_URI=/ +# Default: 0 +# PROFILING_EXTENSION_ENABLED=0 + +# Profile ALL requests made to this account. +# This will have significant performance impact on your installation and should only be used in test circumstances. +# Default: 0 +# PROFILING_EXTENSION_ALWAYS_ON=0 + +# Configure the value for the SPX_KEY parameter needed to access the profiling dashboard +# Default: dev +# PROFILING_EXTENSION_HTTP_KEY=dev + +# Configure the IP whitelist for the profiling dashboard +# By default only localhost is allowed to access this page. +# Uncomment this line to enable access for you. +# Default: 127.0.0.1 +# PROFILING_EXTENSION_HTTP_IP_WHITELIST=* diff --git a/roles/azuracast/upstream/docker-compose.sample.yml b/roles/azuracast/upstream/docker-compose.sample.yml new file mode 100644 index 000000000..3c3759957 --- /dev/null +++ b/roles/azuracast/upstream/docker-compose.sample.yml @@ -0,0 +1,214 @@ +# +# AzuraCast Docker Compose Configuration File +# +# When updating, you will be prompted to replace this file with a new +# version; you should do this whenever possible to take advantage of +# new updates. +# +# If you need to customize this file, you can create a new file named: +# docker-compose.override.yml +# with any changes you need to make. +# + +services: + web: + container_name: azuracast + image: "ghcr.io/azuracast/azuracast:${AZURACAST_VERSION:-latest}" + # Want to customize the HTTP/S ports? Follow the instructions here: + # https://docs.azuracast.com/en/administration/docker#using-non-standard-ports + ports: + - '${AZURACAST_HTTP_PORT:-80}:80' + - '${AZURACAST_HTTPS_PORT:-443}:443' + - '${AZURACAST_SFTP_PORT:-2022}:2022' + # This default mapping is the outgoing and incoming ports for the first 50 stations. + # You can override this port mapping in your own docker-compose.override.yml file. + # For instructions, see: + # https://docs.azuracast.com/en/administration/docker#expanding-the-station-port-range + - '8000:8000' + - '8005:8005' + - '8006:8006' + - '8010:8010' + - '8015:8015' + - '8016:8016' + - '8020:8020' + - '8025:8025' + - '8026:8026' + - '8030:8030' + - '8035:8035' + - '8036:8036' + - '8040:8040' + - '8045:8045' + - '8046:8046' + - '8050:8050' + - '8055:8055' + - '8056:8056' + - '8060:8060' + - '8065:8065' + - '8066:8066' + - '8070:8070' + - '8075:8075' + - '8076:8076' + - '8090:8090' + - '8095:8095' + - '8096:8096' + - '8100:8100' + - '8105:8105' + - '8106:8106' + - '8110:8110' + - '8115:8115' + - '8116:8116' + - '8120:8120' + - '8125:8125' + - '8126:8126' + - '8130:8130' + - '8135:8135' + - '8136:8136' + - '8140:8140' + - '8145:8145' + - '8146:8146' + - '8150:8150' + - '8155:8155' + - '8156:8156' + - '8160:8160' + - '8165:8165' + - '8166:8166' + - '8170:8170' + - '8175:8175' + - '8176:8176' + - '8180:8180' + - '8185:8185' + - '8186:8186' + - '8190:8190' + - '8195:8195' + - '8196:8196' + - '8200:8200' + - '8205:8205' + - '8206:8206' + - '8210:8210' + - '8215:8215' + - '8216:8216' + - '8220:8220' + - '8225:8225' + - '8226:8226' + - '8230:8230' + - '8235:8235' + - '8236:8236' + - '8240:8240' + - '8245:8245' + - '8246:8246' + - '8250:8250' + - '8255:8255' + - '8256:8256' + - '8260:8260' + - '8265:8265' + - '8266:8266' + - '8270:8270' + - '8275:8275' + - '8276:8276' + - '8280:8280' + - '8285:8285' + - '8286:8286' + - '8290:8290' + - '8295:8295' + - '8296:8296' + - '8300:8300' + - '8305:8305' + - '8306:8306' + - '8310:8310' + - '8315:8315' + - '8316:8316' + - '8320:8320' + - '8325:8325' + - '8326:8326' + - '8330:8330' + - '8335:8335' + - '8336:8336' + - '8340:8340' + - '8345:8345' + - '8346:8346' + - '8350:8350' + - '8355:8355' + - '8356:8356' + - '8360:8360' + - '8365:8365' + - '8366:8366' + - '8370:8370' + - '8375:8375' + - '8376:8376' + - '8380:8380' + - '8385:8385' + - '8386:8386' + - '8390:8390' + - '8395:8395' + - '8396:8396' + - '8400:8400' + - '8405:8405' + - '8406:8406' + - '8410:8410' + - '8415:8415' + - '8416:8416' + - '8420:8420' + - '8425:8425' + - '8426:8426' + - '8430:8430' + - '8435:8435' + - '8436:8436' + - '8440:8440' + - '8445:8445' + - '8446:8446' + - '8450:8450' + - '8455:8455' + - '8456:8456' + - '8460:8460' + - '8465:8465' + - '8466:8466' + - '8470:8470' + - '8475:8475' + - '8476:8476' + - '8480:8480' + - '8485:8485' + - '8486:8486' + - '8490:8490' + - '8495:8495' + - '8496:8496' + env_file: azuracast.env + environment: + LANG: ${LANG:-en_US.UTF-8} + AZURACAST_DC_REVISION: 14 + AZURACAST_VERSION: ${AZURACAST_VERSION:-latest} + AZURACAST_SFTP_PORT: ${AZURACAST_SFTP_PORT:-2022} + NGINX_TIMEOUT: ${NGINX_TIMEOUT:-1800} + LETSENCRYPT_HOST: ${LETSENCRYPT_HOST:-} + LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL:-} + PUID: ${AZURACAST_PUID:-1000} + PGID: ${AZURACAST_PGID:-1000} + volumes: + - www_uploads:/var/azuracast/uploads + - station_data:/var/azuracast/stations + - shoutcast2_install:/var/azuracast/servers/shoutcast2 + - stereo_tool_install:/var/azuracast/servers/stereo_tool + - geolite_install:/var/azuracast/geoip + - sftpgo_data:/var/azuracast/sftpgo/persist + - backups:/var/azuracast/backups + - acme:/var/azuracast/acme + - db_data:/var/lib/mysql + restart: unless-stopped + ulimits: &default-ulimits + nofile: + soft: 65536 + hard: 65536 + logging: &default-logging + options: + max-size: "1m" + max-file: "5" + +volumes: + db_data: { } + acme: { } + shoutcast2_install: { } + stereo_tool_install: { } + geolite_install: { } + sftpgo_data: { } + station_data: { } + www_uploads: { } + backups: { } diff --git a/roles/azuracast/upstream/docker.sh b/roles/azuracast/upstream/docker.sh new file mode 100755 index 000000000..dfa1c2b81 --- /dev/null +++ b/roles/azuracast/upstream/docker.sh @@ -0,0 +1,840 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2145,SC2178,SC2120,SC2162 + +# Functions to manage .env files +__dotenv= +__dotenv_file= +__dotenv_cmd=.env + +.env() { + REPLY=() + [[ $__dotenv_file || ${1-} == -* ]] || .env.--file .env || return + if declare -F -- ".env.${1-}" >/dev/null; then + .env."$@" + return + fi + return 64 +} + +.env.-f() { .env.--file "$@"; } + +.env.get() { + .env::arg "get requires a key" "$@" && + [[ "$__dotenv" =~ ^(.*(^|$'\n'))([ ]*)"$1="(.*)$ ]] && + REPLY=${BASH_REMATCH[4]%%$'\n'*} && REPLY=${REPLY%"${REPLY##*[![:space:]]}"} +} + +.env.parse() { + local line key + while IFS= read -r line; do + line=${line#"${line%%[![:space:]]*}"} # trim leading whitespace + line=${line%"${line##*[![:space:]]}"} # trim trailing whitespace + if [[ ! "$line" || "$line" == '#'* ]]; then continue; fi + if (($#)); then + for key; do + if [[ $key == "${line%%=*}" ]]; then + REPLY+=("$line") + break + fi + done + else + REPLY+=("$line") + fi + done <<<"$__dotenv" + ((${#REPLY[@]})) +} + +.env.export() { ! .env.parse "$@" || export "${REPLY[@]}"; } + +.env.set() { + .env::file load || return + local key saved=$__dotenv + while (($#)); do + key=${1#+} + key=${key%%=*} + if .env.get "$key"; then + REPLY=() + if [[ $1 == +* ]]; then + shift + continue # skip if already found + elif [[ $1 == *=* ]]; then + __dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[3]}$1$'\n'${BASH_REMATCH[4]#*$'\n'} + else + __dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[4]#*$'\n'} + continue # delete all occurrences + fi + elif [[ $1 == *=* ]]; then + __dotenv+="${1#+}"$'\n' + fi + shift + done + [[ $__dotenv == "$saved" ]] || .env::file save +} + +.env.puts() { echo "${1-}" >>"$__dotenv_file" && __dotenv+="$1"$'\n'; } + +.env.generate() { + .env::arg "key required for generate" "$@" || return + .env.get "$1" && return || REPLY=$("${@:2}") || return + .env::one "generate: ouptut of '${*:2}' has more than one line" "$REPLY" || return + .env.puts "$1=$REPLY" +} + +.env.--file() { + .env::arg "filename required for --file" "$@" || return + __dotenv_file=$1 + .env::file load || return + (($# < 2)) || .env "${@:2}" +} + +.env::arg() { [[ "${2-}" ]] || { + echo "$__dotenv_cmd: $1" >&2 + return 64 +}; } + +.env::one() { [[ "$2" != *$'\n'* ]] || .env::arg "$1"; } + +.env::file() { + local REPLY=$__dotenv_file + case "$1" in + load) + __dotenv= + ! [[ -f "$REPLY" ]] || __dotenv="$(<"$REPLY")"$'\n' || return + ;; + save) + if [[ -L "$REPLY" ]] && declare -F -- realpath.resolved >/dev/null; then + realpath.resolved "$REPLY" + fi + { [[ ! -f "$REPLY" ]] || cp -p "$REPLY" "$REPLY.bak"; } && + printf %s "$__dotenv" >"$REPLY.bak" && mv "$REPLY.bak" "$REPLY" + ;; + esac +} + +# Shortcut to convert semver version (x.yyy.zzz) into a comparable number. +version-number() { + echo "$@" | awk -F. '{ printf("%03d%03d%03d\n", $1,$2,$3); }' +} + +# Get the current release channel for AzuraCast +get-release-channel() { + local AZURACAST_VERSION="latest" + if [[ -f .env ]]; then + .env --file .env get AZURACAST_VERSION + AZURACAST_VERSION="${REPLY:-latest}" + fi + + echo "$AZURACAST_VERSION" +} + +get-release-branch-name() { + if [[ $(get-release-channel) == "stable" ]]; then + echo "stable" + else + echo "main" + fi +} + +# This is a general-purpose function to ask Yes/No questions in Bash, either +# with or without a default answer. It keeps repeating the question until it +# gets a valid answer. +ask() { + # https://djm.me/ask + local prompt default reply + + while true; do + + if [[ "${2:-}" == "Y" ]]; then + prompt="Y/n" + default=Y + elif [[ "${2:-}" == "N" ]]; then + prompt="y/N" + default=N + else + prompt="y/n" + default= + fi + + # Ask the question (not using "read -p" as it uses stderr not stdout) + echo -n "$1 [$prompt] " + + read reply + + # Default? + if [[ -z "$reply" ]]; then + reply=${default} + fi + + # Check if the reply is valid + case "$reply" in + Y* | y*) return 0 ;; + N* | n*) return 1 ;; + esac + + done +} + +# Generate a prompt to set an environment file value. +envfile-set() { + local VALUE INPUT + + .env --file .env + + .env get "$1" + VALUE=${REPLY:-$2} + + echo -n "$3 [$VALUE]: " + read INPUT + + VALUE=${INPUT:-$VALUE} + + .env set "${1}=${VALUE}" +} + +# +# Configure the ports used by AzuraCast. +# +setup-ports() { + envfile-set "AZURACAST_HTTP_PORT" "80" "Port to use for HTTP connections" + envfile-set "AZURACAST_HTTPS_PORT" "443" "Port to use for HTTPS connections" + envfile-set "AZURACAST_SFTP_PORT" "2022" "Port to use for SFTP connections" +} + +# +# Configure release mode settings. +# +setup-release() { + if [[ ! -f .env ]]; then + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/main/sample.env -o .env + fi + + local OLD_RELEASE_CHANNEL + .env --file .env get AZURACAST_VERSION + OLD_RELEASE_CHANNEL="${REPLY:-latest}" + + local AZURACAST_VERSION="${OLD_RELEASE_CHANNEL}" + + if [[ $AZURACAST_VERSION == "latest" ]]; then + if ask "Your current release channel is 'Rolling Release'. Switch to 'Stable' release channel?" N; then + AZURACAST_VERSION="stable" + fi + elif [[ $AZURACAST_VERSION == "stable" ]]; then + if ask "Your current release channel is 'Stable'. Switch to 'Rolling Release' release channel?" N; then + AZURACAST_VERSION="latest" + fi + fi + + .env --file .env set AZURACAST_VERSION=${AZURACAST_VERSION} + + if [[ $AZURACAST_VERSION != $OLD_RELEASE_CHANNEL ]]; then + if ask "You should update the Docker Utility Script after changing release channels. Automatically update it now?" Y; then + update-self + fi + fi +} + +check-install-requirements() { + local CURRENT_OS CURRENT_ARCH REQUIRED_COMMANDS SCRIPT_DIR + + set -e + + echo "Checking installation requirements for AzuraCast..." + + CURRENT_OS=$(uname -s) + if [[ $CURRENT_OS == "Linux" ]]; then + echo -en "\e[32m[PASS]\e[0m Operating System: ${CURRENT_OS}\n" + else + echo -en "\e[41m[FAIL]\e[0m Operating System: ${CURRENT_OS}\n" + + echo " You are running an unsupported operating system." + echo " Automated AzuraCast installation is not currently supported on this" + echo " operating system." + exit 1 + fi + + CURRENT_ARCH=$(uname -m) + if [[ $CURRENT_ARCH == "x86_64" ]]; then + echo -en "\e[32m[PASS]\e[0m Architecture: ${CURRENT_ARCH}\n" + elif [[ $CURRENT_ARCH == "aarch64" ]]; then + echo -en "\e[32m[PASS]\e[0m Architecture: ${CURRENT_ARCH}\n" + else + echo -en "\e[41m[FAIL]\e[0m Architecture: ${CURRENT_ARCH}\n" + + echo " You are running an unsupported processor architecture." + echo " Automated AzuraCast installation is not currently supported on this " + echo " operating system." + exit 1 + fi + + REQUIRED_COMMANDS=(curl awk) + for COMMAND in "${REQUIRED_COMMANDS[@]}" ; do + if [[ $(command -v "$COMMAND") ]]; then + echo -en "\e[32m[PASS]\e[0m Command Present: ${COMMAND}\n" + else + echo -en "\e[41m[FAIL]\e[0m Command Present: ${COMMAND}\n" + + echo " ${COMMAND} does not appear to be installed." + echo " Install ${COMMAND} using your host's package manager," + echo " then continue installing using this script." + exit 1 + fi + done + + if [[ $EUID -ne 0 ]]; then + if [[ $(command -v sudo) ]]; then + echo -en "\e[32m[PASS]\e[0m User Permissions\n" + else + echo -en "\e[41m[FAIL]\e[0m User Permissions\n" + + echo " You are not currently the root user, and " + echo " 'sudo' does not appear to be installed." + echo " Install sudo using your host's package manager," + echo " then continue installing using this script." + exit 1 + fi + else + echo -en "\e[32m[PASS]\e[0m User Permissions\n" + fi + + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + if [[ $SCRIPT_DIR == "/var/azuracast" ]]; then + echo -en "\e[32m[PASS]\e[0m Installation Directory\n" + else + echo -en "\e[93m[WARN]\e[0m Installation Directory\n" + echo " AzuraCast is not installed in /var/azuracast, as is recommended" + echo " for most installations. This will not prevent AzuraCast from" + echo " working, but you will need to update any instructions in our" + echo " documentation to reflect your current directory:" + echo " $SCRIPT_DIR" + fi + + echo -en "\e[32m[PASS]\e[0m All requirements met!\n" + + set +e +} + +install-docker() { + set -e + + curl -fsSL get.docker.com -o get-docker.sh + sh get-docker.sh + rm get-docker.sh + + if [[ $EUID -ne 0 ]]; then + sudo usermod -aG docker "$(whoami)" + + echo "You must log out or restart to apply necessary Docker permissions changes." + echo "Restart, then continue installing using this script." + exit 1 + fi + + set +e +} + +install-docker-compose() { + set -e + echo "Installing Docker Compose..." + + curl -fsSL -o docker-compose https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-$(uname -m) + + ARCHITECTURE=amd64 + if [ "$(uname -m)" = "aarch64" ]; then + ARCHITECTURE=arm64 + fi + curl -fsSL -o docker-compose-switch https://github.com/docker/compose-switch/releases/download/v1.0.4/docker-compose-linux-${ARCHITECTURE} + + if [[ $EUID -ne 0 ]]; then + sudo chmod a+x ./docker-compose + sudo chmod a+x ./docker-compose-switch + + sudo mv ./docker-compose /usr/libexec/docker/cli-plugins/docker-compose + sudo mv ./docker-compose-switch /usr/local/bin/docker-compose + else + chmod a+x ./docker-compose + chmod a+x ./docker-compose-switch + + mv ./docker-compose /usr/libexec/docker/cli-plugins/docker-compose + mv ./docker-compose-switch /usr/local/bin/docker-compose + fi + + echo "Docker Compose updated!" + set +e +} + +run-installer() { + local AZURACAST_RELEASE_BRANCH + AZURACAST_RELEASE_BRANCH=$(get-release-branch-name) + + if [[ ! -f .env ]]; then + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/sample.env -o .env + fi + if [[ ! -f azuracast.env ]]; then + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/azuracast.sample.env -o azuracast.env + fi + if [[ ! -f docker-compose.yml ]]; then + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/docker-compose.sample.yml -o docker-compose.yml + fi + + touch docker-compose.new.yml + + local dc_config_test=$(docker-compose -f docker-compose.new.yml config 2>/dev/null) + if [ $? -ne 0 ]; then + if ask "Docker Compose needs to be updated to continue. Update to latest version?" Y; then + install-docker-compose + fi + fi + + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/docker-compose.installer.yml -o docker-compose.installer.yml + + docker-compose -p azuracast_installer -f docker-compose.installer.yml pull + docker-compose -p azuracast_installer -f docker-compose.installer.yml run --rm installer install "$@" + + rm docker-compose.installer.yml +} + +# +# Run the initial installer of Docker and AzuraCast. +# Usage: ./docker.sh install +# +install() { + check-install-requirements + + if [[ $(command -v docker) && $(docker --version) ]]; then + echo "Docker is already installed! Continuing..." + else + if ask "Docker does not appear to be installed. Install Docker now?" Y; then + install-docker + fi + fi + + if [[ $(command -v docker-compose) ]]; then + echo "Docker Compose is already installed. Continuing..." + else + if ask "Docker Compose does not appear to be installed. Install Docker Compose now?" Y; then + install-docker-compose + fi + fi + + setup-release + + run-installer "$@" + + # Installer creates a file at docker-compose.new.yml; copy it to the main spot. + if [[ -s docker-compose.new.yml ]]; then + if [[ -f docker-compose.yml ]]; then + rm docker-compose.yml + fi + + mv docker-compose.new.yml docker-compose.yml + fi + + # If this script is running as a non-root user, set the PUID/PGID in the environment vars appropriately. + if [[ $EUID -ne 0 ]]; then + .env --file .env set AZURACAST_PUID="$(id -u)" + .env --file .env set AZURACAST_PGID="$(id -g)" + fi + + docker-compose pull + + docker-compose run --rm web -- azuracast_install "$@" + docker-compose up -d + exit +} + +install-dev() { + if [[ $(command -v docker) && $(docker --version) ]]; then + echo "Docker is already installed! Continuing..." + else + if ask "Docker does not appear to be installed. Install Docker now?" Y; then + install-docker + fi + fi + + if [[ $(command -v docker-compose) ]]; then + echo "Docker Compose is already installed. Continuing..." + else + if ask "Docker Compose does not appear to be installed. Install Docker Compose now?" Y; then + install-docker-compose + fi + fi + + if [[ ! -f docker-compose.yml ]]; then + cp docker-compose.sample.yml docker-compose.yml + fi + if [[ ! -f docker-compose.override.yml ]]; then + cp docker-compose.dev.yml docker-compose.override.yml + fi + if [[ ! -f .env ]]; then + cp dev.env .env + fi + if [[ ! -f azuracast.env ]]; then + cp azuracast.dev.env azuracast.env + + echo "Customize azuracast.env file now before continuing. Re-run this command to continue installation." + exit + fi + + # If this script is running as a non-root user, set the PUID/PGID in the environment vars appropriately. + if [[ $EUID -ne 0 ]]; then + .env --file .env set AZURACAST_PUID="$(id -u)" + .env --file .env set AZURACAST_PGID="$(id -g)" + fi + + chmod 777 ./frontend/ ./web/ ./vendor/ \ + ./web/static/ ./web/static/api/ \ + ./web/static/dist/ ./web/static/img/ + + docker-compose build + docker-compose run --rm web -- azuracast_install "$@" + + docker-compose -p azuracast_frontend -f docker-compose.frontend.yml build + docker-compose -p azuracast_frontend -f docker-compose.frontend.yml run --rm frontend npm run build + + docker-compose up -d + exit +} + +# +# Update the Docker images and codebase. +# Usage: ./docker.sh update +# +update() { + echo "[NOTICE] Before you continue, please make sure you have a recent snapshot of your system and or backed it up." + if ask "Are you ready to continue with the update?" Y; then + + # Check for a new Docker Utility Script. + local AZURACAST_RELEASE_BRANCH + AZURACAST_RELEASE_BRANCH=$(get-release-branch-name) + + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/docker.sh -o docker.new.sh + + local UTILITY_FILES_MATCH + UTILITY_FILES_MATCH="$( + cmp --silent docker.sh docker.new.sh + echo $? + )" + + local UPDATE_UTILITY=0 + if [[ ${UTILITY_FILES_MATCH} -ne 0 ]]; then + if ask "The Docker Utility Script has changed since your version. Update to latest version?" Y; then + UPDATE_UTILITY=1 + fi + fi + + if [[ ${UPDATE_UTILITY} -ne 0 ]]; then + mv docker.new.sh docker.sh + chmod a+x docker.sh + + echo "A new Docker Utility Script has been downloaded." + echo "Please re-run the update process to continue." + exit + else + rm docker.new.sh + fi + + run-installer --update "$@" + + # Check for updated Docker Compose config. + local COMPOSE_FILES_MATCH + + if [[ ! -s docker-compose.new.yml ]]; then + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/docker-compose.sample.yml -o docker-compose.new.yml + fi + + COMPOSE_FILES_MATCH="$( + cmp --silent docker-compose.yml docker-compose.new.yml + echo $? + )" + + if [[ ${COMPOSE_FILES_MATCH} -ne 0 ]]; then + docker-compose -f docker-compose.new.yml pull + docker-compose down + + cp docker-compose.yml docker-compose.backup.yml + mv docker-compose.new.yml docker-compose.yml + else + rm docker-compose.new.yml + + docker-compose pull + docker-compose down + fi + + docker-compose run --rm web -- azuracast_update "$@" + docker-compose up -d + + if ask "Clean up all stopped Docker containers and images to save space?" Y; then + docker system prune -f + fi + + echo "Update complete!" + fi + exit +} + +# +# Update this Docker utility script. +# Usage: ./docker.sh update-self +# +update-self() { + local AZURACAST_RELEASE_BRANCH + AZURACAST_RELEASE_BRANCH=$(get-release-branch-name) + + curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/$AZURACAST_RELEASE_BRANCH/docker.sh -o docker.sh + chmod a+x docker.sh + + echo "New Docker utility script downloaded." + exit +} + +# +# Run a CLI command inside the Docker container. +# Usage: ./docker.sh cli [command] +# +cli() { + docker-compose exec --user="azuracast" web azuracast_cli "$@" + exit +} + +# +# Enter the bash terminal of the running web container. +# Usage: ./docker.sh bash +# +bash() { + docker-compose exec --user="azuracast" web bash + exit +} + +# +# Enter the MariaDB database management terminal with the correct credentials. +# +db() { + local MYSQL_HOST MYSQL_PORT MYSQL_USER MYSQL_PASSWORD MYSQL_DATABASE + + .env --file azuracast.env get MYSQL_HOST + MYSQL_HOST="${REPLY:-localhost}" + + .env --file azuracast.env get MYSQL_PORT + MYSQL_PORT="${REPLY:-3306}" + + .env --file azuracast.env get MYSQL_USER + MYSQL_USER="${REPLY:-azuracast}" + + .env --file azuracast.env get MYSQL_PASSWORD + MYSQL_PASSWORD="${REPLY:-azur4c457}" + + .env --file azuracast.env get MYSQL_DATABASE + MYSQL_DATABASE="${REPLY:-azuracast}" + + docker-compose exec --user="mysql" web mysql --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} \ + --host=${MYSQL_HOST} --port=${MYSQL_PORT} --database=${MYSQL_DATABASE} + + exit +} + +# +# Back up the Docker volumes to a .tar.gz file. +# Usage: +# ./docker.sh backup [/custom/backup/dir/custombackupname.zip] +# +backup() { + local BACKUP_PATH BACKUP_DIR BACKUP_FILENAME BACKUP_EXT + BACKUP_PATH=$(readlink -f ${1:-"./backup.tar.gz"}) + BACKUP_DIR=$(dirname -- "$BACKUP_PATH") + BACKUP_FILENAME=$(basename -- "$BACKUP_PATH") + BACKUP_EXT="${BACKUP_FILENAME##*.}" + shift + + # Prepare permissions + if [[ $EUID -ne 0 ]]; then + .env --file .env set AZURACAST_PUID="$(id -u)" + .env --file .env set AZURACAST_PGID="$(id -g)" + fi + + docker-compose exec --user="azuracast" web azuracast_cli azuracast:backup "/var/azuracast/backups/${BACKUP_FILENAME}" "$@" + + # Move from Docker volume to local filesystem + docker run --rm -v "azuracast_backups:/backup_src" \ + -v "$BACKUP_DIR:/backup_dest" \ + busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" +} + +# +# Restore an AzuraCast backup into Docker. +# Usage: +# ./docker.sh restore [/custom/backup/dir/custombackupname.zip] +# +restore() { + if [[ ! -f .env ]] || [[ ! -f azuracast.env ]]; then + echo "AzuraCast hasn't been installed yet on this server." + echo "You should run './docker.sh install' first before restoring." + exit 1 + fi + + if ask "Restoring will remove any existing AzuraCast installation data, replacing it with your backup. Continue?" Y; then + if [[ $1 != "" ]]; then + local BACKUP_PATH BACKUP_DIR BACKUP_FILENAME BACKUP_EXT + BACKUP_PATH=$(readlink -f ${1:-"./backup.tar.gz"}) + BACKUP_DIR=$(dirname -- "$BACKUP_PATH") + BACKUP_FILENAME=$(basename -- "$BACKUP_PATH") + BACKUP_EXT="${BACKUP_FILENAME##*.}" + shift + + if [[ ! -f ${BACKUP_PATH} ]]; then + echo "File '${BACKUP_PATH}' does not exist. Nothing to restore." + exit 1 + fi + + docker-compose down -v + docker volume create azuracast_backups + + # Move from local filesystem to Docker volume + docker run --rm -v "$BACKUP_DIR:/backup_src" \ + -v "azuracast_backups:/backup_dest" \ + busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" + + # Prepare permissions + if [[ $EUID -ne 0 ]]; then + .env --file .env set AZURACAST_PUID="$(id -u)" + .env --file .env set AZURACAST_PGID="$(id -g)" + fi + + docker-compose run --rm web -- azuracast_restore "/var/azuracast/backups/${BACKUP_FILENAME}" "$@" + + # Move file back from volume to local filesystem + docker run --rm -v "azuracast_backups:/backup_src" \ + -v "$BACKUP_DIR:/backup_dest" \ + busybox mv "/backup_src/${BACKUP_FILENAME}" "/backup_dest/${BACKUP_FILENAME}" + + docker-compose down + docker-compose up -d + else + docker-compose down + + # Remove all volumes except the backup volume. + docker volume rm -f $(docker volume ls | grep -v "azuracast_backups" | awk 'NR>1 {print $2}') + + docker-compose run --rm web -- azuracast_restore "$@" + + docker-compose down + docker-compose up -d + fi + fi + exit +} + +# +# Restore the Docker volumes from a legacy backup format .tar.gz file. +# Usage: +# ./docker.sh restore [/custom/backup/dir/custombackupname.tar.gz] +# +restore-legacy() { + local APP_BASE_DIR BACKUP_PATH BACKUP_DIR BACKUP_FILENAME + + APP_BASE_DIR=$(pwd) + + BACKUP_PATH=${1:-"./backup.tar.gz"} + BACKUP_DIR=$(cd "$(dirname "$BACKUP_PATH")" && pwd) + BACKUP_FILENAME=$(basename "$BACKUP_PATH") + + cd "$APP_BASE_DIR" || exit + + if [ -f "$BACKUP_PATH" ]; then + docker-compose down + + docker volume rm azuracast_db_data azuracast_station_data + docker volume create azuracast_db_data + docker volume create azuracast_station_data + + docker run --rm -v "$BACKUP_DIR:/backup" \ + -v azuracast_db_data:/azuracast/db \ + -v azuracast_station_data:/azuracast/stations \ + busybox tar zxvf "/backup/$BACKUP_FILENAME" + + docker-compose up -d + else + echo "File $BACKUP_PATH does not exist in this directory. Nothing to restore." + exit 1 + fi + + exit +} + +# +# DEVELOPER TOOL: +# Access the static console as a developer. +# Usage: ./docker.sh static [static_container_command] +# +static() { + docker-compose -f docker-compose.frontend.yml down -v + docker-compose -f docker-compose.frontend.yml build + docker-compose --env-file=.env -f docker-compose.frontend.yml run --rm frontend "$@" + exit +} + +# +# Stop all Docker containers and remove related volumes. +# Usage: ./docker.sh uninstall +# +uninstall() { + if ask "This operation is destructive and will wipe your existing Docker containers. Continue?" N; then + + docker-compose down -v + docker-compose rm -f + docker volume prune -f + + echo "All AzuraCast Docker containers and volumes were removed." + echo "To remove *all* Docker containers and volumes, run:" + echo " docker stop \$(docker ps -a -q)" + echo " docker rm \$(docker ps -a -q)" + echo " docker volume prune -f" + echo "" + fi + + exit +} + +# +# LetsEncrypt: Now managed via the Web UI. +# +setup-letsencrypt() { + echo "LetsEncrypt is now managed from within the web interface." +} + +letsencrypt-create() { + setup-letsencrypt + exit +} + +# +# Utility script to facilitate switching ports. +# Usage: ./docker.sh change-ports +# +change-ports() { + setup-ports + + docker-compose down + docker-compose up -d +} + +# +# Helper scripts for basic Docker Compose functions +# +up() { + echo "Starting up AzuraCast services..." + docker-compose up -d +} + +down() { + echo "Shutting down AzuraCast services..." + docker-compose down +} + +restart() { + down + up +} + +# Ensure we're in the same directory as this script. +cd "$( dirname "${BASH_SOURCE[0]}" )" || exit + +"$@" diff --git a/roles/azuracast/upstream/notes.txt b/roles/azuracast/upstream/notes.txt new file mode 100644 index 000000000..47be401bc --- /dev/null +++ b/roles/azuracast/upstream/notes.txt @@ -0,0 +1 @@ +The three file found here are mentioned in docker.sh's run-installer() with 'sample.' added to the filename diff --git a/roles/azuracast/upstream/sample.env b/roles/azuracast/upstream/sample.env new file mode 100644 index 000000000..303905de1 --- /dev/null +++ b/roles/azuracast/upstream/sample.env @@ -0,0 +1,11 @@ +COMPOSE_PROJECT_NAME=azuracast + +AZURACAST_HTTP_PORT=80 +AZURACAST_HTTPS_PORT=443 + +AZURACAST_SFTP_PORT=2022 + +AZURACAST_PUID=1000 +AZURACAST_PGID=1000 + +NGINX_TIMEOUT=1800 diff --git a/roles/calibre-web/README.rst b/roles/calibre-web/README.rst index 84b5cadae..a29896573 100644 --- a/roles/calibre-web/README.rst +++ b/roles/calibre-web/README.rst @@ -13,101 +13,179 @@ Calibre-Web README ================== -Calibre-Web provides a clean interface for browsing, reading and downloading -e-books using an existing Calibre database. Teachers can upload e-books, -adjust e-book metadata, and create custom e-book collections ("bookshelves"): -https://github.com/janeczku/calibre-web#about +This Ansible role installs +`Calibre-Web `_ as a modern +client-server alternative to Calibre, for your +`Internet-in-a-Box (IIAB) `_. -This Ansible role installs Calibre-Web as part of your Internet-in-a-Box (IIAB) -as a possible alternative to Calibre. +Calibre-Web provides a clean web interface for students to browse, read and +download e-books using a +`Calibre-compatible database `_. -*WARNING: Calibre-Web depends on Calibre's own /usr/bin/ebook-convert program, -so we strongly recommend you also install Calibre during your IIAB -installation!* +Teachers upload e-books, adjust e-book metadata, and create custom "bookshelf" +collections β€” to help students build the best local community library! -Please note Calibre-Web's Ansible playbook is ``/opt/iiab/iiab/roles/calibre-web`` -whereas its Ansible variables ``calibreweb_*`` do **not** include the dash, -per Ansible recommendations. +**NEW AS OF JANUARY 2024:** `IIAB's experimental new version of Calibre-Web `_ +**also lets you add YouTube and Vimeo videos (and local videos, e.g. from +teachers' phones) to expand your indigenous/local/family learning library!** + +.. image:: https://www.yankodesign.com/images/design_news/2019/05/221758/luo_beetle_library_8.jpg + +πŸ’ GURU TIPS πŸ’ + +* Calibre-Web takes advantage of Calibre's own `/usr/bin/ebook-convert + `_ program + if that's installed β€” so consider also installing + `Calibre `_ during your IIAB + installation β€” *if you tolerate the weighty ~1 GB (of graphical OS libraries) + that Calibre mandates!* + +* If you choose to also install Calibre (e.g. by running + ``sudo apt install calibre``) then you'll get useful e-book + importing/organizing tools like + `/usr/bin/calibredb `_. + +Install It +---------- + +Install Calibre-Web by setting these 2 variables in +`/etc/iiab/local_vars.yml `_:: + + calibreweb_install: True + calibreweb_enabled: True + +Then install IIAB (`download.iiab.io `_). Or if +IIAB's already installed, run:: + + cd /opt/iiab/iiab + sudo ./runrole calibre-web + +NOTE: Calibre-Web's Ansible role (playbook) in +`/opt/iiab/iiab/roles `_ is +``calibre-web`` which contains a hyphen β€” *whereas its Ansible variables* +``calibreweb_*`` *do NOT contain a hyphen!* Using It -------- -After installation, try out Calibre-Web at http://box/books (or box.lan/books). +Try Calibre-Web on your own IIAB by browsing to http://box/books (or +http://box.lan/books). -Typically students access it without a password (to read and download books) -whereas teachers add books using an administrative account, as follows:: +*Students* access it without a password (to read and download books). + +*Teachers* add and arrange books using an administrative account, by clicking +**Guest** then logging in with:: Username: Admin Password: changeme -If the default configuration is not found, the Calibre-Web server creates a -new settings file with calibre-web's own default administrative account:: +πŸ’ GURU TIPS πŸ’ - Username: admin - Password: admin123 +* If Calibre-Web's configuration file (app.db) goes missing, the administrative + account will revert to:: -Backend -------- + Username: admin + Password: admin123 -You can manage the backend Calibre-Web server with these systemd commands:: - - systemctl enable calibre-web - systemctl restart calibre-web - systemctl status calibre-web - systemctl stop calibre-web +* If you lose your password, you can change it with the + ``-s [username]:[newpassword]`` command-line option: + https://github.com/janeczku/calibre-web/wiki/FAQ#what-do-i-do-if-i-lose-my-admin-password Configuration ------------- -To configure Calibre-Web, log in as user 'Admin' then click 'Admin' on top. -Check 'Configuration' options near the bottom of the page. +To configure Calibre-Web browse to http://box/books then click **Guest** to log +in as user **Admin** (default passwords above!) -Critical settings are stored in:: +Then click the leftmost **Admin** button to administer β€” considering all 3 +**Configuration** buttons further below. + +These critical settings are stored in:: /library/calibre-web/config/app.db -Your e-book metadata is stored in a Calibre-style database:: +Whereas your e-book metadata is stored in a Calibre-style database:: /library/calibre-web/metadata.db +Videos' metadata is stored in database:: + + /library/calibre-web/xklb-metadata.db + See also:: /library/calibre-web/metadata_db_prefs_backup.json -See the official docs on Calibre-Web's `Runtime Configuration Options `_. +Finally, take note of Calibre-Web's +`FAQ `_ and official docs on +its +`Runtime Configuration Options `_ +and +`Command Line Interface `_. + +Backend +------- + +You can manage the backend Calibre-Web server with systemd commands like:: + + systemctl status calibre-web + systemctl stop calibre-web + systemctl restart calibre-web + +Run all commands +`as root `_. + +Errors and warnings can be seen if you run:: + + journalctl -u calibre-web + +Log verbosity level can be +`adjusted `_ +within Calibre-Web's **Configuration > Basic Configuration > Logfile +Configuration**. + +Finally, http://box/live/stats (Calibre-Web's **About** page) can be a very +useful list of ~42 `Calibre-Web dependencies `_ +(mostly Python packages, and the version number of each that's installed). Back Up Everything ------------------ Please back up the entire folder ``/library/calibre-web`` before upgrading β€” -as it contains your Calibre-Web content **and** settings! +as it contains your Calibre-Web content **and** configuration settings! Upgrading --------- -Reinstalling Calibre-Web automatically upgrades to the latest version if your -Internet-in-a-Box (IIAB) is online. +Please see our `new/automated upgrade technique (iiab-update) `_ +introduced in July 2024. -But first: back up your content **and** settings, as explained above. +But first: back up your content **and** configuration settings, as outlined +above! -**Then move your /library/calibre-web/metadata.db out of the way, if you're -sure you want to (re)install bare/minimal metadata, and force all Calibre-Web -settings to the default. Then run**:: +**Conversely if you're sure you want to fully reset your Calibre-Web settings, +and remove all existing e-book/video/media metadata β€” then move your +/library/calibre-web/config/app.db, /library/calibre-web/metadata.db and +/library/calibre-web/xklb-metadata.db out of the way.** + +RECAP: Either way, "reinstalling" Calibre-Web automatically installs the latest +version β€” so long as your Internet-in-a-Box (IIAB) is online. Most people +should stick with the new ``iiab-update`` technique above. However if you must +use the older/manual approach, you would need to run, as root:: cd /opt/iiab/iiab - ./runrole calibre-web - -Or, to reinstall all of IIAB:: + ./runrole --reinstall calibre-web - cd /opt/iiab/iiab - ./iiab-install --reinstall +Or, if there's a need to try updating Calibre-Web's code alone:: -Or, if you just want to upgrade Calibre-Web code alone, prior to proceeding -manually:: - - cd /opt/iiab/calibre-web + cd /usr/local/calibre-web-py3 git pull +Finally, this much older way is *no longer recommended*:: + + cd /opt/iiab/iiab + ./iiab-install --reinstall # OR: ./iiab-configure + Known Issues ------------ @@ -153,7 +231,7 @@ Known Issues * |ss| Imagemagick policy prevents generating thumbnails for PDF's during upload: `#1530 `_ `janeczku/calibre-web#827 `_ |se| -* Upload of not supported file formats gives no feedback to the user: `janeczku/calibre-web#828 `_ +* |ss| Upload of not supported file formats gives no feedback to the user: `janeczku/calibre-web#828 `_ |se| |nbsp| Fixed by `361a124 `_ on 2019-02-27. -* *Please assist us in reporting serious issues here:* - https://github.com/janeczku/calibre-web/issues +* *Please report serious issues here:* + https://github.com/iiab/calibre-web/issues diff --git a/roles/calibre-web/defaults/main.yml b/roles/calibre-web/defaults/main.yml index 903b3b6e5..3e99725a9 100644 --- a/roles/calibre-web/defaults/main.yml +++ b/roles/calibre-web/defaults/main.yml @@ -14,23 +14,26 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! +calibreweb_repo_url: https://github.com/iiab/calibre-web # Or use upstream: https://github.com/janeczku/calibre-web calibreweb_version: master # WAS: master, 0.6.4, 0.6.5, 0.6.6, 0.6.7, 0.6.8, 0.6.9 +calibreweb_venv_wipe: False # 2023-12-04: NEW default TDD (Test-Driven Dev!) calibreweb_venv_path: /usr/local/calibre-web-py3 calibreweb_exec_path: "{{ calibreweb_venv_path }}/cps.py" -# Config files put in: +# Config files (in reality just app.db) put in: calibreweb_config: "{{ calibreweb_home }}/config" -# Calibre-Web will be provisioned with default administrative account, -# metadata.db and language if /library/calibre-web/metadata.db does not exist. -# NOT CURRENTLY IN USE: calibreweb_provision: True -calibreweb_settings_database: app.db -calibreweb_database: metadata.db +# 2022-03-07: Calibre-Web will be reset to default settings if (re)installed +# when /library/calibre-web/config/app.db doesn't exist: +calibreweb_settings_database: app.db # /library/calibre-web/config/app.db + +# UNUSED var as of 2022-03-07: +# calibreweb_database: metadata.db # /library/calibre-web/metadata.db # Files owned by: calibreweb_user: root -# UNUSED variables, as of March 2019: +# UNUSED vars, as of March 2019: # calibreweb_admin_user: Admin # calibreweb_admin_password: changeme diff --git a/roles/calibre-web/files/app.db b/roles/calibre-web/files/app.db index 31a8b716a..3183544da 100644 Binary files a/roles/calibre-web/files/app.db and b/roles/calibre-web/files/app.db differ diff --git a/roles/calibre-web/tasks/enable-or-disable.yml b/roles/calibre-web/tasks/enable-or-disable.yml new file mode 100644 index 000000000..493703dc7 --- /dev/null +++ b/roles/calibre-web/tasks/enable-or-disable.yml @@ -0,0 +1,52 @@ +- name: Enable & Restart 'calibre-web' systemd service, if calibreweb_enabled + systemd: + name: calibre-web + daemon_reload: yes + enabled: yes + state: restarted + when: calibreweb_enabled + +- name: Disable & Stop 'calibre-web' systemd service, if not calibreweb_enabled + systemd: + name: calibre-web + enabled: no + state: stopped + when: not calibreweb_enabled + + +# TO DO: restore http://box/libros & http://box/livres etc, alongside English (#2195) +# RELATED: https://github.com/janeczku/calibre-web/wiki/Setup-Reverse-Proxy + +- name: Enable http://box{{ calibreweb_url1 }} via NGINX, by installing {{ nginx_conf_dir }}/calibre-web-nginx.conf from template # http://box/books + template: + src: calibre-web-nginx.conf.j2 + dest: "{{ nginx_conf_dir }}/calibre-web-nginx.conf" # /etc/nginx/conf.d + when: calibreweb_enabled + +- name: If enabling with Calibre-Web enhanced for large audio/video "books" too, also append onto calibre-web-nginx.conf AND symlink /library/www/html/calibre-web -> /library/calibre-web (WIP) + shell: | + if [ -f {{ calibreweb_venv_path }}/scripts/calibre-web-nginx.conf ]; then + cat {{ calibreweb_venv_path }}/scripts/calibre-web-nginx.conf >> {{ nginx_conf_dir }}/calibre-web-nginx.conf + # 2023-12-05: Not needed as a result of PR iiab/calibre-web#57 + # ln -sf {{ calibreweb_home }} {{ doc_root }}/calibre-web + fi + when: calibreweb_enabled + + +- name: Disable http://box{{ calibreweb_url1 }} via NGINX, by removing {{ nginx_conf_dir }}/calibre-web-nginx.conf + file: + path: "{{ nginx_conf_dir }}/calibre-web-nginx.conf" + state: absent + when: not calibreweb_enabled + +- name: If disabling, also remove symlink /library/www/html/calibre-web (WIP) + file: + path: "{{ doc_root }}/calibre-web" # /library/www/html + state: absent + when: not calibreweb_enabled + + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/calibre-web/tasks/install.yml b/roles/calibre-web/tasks/install.yml index 7d82f6677..d293afe23 100644 --- a/roles/calibre-web/tasks/install.yml +++ b/roles/calibre-web/tasks/install.yml @@ -1,10 +1,50 @@ -- name: "Install packages: imagemagick, python3-venv" +# Or try 'iiab-update -f' for a more rapid upgrade of IIAB Calibre-Web: +# +# https://wiki.iiab.io/go/FAQ#Can_I_upgrade_IIAB_software%3F +# https://github.com/iiab/calibre-web/wiki#upgrading +# https://github.com/iiab/iiab/blob/master/scripts/iiab-update +# https://github.com/iiab/iiab/tree/master/roles/calibre-web#upgrading + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: Stop 'calibre-web' systemd service for safety (RED ERROR CAN BE IGNORED!) + systemd: + name: calibre-web + state: stopped + ignore_errors: True # Shows red errors, and continue... + #failed_when: False # Hides red errors, and continue... + +# Official upstream instructions: +# apt install python3-pip python3-venv +# https://github.com/janeczku/calibre-web/wiki/Manual-installation +- name: "Install package: imagemagick" package: name: - imagemagick - - python3-venv + #- python3-cryptography # Was needed on Raspberry Pi OS (SEE iiab/calibre-web#260, janeczku/calibre-web#3183) + #- python3-netifaces state: present +# https://github.com/iiab/iiab/pull/3496#issuecomment-1475094542 +#- name: "Install packages: python3-dev, gcc to compile 'netifaces'" +# package: +# name: +# - python3-dev # header files +# - gcc # compiler +# state: present +# when: python_version is version('3.10', '>=') + +- name: Does /etc/ImageMagick-6/policy.xml exist? + stat: + path: /etc/ImageMagick-6/policy.xml + register: imagemagick6_policy_xml + +# 2024-12-16: Debian 13 uses /etc/ImageMagick-7/policy.xml instead, which doesn't need this lineinfile surgery: +# https://stackoverflow.com/questions/52998331/imagemagick-security-policy-pdf-blocking-conversion - name: Allow ImageMagick to read PDFs, per /etc/ImageMagick-6/policy.xml, to create book cover thumbnails lineinfile: path: /etc/ImageMagick-6/policy.xml @@ -12,43 +52,111 @@ backrefs: yes line: ' ' state: present + when: imagemagick6_policy_xml.stat.exists -- name: "Create 3 Calibre-Web folders to store data and config files: {{ calibreweb_home }}, {{ calibreweb_venv_path }}, {{ calibreweb_config }} (all set to {{ calibreweb_user }}:{{ apache_user }}) (default to 0755)" +- name: "Create 2 Calibre-Web folders to store data and config files: {{ calibreweb_home }}, {{ calibreweb_config }} (each set to {{ calibreweb_user }}:{{ apache_user }}, default to 0755)" file: state: directory path: "{{ item }}" owner: "{{ calibreweb_user }}" # root group: "{{ apache_user }}" # www-data on debuntu - #mode: '0755' with_items: - "{{ calibreweb_home }}" # /library/calibre-web - "{{ calibreweb_config }}" # /library/calibre-web/config - - "{{ calibreweb_venv_path }}" # /usr/local/calibre-web-py3 -## TODO: Calibre-web future release might get into pypi https://github.com/janeczku/calibre-web/issues/456 -- name: Clone i.e. download Calibre-Web ({{ calibreweb_version }}) from https://github.com/janeczku/calibre-web.git to {{ calibreweb_venv_path }} (~94 MB initially, ~115+ MB later) +# FYI since May 2021, Calibre-Web (major releases) can be installed with pip: +# https://pypi.org/project/calibreweb/ +# https://github.com/janeczku/calibre-web/issues/456 +# https://github.com/janeczku/calibre-web/issues/677 +# https://github.com/janeczku/calibre-web/pull/927 +# https://github.com/janeczku/calibre-web/pull/1459 + +- name: "Remove previous virtual environment {{ calibreweb_venv_path }} -- if 'calibreweb_venv_wipe: True'" + file: + path: "{{ calibreweb_venv_path }}" # /usr/local/calibre-web-py3 + state: absent + when: calibreweb_venv_wipe + +- name: Does {{ calibreweb_venv_path }} exist? + stat: + path: "{{ calibreweb_venv_path }}" + register: calibreweb_venv + +- name: git clone Calibre-Web ({{ calibreweb_version }}) from {{ calibreweb_repo_url }} to {{ calibreweb_venv_path }} (~122 MB initially, ~191+ or ~203+ MB later) -- if {{ calibreweb_venv_path }} doesns't exist git: - repo: https://github.com/janeczku/calibre-web.git - dest: "{{ calibreweb_venv_path }}" # /usr/local/calibre-web - force: yes - depth: 1 - version: "{{ calibreweb_version }}" # e.g. master, 0.6.5 + repo: "{{ calibreweb_repo_url }}" # e.g. https://github.com/iiab/calibre-web or https://github.com/janeczku/calibre-web + dest: "{{ calibreweb_venv_path }}" + #force: True # CLAIM: "If true, any modified files in the working repository will be discarded" -- REALITY: even if `force: no`, Ansible destructively reclones (also removing all test branch commits etc!) -- unless a git credential is provided to Ansible? + #depth: 1 # 2023-11-04: Full clone for now, to help @deldesir & wider community testing + version: "{{ calibreweb_version }}" # e.g. master, 0.6.22 + when: not calibreweb_venv.stat.exists -## Ansible Pip Bug: Cannot use 'chdir' with 'env' https://github.com/ansible/ansible/issues/37912 (Patch landed) -#- name: Download calibre-web dependencies into vendor subdirectory. -# pip: -# requirements: "{{ calibreweb_path }}/requirements.txt" -# chdir: "{{ calibreweb_path }}" -# extra_args: '--target vendor' -# ignore_errors: True -## -# Implementing this with Ansible command module for now. -- name: Download Calibre-Web dependencies (using pip) into python3 virtual environment {{ calibreweb_venv_path }} +- name: cd {{ calibreweb_venv_path }} ; git pull {{ calibreweb_repo_url }} {{ calibreweb_version }} --no-rebase --no-edit -- if {{ calibreweb_venv_path }} exists + command: git pull "{{ calibreweb_repo_url }}" "{{ calibreweb_version }}" --no-rebase --no-edit + args: + chdir: "{{ calibreweb_venv_path }}" + when: calibreweb_venv.stat.exists + +- debug: + msg: + - "NEED BETTER/EXPERIMENTAL YouTube SCRAPING? RUN THE NEXT LINE -- for the latest yt-dlp 'nightly' release:" + - sudo pipx inject --pip-args='--upgrade --pre' -f library yt-dlp[default] + +- name: If Calibre-Web is being enhanced with audio/video "books" too, install/upgrade additional prereqs -- SEE https://github.com/iiab/calibre-web/wiki + shell: | + if [ -f {{ calibreweb_venv_path }}/scripts/lb-wrapper ]; then + apt install ffmpeg pipx -y + if lb --version; then + if pipx list | grep -q 'xklb'; then + pipx uninstall xklb + pipx install library + else + pipx reinstall library + fi + else + pipx install library + fi + ln -sf /root/.local/bin/lb /usr/local/bin/lb + if [ -f /root/.local/share/pipx/venvs/library/bin/yt-dlp ]; then + ln -sf /root/.local/share/pipx/venvs/library/bin/yt-dlp /usr/local/bin/yt-dlp + elif [ -f /root/.local/pipx/venvs/library/bin/yt-dlp ]; then + ln -sf /root/.local/pipx/venvs/library/bin/yt-dlp /usr/local/bin/yt-dlp + else + echo "ERROR: yt-dlp NOT FOUND" + fi + # NEED BETTER/EXPERIMENTAL YouTube SCRAPING? UNCOMMENT THE NEXT LINE -- for the latest yt-dlp "nightly" release: + # pipx inject --pip-args="--upgrade --pre" -f library yt-dlp[default] + # + # https://github.com/yt-dlp/yt-dlp-nightly-builds/releases + # https://pypi.org/project/yt-dlp/#history + cp {{ calibreweb_venv_path }}/scripts/lb-wrapper /usr/local/bin/ + chmod a+x /usr/local/bin/lb-wrapper + fi + +- name: Download Calibre-Web dependencies from 'requirements.txt' into python3 virtual environment {{ calibreweb_venv_path }} pip: requirements: "{{ calibreweb_venv_path }}/requirements.txt" virtualenv: "{{ calibreweb_venv_path }}" # /usr/local/calibre-web-py3 - virtualenv_site_packages: no + #virtualenv_site_packages: no + #virtualenv_command: python3 -m venv --system-site-packages {{ calibreweb_venv_path }} virtualenv_command: python3 -m venv {{ calibreweb_venv_path }} + extra_args: --prefer-binary # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560 + +# 2023-10-11: RasPiOS Bookworm doc for Python with venv (PEP 668 now enforced!) +# https://www.raspberrypi.com/documentation/computers/os.html#use-python-on-a-raspberry-pi +# https://www.raspberrypi.com/documentation/computers/os.html#install-python-packages-using-apt +# https://www.raspberrypi.com/documentation/computers/os.html#install-python-libraries-using-pip + +# VIRTUALENV EXAMPLE COMMANDS: +# python3 -m venv /usr/local/calibre-web-py3 (create venv) +# cd /usr/local/calibre-web-py3 +# . bin/activate (or 'source bin/activate' -- this prepends '/usr/local/calibre-web-py3/bin' to yr PATH) +# python3 -m pip list ('pip list' sufficient *IF* path set above!) +# python3 -m pip freeze > /tmp/requirements.txt +# python3 -m pip install -r requirements.txt +# deactivate +# https://pip.pypa.io/en/stable/user_guide/#requirements-files +# https://pip.pypa.io/en/latest/reference/requirements-file-format/ - name: Install /etc/systemd/system/calibre-web.service from template template: @@ -66,28 +174,40 @@ dest: "{{ calibreweb_home }}" # /library/calibre-web owner: "{{ calibreweb_user }}" # root group: "{{ apache_user }}" # www-data on debuntu - #mode: '0644' backup: yes with_items: - roles/calibre-web/files/metadata.db - roles/calibre-web/files/metadata_db_prefs_backup.json when: not metadatadb.stat.exists - #when: calibreweb_provision -- name: Provision/Copy default admin settings to {{ calibreweb_config }}/app.db IF metadata.db did not exist +- name: Does /library/calibre-web/config/app.db exist? + stat: + path: /library/calibre-web/config/app.db + register: appdb + +- name: Provision/Copy default admin settings to {{ calibreweb_config }}/app.db IF it did not exist copy: src: roles/calibre-web/files/app.db dest: "{{ calibreweb_config }}" # /library/calibre-web/config owner: "{{ calibreweb_user }}" # root group: "{{ apache_user }}" # www-data on debuntu - #mode: '0644' backup: yes - when: not metadatadb.stat.exists - #when: calibreweb_provision + when: not appdb.stat.exists # RECORD Calibre-Web AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'calibreweb_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: calibre-web + option: calibreweb_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'calibreweb_installed: True'" set_fact: calibreweb_installed: True diff --git a/roles/calibre-web/tasks/main.yml b/roles/calibre-web/tasks/main.yml index 40515eb57..cc0e89850 100644 --- a/roles/calibre-web/tasks/main.yml +++ b/roles/calibre-web/tasks/main.yml @@ -19,56 +19,47 @@ quiet: yes -- name: Install Calibre-Web if 'calibreweb_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: calibreweb_installed is undefined +- block: + - name: Install Calibre-Web if 'calibreweb_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: calibreweb_installed is undefined -- name: Enable & Restart 'calibre-web' systemd service, if calibreweb_enabled - systemd: - name: calibre-web - daemon_reload: yes - enabled: yes - state: restarted - when: calibreweb_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'calibre-web' systemd service, if not calibreweb_enabled - systemd: - name: calibre-web - enabled: no - state: stopped - when: not calibreweb_enabled + - name: Add 'calibre-web' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: calibre-web + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Calibre-Web + - option: description + value: '"Calibre-Web is a web app providing a clean interface for browsing, reading and downloading e-books."' + - option: calibreweb_install + value: "{{ calibreweb_install }}" + - option: calibreweb_enabled + value: "{{ calibreweb_enabled }}" + - option: calibreweb_url1 + value: "{{ calibreweb_url1 }}" + - option: calibreweb_url2 + value: "{{ calibreweb_url2 }}" + - option: calibreweb_url3 + value: "{{ calibreweb_url3 }}" + - option: calibreweb_path + value: "{{ calibreweb_venv_path }}" + - option: calibreweb_home + value: "{{ calibreweb_home }}" + - option: calibreweb_port + value: "{{ calibreweb_port }}" + - option: calibreweb_settings_database + value: "{{ calibreweb_settings_database }}" -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + rescue: - -- name: Add 'calibre-web' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: calibre-web - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Calibre-Web - - option: description - value: '"Calibre-Web is a web app providing a clean interface for browsing, reading and downloading e-books."' - - option: calibreweb_install - value: "{{ calibreweb_install }}" - - option: calibreweb_enabled - value: "{{ calibreweb_enabled }}" - - option: calibreweb_url1 - value: "{{ calibreweb_url1 }}" - - option: calibreweb_url2 - value: "{{ calibreweb_url2 }}" - - option: calibreweb_url3 - value: "{{ calibreweb_url3 }}" - - option: calibreweb_path - value: "{{ calibreweb_venv_path }}" - - option: calibreweb_home - value: "{{ calibreweb_home }}" - - option: calibreweb_port - value: "{{ calibreweb_port }}" - - option: calibreweb_database - value: "{{ calibreweb_database }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/calibre-web/tasks/nginx.yml b/roles/calibre-web/tasks/nginx.yml deleted file mode 100644 index 046bc65b8..000000000 --- a/roles/calibre-web/tasks/nginx.yml +++ /dev/null @@ -1,19 +0,0 @@ -# TO DO: restore http://box/libros & http://box/livres etc, alongside English (#2195) -# RELATED: https://github.com/janeczku/calibre-web/wiki/Setup-Reverse-Proxy - -- name: Enable http://box{{ calibreweb_url1 }} via NGINX, by installing {{ nginx_conf_dir }}/calibre-web-nginx.conf from template # http://box/books - template: - src: calibre-web-nginx.conf.j2 - dest: "{{ nginx_conf_dir }}/calibre-web-nginx.conf" # /etc/nginx/conf.d - when: calibreweb_enabled - -- name: Disable http://box{{ calibreweb_url1 }} via NGINX, by removing {{ nginx_conf_dir }}/calibre-web-nginx.conf - file: - path: "{{ nginx_conf_dir }}/calibre-web-nginx.conf" # /etc/nginx/conf.d - state: absent - when: not calibreweb_enabled - -- name: Restart 'nginx' systemd service - systemd: - name: nginx - state: restarted diff --git a/roles/calibre-web/templates/calibre-web-nginx.conf.j2 b/roles/calibre-web/templates/calibre-web-nginx.conf.j2 index d1f2da25b..2ebfe47fe 100644 --- a/roles/calibre-web/templates/calibre-web-nginx.conf.j2 +++ b/roles/calibre-web/templates/calibre-web-nginx.conf.j2 @@ -5,7 +5,7 @@ location {{ calibreweb_url1 }}/ { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; - proxy_set_header X-Script-Name {{ calibreweb_url1 }}; + proxy_set_header X-Script-Name "{{ calibreweb_url1 }}"; proxy_pass http://127.0.0.1:8083; } @@ -14,7 +14,7 @@ location {{ calibreweb_url2 }}/ { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; - proxy_set_header X-Script-Name {{ calibreweb_url2 }}; + proxy_set_header X-Script-Name "{{ calibreweb_url2 }}"; proxy_pass http://127.0.0.1:8083; } @@ -23,6 +23,6 @@ location {{ calibreweb_url3 }}/ { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; - proxy_set_header X-Script-Name {{ calibreweb_url3 }}; + proxy_set_header X-Script-Name "{{ calibreweb_url3 }}"; proxy_pass http://127.0.0.1:8083; } diff --git a/roles/calibre/defaults/main.yml b/roles/calibre/defaults/main.yml index b41475e23..0f3643735 100644 --- a/roles/calibre/defaults/main.yml +++ b/roles/calibre/defaults/main.yml @@ -34,11 +34,11 @@ calibre_userdb: "{{ calibre_dbpath }}/users.sqlite" # calibre-server --manage-users --userdb /library/calibre/users.sqlite calibre_sample_book: "Metamorphosis-jackson.epub" -# Must be downloadable from http://download.iiab.io/packages +# Must be downloadable from https://download.iiab.io/packages calibre_src_url: "https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py" -calibre_deb_url: "{{ iiab_download_url }}" # http://download.iiab.io/packages +calibre_deb_url: "{{ iiab_download_url }}" # https://download.iiab.io/packages # Above URL must offer both .deb files below: (for scripts/calibre-install-pinned-rpi.sh to run) calibre_deb_pin_version: 3.33.1+dfsg-1 # for calibre_3.33.1+dfsg-1_all.deb (24M, 2018-10-21) calibre_bin_deb_pin_version: "{{ calibre_deb_pin_version }}" # for calibre-bin_3.33.1+dfsg-1_armhf.deb (706K, 2018-10-23) diff --git a/roles/calibre/tasks/enable-or-disable.yml b/roles/calibre/tasks/enable-or-disable.yml new file mode 100644 index 000000000..07a0cc911 --- /dev/null +++ b/roles/calibre/tasks/enable-or-disable.yml @@ -0,0 +1,29 @@ +# http://box:8080 & http://box:8080/mobile WORK BUT OTHER URL'S LIKE http://box/calibre ARE A MESS (BOOKS RARELY DISPLAY) +# +# 2018-08-27 POSSIBLE FIX...CONSIDER THIS ProxyPass / ProxyPassReverse TECHNIQUE: +# https://github.com/iiab/iiab/tree/master/roles/calibre-web/templates/calibre-web.conf.j2 +# (anyway this works great for calibre-web, allowing http://box/books +# to work even better than http://box:8083 when box == 192.168.0.x !) +# +#- name: Attempt to enable http://box/calibre via Apache (UNTESTED) +# command: a2ensite calibre.conf +# when: apache_installed and calibre_enabled +# +#- name: Attempt to disable http://box/calibre via Apache (UNTESTED) +# command: a2dissite calibre.conf +# when: apache_installed and not calibre_enabled + +- name: Enable & (Re)Start 'calibre-serve' service, if calibre_enabled + systemd: + daemon_reload: yes + name: calibre-serve + enabled: yes + state: restarted + when: calibre_enabled + +- name: Disable & Stop 'calibre-serve' service, if not calibre_enabled + systemd: + name: calibre-serve + enabled: no + state: stopped + when: not calibre_enabled diff --git a/roles/calibre/tasks/install.yml b/roles/calibre/tasks/install.yml index 840440583..82218ada0 100644 --- a/roles/calibre/tasks/install.yml +++ b/roles/calibre/tasks/install.yml @@ -1,4 +1,9 @@ -# 1. INSTALL CALIBRE 3.39.1+ or 4.12+ (calibre, calibredb, calibre-server etc) ON ALL OS'S +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# 1. APT INSTALL CALIBRE 4.12+ or 5.12+ (calibre, calibredb, calibre-server etc) ON ALL OS'S - name: "Install OS's latest packages: calibre, calibre-bin" package: @@ -79,6 +84,17 @@ # 5. RECORD Calibre AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'calibre_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: calibre + option: calibre_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'calibre_installed: True'" set_fact: calibre_installed: True diff --git a/roles/calibre/tasks/main.yml b/roles/calibre/tasks/main.yml index 2c05b42de..a6504b658 100644 --- a/roles/calibre/tasks/main.yml +++ b/roles/calibre/tasks/main.yml @@ -19,65 +19,37 @@ quiet: yes -- name: Install Calibre if 'calibre_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: calibre_installed is undefined +- block: -# http://box:8080 & http://box:8080/mobile WORK BUT OTHER URL'S LIKE http://box/calibre ARE A MESS (BOOKS RARELY DISPLAY) -# -# 2018-08-27 POSSIBLE FIX...CONSIDER THIS ProxyPass / ProxyPassReverse TECHNIQUE: -# https://github.com/iiab/iiab/tree/master/roles/calibre-web/templates/calibre-web.conf.j2 -# (anyway this works great for calibre-web, allowing http://box/books -# to work even better than http://box:8083 when box == 192.168.0.x !) -# -#- name: Attempt to enable http://box/calibre via Apache (UNTESTED) -# command: a2ensite calibre.conf -# when: apache_installed and calibre_enabled -# -#- name: Attempt to disable http://box/calibre via Apache (UNTESTED) -# command: a2dissite calibre.conf -# when: apache_installed and not calibre_enabled + - name: Install Calibre if 'calibre_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: calibre_installed is undefined -- name: Enable & (Re)Start 'calibre-serve' service, if calibre_enabled - systemd: - daemon_reload: yes - name: calibre-serve - enabled: yes - state: restarted - when: calibre_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'calibre-serve' service, if not calibre_enabled - systemd: - name: calibre-serve - enabled: no - state: stopped - when: not calibre_enabled + - name: Add 'calibre' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: calibre + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Calibre + - option: description + value: '"Calibre is an extremely popular personal library system for e-books."' + - option: calibre_src_url + value: "{{ calibre_src_url }}" + - option: calibre_dbpath + value: "{{ calibre_dbpath }}" + - option: calibre_port + value: "{{ calibre_port }}" + - option: calibre_enabled + value: "{{ calibre_enabled }}" -#- name: Enable/Disable/Restart Apache if primary -# include_tasks: apache.yml -# when: not nginx_enabled -# -#- name: Enable/Disable/Restart NGINX if primary -# include_tasks: nginx.yml -# when: nginx_enabled + rescue: - -- name: Add 'calibre' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: calibre - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Calibre - - option: description - value: '"Calibre is an extremely popular personal library system for e-books."' - - option: calibre_src_url - value: "{{ calibre_src_url }}" - - option: calibre_dbpath - value: "{{ calibre_dbpath }}" - - option: calibre_port - value: "{{ calibre_port }}" - - option: calibre_enabled - value: "{{ calibre_enabled }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/captiveportal/README.md b/roles/captiveportal/README.md index 11736aadd..ddacbe311 100644 --- a/roles/captiveportal/README.md +++ b/roles/captiveportal/README.md @@ -1,4 +1,4 @@ -_Please Also See: http://FAQ.IIAB.IO > ["Captive Portal Administration: What tips & tricks exist?"](http://wiki.laptop.org/go/IIAB/FAQ#Captive_Portal_Administration:_What_tips_.26_tricks_exist.3F)_ +_Please Also See: http://FAQ.IIAB.IO > ["Captive Portal Administration: What tips & tricks exist?"](https://wiki.iiab.io/go/FAQ#Captive_Portal_Administration:_What_tips_&_tricks_exist%3F)_ ## Theory of Operation diff --git a/roles/captiveportal/tasks/install.yml b/roles/captiveportal/tasks/install.yml index af022f0e9..b76ad39b0 100644 --- a/roles/captiveportal/tasks/install.yml +++ b/roles/captiveportal/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Install packages: python3-dateutil, python3-jinja2" package: name: @@ -26,7 +31,7 @@ mode: "{{ item.mode }}" with_items: - { src: roles/captiveportal/templates/checkurls, dest: /opt/iiab/captiveportal/, mode: '0644' } - - { src: roles/captiveportal/templates/iiab-divert-to-nginx, dest: /usr/sbin/, mode: '0755' } + - { src: roles/captiveportal/templates/iiab-divert-to-nginx.j2, dest: /usr/sbin/iiab-divert-to-nginx, mode: '0755' } - { src: roles/captiveportal/templates/iiab-make-cp-servers.py, dest: /usr/sbin/, mode: '0755' } - name: Install /opt/iiab/captiveportal/capture-wsgi.py from template, mode '0755' (creates the server) @@ -51,6 +56,17 @@ # RECORD Captive Portal AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'captiveportal_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: captiveportal + option: captiveportal_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'captiveportal_installed: True'" set_fact: captiveportal_installed: True diff --git a/roles/captiveportal/tasks/main.yml b/roles/captiveportal/tasks/main.yml index 0b3408b75..bd24b7186 100644 --- a/roles/captiveportal/tasks/main.yml +++ b/roles/captiveportal/tasks/main.yml @@ -19,27 +19,33 @@ quiet: yes -- name: Install Captive Portal if 'captiveportal_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: captiveportal_installed is undefined +- block: + - name: Install Captive Portal if 'captiveportal_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: captiveportal_installed is undefined -- name: Enable or Disable Captive Portal - include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'captiveportal' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: captiveportal + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Captive Portal + - option: description + value: '"Captive Portal tries to open the browser automatically, so users don''t have to type in URL''s like http://box.lan in support of kiosk-like situations, in multilingual and less literate communities."' + - option: captiveportal_install + value: "{{ captiveportal_install }}" + - option: captiveportal_enabled + value: "{{ captiveportal_enabled }}" -- name: Add 'captiveportal' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: captiveportal - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Captive Portal - - option: description - value: '"Captive Portal tries to open the browser automatically, so users don''t have to type in URL''s like http://box.lan in support of kiosk-like situations, in multilingual and less literate communities."' - - option: captiveportal_install - value: "{{ captiveportal_install }}" - - option: captiveportal_enabled - value: "{{ captiveportal_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/captiveportal/templates/iiab-divert-to-nginx b/roles/captiveportal/templates/iiab-divert-to-nginx.j2 similarity index 63% rename from roles/captiveportal/templates/iiab-divert-to-nginx rename to roles/captiveportal/templates/iiab-divert-to-nginx.j2 index c708de87a..8d6d06b2e 100755 --- a/roles/captiveportal/templates/iiab-divert-to-nginx +++ b/roles/captiveportal/templates/iiab-divert-to-nginx.j2 @@ -1,4 +1,4 @@ #!/bin/bash -x -awk '{print("address=/" $1 "/172.18.96.1")}' /opt/iiab/captiveportal/checkurls > /etc/dnsmasq.d/capture +awk '{print("address=/" $1 "/{{ lan_ip }}")}' /opt/iiab/captiveportal/checkurls > /etc/dnsmasq.d/capture echo "#following tells windows 7 that captive portal is active" >> /etc/dnsmasq.d/capture echo "address=/dns.msftncsi.com/131.107.255.255" >> /etc/dnsmasq.d/capture diff --git a/roles/cups/README.md b/roles/cups/README.md index 493673715..cd727be5f 100644 --- a/roles/cups/README.md +++ b/roles/cups/README.md @@ -2,13 +2,13 @@ [CUPS](https://en.wikipedia.org/wiki/CUPS) (also known as the "Common UNIX Printing System") is the standards-based, open source printing system for Linux and macOS. -It allows your [Internet-in-a-Box (IIAB)](http://internet-in-a-box.org) to act as a print server. +It allows your [Internet-in-a-Box (IIAB)](https://internet-in-a-box.org) to act as a print server. This can be useful if a printer is attached to your IIAB — so student/teacher print jobs from client computers and phones can be processed — and then sent to the appropriate printer. ## Using it -Make sure your IIAB was installed with these 2 lines in [/etc/iiab/local_vars.yml](http://faq.iiab.io/#What_is_local_vars.yml_and_how_do_I_customize_it.3F) : +Make sure your IIAB was installed with these 2 lines in [/etc/iiab/local_vars.yml](http://faq.iiab.io/#What_is_local_vars.yml_and_how_do_I_customize_it%3F) : ``` cups_install: True diff --git a/roles/cups/tasks/install.yml b/roles/cups/tasks/install.yml index ea073de16..55209a50b 100644 --- a/roles/cups/tasks/install.yml +++ b/roles/cups/tasks/install.yml @@ -2,6 +2,11 @@ # (OR ANY MEMBER OF LINUX GROUP 'lpadmin') AS SET UP BELOW... +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Install 'cups' package package: name: cups @@ -49,19 +54,34 @@ blockinfile: path: /etc/cups/cupsd.conf insertafter: '^$' - block: |2 # Indent with 2 spaces, and surround block with 2 comment lines: "# BEGIN ANSIBLE MANAGED BLOCK", "# END ANSIBLE MANAGED BLOCK" + block: |2 # |n MEANS: Set the block's left edge n CHARACTERS TO THE RIGHT of *this line's* indentation -- where n is {1..9} -- instead of setting its left edge to the 1st non-blank line's indentation below. Also surround block with comment lines: "# BEGIN ANSIBLE MANAGED BLOCK", "# END ANSIBLE MANAGED BLOCK" AuthType Default Require user @SYSTEM -- name: "CUPS web administration: Create Linux username 'Admin' with password 'changeme' in Linux group 'lpadmin' (shell: /usr/sbin/nologin, create_home: no)" +- name: "CUPS web administration: Create Linux username 'Admin' in Linux group 'lpadmin' (shell: /usr/sbin/nologin, create_home: no)" user: name: Admin append: yes # Don't clobber other groups, that other IIAB Apps might need. groups: lpadmin - password: "{{ 'changeme' | password_hash('sha512') }}" # Random salt. Presumably runs 5000 rounds of SHA-512 per /etc/login.defs & /etc/pam.d/common-password -- https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#encrypting-and-checksumming-strings-and-passwords + #password: "{{ 'changeme' | password_hash('sha512') }}" # Random salt. Presumably runs 5000 rounds of SHA-512 per /etc/login.defs & /etc/pam.d/common-password -- https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html#hashing-and-encrypting-strings-and-passwords create_home: no shell: /usr/sbin/nologin # Debian/Ubuntu norm -- instead of /sbin/nologin, /bin/false +# 2024-05-01: Above password-setting approach no longer works w/ Ansible 2.17 RC1 (#3727). +# Ansible STOPS with this error... +# +# "[DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated. The Python crypt module is +# deprecated and will be removed from Python 3.13. Install the passlib library for continued encryption +# functionality. This feature will be removed in version 2.17. Deprecation warnings can be disabled by +# setting deprecation_warnings=False in ansible.cfg." +# +# ...so we instead use Linux's "chpasswd" command (below!) + +- name: Use chpasswd to set Linux username 'Admin' password to 'changeme' + command: chpasswd + args: + stdin: Admin:changeme + # - name: Add user '{{ iiab_admin_user }}' to Linux group 'lpadmin' -- for CUPS web administration (or modify default 'SystemGroup lpadmin' in /etc/cups/cups-files.conf -- in coordination with ~14 -> ~15 '@SYSTEM' lines in /etc/cups/cupsd.conf) # #command: "gpasswd -a {{ iiab_admin_user | quote }} lpadmin" # #command: "gpasswd -d {{ iiab_admin_user | quote }} lpadmin" @@ -76,14 +96,14 @@ name: cups state: started -# - name: "Authorize Nearby IP Addresses: Run 'cupsctl --remote-admin --share-printers --user-cancel-any' to enable http://192.168.0.x:631 AND http://172.18.96.1:631 (if cups_enabled) -- REPEATED USE OF 'cupsctl' COMMANDS CAN *DAMAGE* /etc/cups/cupsd.conf BY ADDING DUPLICATE LINES (AND WORSE!) -- SO PLEASE ALSO MANUALLY RUN 'sudo cupsctl' AND 'sudo cupsd -t' TO VERIFY /etc/cups/cupsd.conf" +# - name: "Authorize Nearby IP Addresses: Run 'cupsctl --remote-admin --share-printers --user-cancel-any' to enable http://192.168.0.x:631 AND http://{{ lan_ip }}:631 (if cups_enabled) -- REPEATED USE OF 'cupsctl' COMMANDS CAN *DAMAGE* /etc/cups/cupsd.conf BY ADDING DUPLICATE LINES (AND WORSE!) -- SO PLEASE ALSO MANUALLY RUN 'sudo cupsctl' AND 'sudo cupsd -t' TO VERIFY /etc/cups/cupsd.conf" # command: cupsctl --remote-admin --share-printers --user-cancel-any # 2021-07-11: BOTH FLAGS *CANNOT* BE USED TOGETHER -- CHOOSE ONE OR THE OTHER: # (1) '--remote-admin' AS ABOVE, OR (2) '--remote-any' AS BELOW. # (RUN 'cupsctl' WITHOUT PARAMETERS TO CONFIRM THIS!) -- name: "Authorize All IP Addresses: Run 'cupsctl --remote-any --share-printers --user-cancel-any' to enable http://192.168.0.x:631 AND http://172.18.96.1:631 AND http://10.8.0.y:631 (if cups_enabled) -- REPEATED USE OF 'cupsctl' COMMANDS CAN *DAMAGE* /etc/cups/cupsd.conf BY ADDING DUPLICATE LINES (AND WORSE!) -- SO PLEASE ALSO MANUALLY RUN 'sudo cupsctl' AND 'sudo cupsd -t' TO VERIFY /etc/cups/cupsd.conf" +- name: "Authorize All IP Addresses: Run 'cupsctl --remote-any --share-printers --user-cancel-any' to enable http://192.168.0.x:631 AND http://{{ lan_ip }}:631 AND http://10.8.0.y:631 (if cups_enabled) -- REPEATED USE OF 'cupsctl' COMMANDS CAN *DAMAGE* /etc/cups/cupsd.conf BY ADDING DUPLICATE LINES (AND WORSE!) -- SO PLEASE ALSO MANUALLY RUN 'sudo cupsctl' AND 'sudo cupsd -t' TO VERIFY /etc/cups/cupsd.conf" command: cupsctl --remote-any --share-printers --user-cancel-any # 2021-07-11: In theory 'cupsctl' stanzas could be put in enable-or-disable.yml @@ -96,7 +116,7 @@ # command: cupsctl --no-remote-admin --no-remote-any --no-share-printers --no-user-cancel-any --no-debug-logging # when: not cups_enabled -# - name: "2021-07-14: EXPERIMENTALLY ADD DIRECTIVES TO /etc/cups/cupsd.conf followed by 'systemctl restart cups'. As should no longer be nec thanks to NEW cups/templates/cups.conf for /etc/nginx/conf.d/cups.conf (followed by 'systemctl restart nginx'). Which FIXED URL'S LIKE: http://box/print, http://box.lan/print, http://192.168.0.x/print, http://172.18.96.1/print and http://10.8.0.x/print (WITH OR WITHOUT THE TRAILING SLASH!) RECAP: (1) So be it that these 2 URL'S STILL DON'T WORK: http://box:631, http://box.lan:631 (due to CUPS' internal web server's overly stringent hostname checks, i.e. '400 Bad Request' and 'Request from \"localhost\" using invalid Host: field \"box[.lan]:631\".' in /var/log/cups/error_log) -- (2) While these 2 URL'S STILL DO WORK: http://localhost:631, http://127.0.0.1:631 -- (3) Whereas these 3 URL'S MAY WORK, DEPENDING ON 'cupsctl' COMMAND(S) ABOVE: http://192.168.0.x:631, http://172.18.96.1:631, http://10.8.0.x:631" +# - name: "2021-07-14: EXPERIMENTALLY ADD DIRECTIVES TO /etc/cups/cupsd.conf followed by 'systemctl restart cups'. As should no longer be nec thanks to NEW cups/templates/cups.conf for /etc/nginx/conf.d/cups.conf (followed by 'systemctl restart nginx'). Which FIXED URL'S LIKE: http://box/print, http://box.lan/print, http://192.168.0.x/print, http://{{ lan_ip }}/print and http://10.8.0.x/print (WITH OR WITHOUT THE TRAILING SLASH!) RECAP: (1) So be it that these 2 URL'S STILL DON'T WORK: http://box:631, http://box.lan:631 (due to CUPS' internal web server's overly stringent hostname checks, i.e. '400 Bad Request' and 'Request from \"localhost\" using invalid Host: field \"box[.lan]:631\".' in /var/log/cups/error_log) -- (2) While these 2 URL'S STILL DO WORK: http://localhost:631, http://127.0.0.1:631 -- (3) Whereas these 3 URL'S MAY WORK, DEPENDING ON 'cupsctl' COMMAND(S) ABOVE: http://192.168.0.x:631, http://{{ lan_ip }}:631, http://10.8.0.x:631" # lineinfile: # path: /etc/cups/cupsd.conf # line: "{{ item }}" @@ -105,7 +125,7 @@ # - "HostNameLookups On" # More False Leads: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=530027 # - "ServerAlias *" # - "#ServerName {{ iiab_hostname }}.{{ iiab_domain }}" # box.lan -# - "#Listen {{ lan_ip }}:631" # 172.18.96.1 +# - "#Listen {{ lan_ip }}:631" # e.g. 10.10.10.10 # - "#Listen 127.0.0.1:631" # - "#Listen 0.0.0.0:631" # - "#Listen *:631" @@ -124,6 +144,17 @@ # RECORD CUPS AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'cups_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: cups + option: cups_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'cups_installed: True'" set_fact: cups_installed: True diff --git a/roles/cups/tasks/main.yml b/roles/cups/tasks/main.yml index 2c9531814..a709ac090 100644 --- a/roles/cups/tasks/main.yml +++ b/roles/cups/tasks/main.yml @@ -23,26 +23,33 @@ quiet: yes -- name: Install CUPS if 'cups_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: cups_installed is undefined +- block: + - name: Install CUPS if 'cups_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: cups_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'cups' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: cups + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: CUPS + - option: description + value: '"CUPS (Common UNIX Printing System) is a modular printing system that allows a computer to act as a print server. A computer running CUPS is a host that can accept print jobs from client computers, process them, and send them to the appropriate printer."' + - option: cups_install + value: "{{ cups_install }}" + - option: cups_enabled + value: "{{ cups_enabled }}" -- name: Add 'cups' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: cups - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: CUPS - - option: description - value: '"CUPS (Common UNIX Printing System) is a modular printing system that allows a computer to act as a print server. A computer running CUPS is a host that can accept print jobs from client computers, process them, and send them to the appropriate printer."' - - option: cups_install - value: "{{ cups_install }}" - - option: cups_enabled - value: "{{ cups_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/cups/templates/cups.conf.j2 b/roles/cups/templates/cups.conf.j2 index abec5152d..3d4f4f53f 100644 --- a/roles/cups/templates/cups.conf.j2 +++ b/roles/cups/templates/cups.conf.j2 @@ -21,7 +21,7 @@ location ~ ^/print(|/.*)$ { # '~' -> '~*' for case-insensitive regex return 301 http://localhost:631; } - return 301 http://$host:631; # For 192.168.0.x, 172.18.96.1, 10.8.0.y ETC + return 301 http://$host:631; # For 192.168.0.x, 10.10.10.10, 172.18.96.1, 10.8.0.y ETC } diff --git a/roles/firmware/tasks/download.yml b/roles/firmware/tasks/download.yml index d35147013..abda2e6b4 100644 --- a/roles/firmware/tasks/download.yml +++ b/roles/firmware/tasks/download.yml @@ -1,22 +1,48 @@ -- name: Back up original e.g. OS-provided firmware (for RPi internal WiFi) - copy: - src: "/lib/firmware/brcm/{{ item }}" - dest: "/lib/firmware/brcm/{{ item }}.orig" - with_items: - - brcmfmac43430-sdio.bin - - brcmfmac43455-sdio.bin - - brcmfmac43455-sdio.clm_blob +# 2023-02-25: MONITOR FIRMWARE UPDATES in 3 places especially... +# +# 1. apt changelog firmware-brcm80211 +# https://github.com/RPi-Distro/firmware-nonfree -> debian/config/brcm80211 (brcm, cypress) +# https://archive.raspberrypi.org/debian/dists/bullseye/main/binary-arm64/Packages (1.1MB text file, look inside for summary of latest firmware-brcm80211) +# https://archive.raspberrypi.org/debian/pool/main/f/firmware-nonfree/ -> firmware-brcm80211_* e.g.: +# https://archive.raspberrypi.org/debian/pool/main/f/firmware-nonfree/firmware-brcm80211_20190114-1+rpt11_all.deb from 2021-01-25 +# https://archive.raspberrypi.org/debian/pool/main/f/firmware-nonfree/firmware-brcm80211_20210315-3+rpt4_all.deb from 2021-12-06 +# https://archive.raspberrypi.org/debian/pool/main/f/firmware-nonfree/firmware-brcm80211_20221012-1~bpo11+1+rpt1_all.deb from 2022-11-17 +# 2. apt changelog linux-firmware-raspi +# https://packages.ubuntu.com/search?keywords=linux-firmware-raspi +# 3. https://github.com/moodlebox/moodlebox/blob/main/roles/accesspoint/tasks/main.yml -- name: Download high-capacity older firmware (for RPi internal WiFi, per https://github.com/iiab/iiab/issues/823#issuecomment-662285202) +#- name: Back up 4 OS-provided WiFi firmware files (incl symlink contents) to /lib/firmware/cypress/*.orig +- name: Back up 4 OS-provided WiFi firmware files (replicate any symlinks) to /lib/firmware/cypress/*.orig -- /usr/bin/iiab-check-firmware will later do similar (e.g. as firmware install completes) -- moving 2-or-4 of these to .YYYY-MM-DD-HH:MM:SS ("doubly timestamping" to preserve BOTH last-modif & moving date) + # copy: + # src: /lib/firmware/cypress/{{ item }} + # dest: /lib/firmware/cypress/{{ item }}.orig + # #local_follow: False # FAILS TO PRESERVE LINKS (ansible/ansible#74777) e.g. /lib/firmware/cypress/cyfmac43455-sdio.bin -> /etc/alternatives/cyfmac43455-sdio.bin -> ... + # 2023-05-01 CLARIF OF BELOW: + # 1) Even if 'mv' fails, no matter it'll continue to 'cp' below + # 2) 'cp -P' == 'cp --no-dereference' sufficient to replicate these symlinks and files ('cp -d' & 'cp -a' are incrementally stronger, and so probably can't hurt) + shell: | + mv /lib/firmware/cypress/{{ item }}.orig /lib/firmware/cypress/{{ item }}.orig.$(date +%F-%T) + cp -a /lib/firmware/cypress/{{ item }} /lib/firmware/cypress/{{ item }}.orig + with_items: + - cyfmac43430-sdio.bin + - cyfmac43430-sdio.clm_blob + - cyfmac43455-sdio.bin + - cyfmac43455-sdio.clm_blob + #ignore_errors: yes # 2023-02-25: Let's INTENTIONALLY surface any errors, e.g. if any future RasPiOS or Ubuntu-on-Rpi lack some of the above 4 files/links? + +- name: Download higher-capacity firmwares (for RPi internal WiFi, per https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and https://github.com/iiab/iiab/issues/2853) get_url: - url: "{{ item.url }}" - dest: "{{ item.dest }}" + url: "{{ iiab_download_url }}/{{ item }}" + dest: /lib/firmware/cypress/ timeout: "{{ download_timeout }}" with_items: - - { url: 'http://d.iiab.io/packages/brcmfmac43430-sdio.bin_2018-09-11_7.45.98.65', dest: '/lib/firmware/brcm/brcmfmac43430-sdio.bin.iiab' } - - { url: 'http://d.iiab.io/packages/brcmfmac43430-sdio.clm_blob_2018-09-11_7.45.98.65', dest: '/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob.iiab' } - - { url: 'http://d.iiab.io/packages/brcmfmac43455-sdio.bin_2015-03-01_7.45.18.0_ub19.10.1', dest: '/lib/firmware/brcm/brcmfmac43455-sdio.bin.iiab' } - - { url: 'http://d.iiab.io/packages/brcmfmac43455-sdio.clm_blob_2018-02-26_rpi', dest: '/lib/firmware/brcm/brcmfmac43455-sdio.clm_blob.iiab' } + - brcmfmac43455-sdio.bin_2021-11-30_minimal # 19 -- SAME AS RASPIOS & UBUNTU'S https://github.com/RPi-Distro/firmware-nonfree/blob/feeeda21e930c2e182484e8e1269b61cca2a8451/debian/config/brcm80211/cypress/cyfmac43455-sdio-minimal.bin + - brcmfmac43455-sdio.bin_2021-10-05_3rd-trial-minimal # 24 -- from https://github.com/iiab/iiab/issues/2853#issuecomment-934293015 + - brcmfmac43455-sdio.clm_blob_2021-11-17_rpi # Works w/ both above -- SAME AS RASPIOS & UBUNTU'S https://github.com/RPi-Distro/firmware-nonfree/blob/dc406650e840705957f8403efeacf71d2d7543b3/debian/config/brcm80211/cypress/cyfmac43455-sdio.clm_blob + - brcmfmac43455-sdio.bin_2015-03-01_7.45.18.0_ub19.10.1 # 32 -- from https://github.com/iiab/iiab/issues/823#issuecomment-662285202 + - brcmfmac43455-sdio.clm_blob_2018-02-26_rpi + - brcmfmac43430-sdio.bin_2018-09-11_7.45.98.65 # 30 -- from https://github.com/iiab/iiab/issues/823#issuecomment-662285202 + - brcmfmac43430-sdio.clm_blob_2018-09-11_7.45.98.65 # RECORD firmware AS DOWNLOADED diff --git a/roles/firmware/tasks/install.yml b/roles/firmware/tasks/install.yml index ce7004ea2..4f323ca72 100644 --- a/roles/firmware/tasks/install.yml +++ b/roles/firmware/tasks/install.yml @@ -2,6 +2,75 @@ include_tasks: download.yml when: firmware_downloaded is undefined # SEE ALSO firmware_installed below + +# Set 2 symlinks for RPi 3 B+ and 4 (43455) +# COMPARE: update-alternatives --display cyfmac43455-sdio.bin +# https://github.com/moodlebox/moodlebox/blob/main/roles/accesspoint/tasks/main.yml#L3-L6 + +- name: Populate rpi3bplus_rpi4_wifi_firmwares dictionary (lookup table for operator-chosen .bin and .clm_blob files in /lib/firmware/cypress) + set_fact: + rpi3bplus_rpi4_wifi_firmwares: # Dictionary keys (left side) are always strings, e.g. "19" + os: + - cyfmac43455-sdio.bin.orig # 2023-02-25: 7.45.241 from 2021-11-01 on Ubuntu 22.04.2 too (cyfmac43455-sdio-standard.bin) + - cyfmac43455-sdio.clm_blob.orig # On Ubuntu 22.04.2 too (brcmfmac43455-sdio.clm_blob_2021-11-17_rpi) + ub: + - cyfmac43455-sdio.bin.distrib # 2023-02-25: STALE 7.45.234 from 2021-04-15; on Ubuntu 22.04.2 NOT RasPiOS + - cyfmac43455-sdio.clm_blob.distrib # 4.7K instead of 2.7K w/ above "os" + 19: + - brcmfmac43455-sdio.bin_2021-11-30_minimal # On Ubuntu 22.04.2 too (cyfmac43455-sdio-minimal.bin) + - brcmfmac43455-sdio.clm_blob_2021-11-17_rpi # On Ubuntu 22.04.2 too (cyfmac43455-sdio.clm_blob) + 24: + - brcmfmac43455-sdio.bin_2021-10-05_3rd-trial-minimal + - brcmfmac43455-sdio.clm_blob_2021-11-17_rpi # On Ubuntu 22.04.2 too (cyfmac43455-sdio.clm_blob) + 32: + - brcmfmac43455-sdio.bin_2015-03-01_7.45.18.0_ub19.10.1 + - brcmfmac43455-sdio.clm_blob_2018-02-26_rpi # 14K instead of 2.7K w/ above "os" + +- name: Symlink /lib/firmware/cypress/cyfmac43455-sdio.bin.iiab -> {{ rpi3bplus_rpi4_wifi_firmwares[rpi3bplus_rpi4_wifi_firmware][0] }} (as rpi3bplus_rpi4_wifi_firmware is "{{ rpi3bplus_rpi4_wifi_firmware }}") + file: + src: "{{ rpi3bplus_rpi4_wifi_firmwares[rpi3bplus_rpi4_wifi_firmware][0] }}" + path: /lib/firmware/cypress/cyfmac43455-sdio.bin.iiab + state: link + force: yes + +- name: Symlink /lib/firmware/cypress/cyfmac43455-sdio.clm_blob.iiab -> {{ rpi3bplus_rpi4_wifi_firmwares[rpi3bplus_rpi4_wifi_firmware][1] }} (as rpi3bplus_rpi4_wifi_firmware is "{{ rpi3bplus_rpi4_wifi_firmware }}") + file: + src: "{{ rpi3bplus_rpi4_wifi_firmwares[rpi3bplus_rpi4_wifi_firmware][1] }}" + path: /lib/firmware/cypress/cyfmac43455-sdio.clm_blob.iiab + state: link + force: yes + + +# Set 2 symlinks for RPi Zero W and 3 (43430) + +- name: Populate rpizerow_rpi3_wifi_firmwares dictionary (lookup table for operator-chosen .bin and .clm_blob files in /lib/firmware/cypress) + set_fact: + rpizerow_rpi3_wifi_firmwares: + os: + - cyfmac43430-sdio.bin.orig # 2023-02-25: 7.45.98 from 2021-07-19 on Ubuntu 22.04.2 too + - cyfmac43430-sdio.clm_blob.orig # On Ubuntu 22.04.2 too + ub: + - cyfmac43430-sdio.bin.distrib # 2023-02-25: STALE 7.45.98.118 from 2021-03-30; on Ubuntu 22.04.2 NOT RasPiOS + - cyfmac43430-sdio.clm_blob.distrib # Identical to above 4.7K cyfmac43430-sdio.clm_blob + 30: + - brcmfmac43430-sdio.bin_2018-09-11_7.45.98.65 + - brcmfmac43430-sdio.clm_blob_2018-09-11_7.45.98.65 # 14K instead of 4.7K w/ above "os" & "ub" + +- name: Symlink /lib/firmware/cypress/cyfmac43430-sdio.bin.iiab -> {{ rpizerow_rpi3_wifi_firmwares[rpizerow_rpi3_wifi_firmware][0] }} (as rpizerow_rpi3_wifi_firmware is "{{ rpizerow_rpi3_wifi_firmware }}") + file: + src: "{{ rpizerow_rpi3_wifi_firmwares[rpizerow_rpi3_wifi_firmware][0] }}" + path: /lib/firmware/cypress/cyfmac43430-sdio.bin.iiab + state: link + force: yes + +- name: Symlink /lib/firmware/cypress/cyfmac43430-sdio.clm_blob.iiab -> {{ rpizerow_rpi3_wifi_firmwares[rpizerow_rpi3_wifi_firmware][1] }} (as rpizerow_rpi3_wifi_firmware is "{{ rpizerow_rpi3_wifi_firmware }}") + file: + src: "{{ rpizerow_rpi3_wifi_firmwares[rpizerow_rpi3_wifi_firmware][1] }}" + path: /lib/firmware/cypress/cyfmac43430-sdio.clm_blob.iiab + state: link + force: yes + + - name: 'Install from template: /usr/bin/iiab-check-firmware, /etc/systemd/system/iiab-check-firmware.service & /etc/profile.d/iiab-firmware-warn.sh' template: src: "{{ item.src }}" @@ -12,7 +81,7 @@ - { src: 'iiab-check-firmware.service', dest: '/etc/systemd/system/', mode: '0644' } - { src: 'iiab-firmware-warn.sh', dest: '/etc/profile.d/', mode: '0644' } -- name: Enable & (Re)Start iiab-check-firmware.service (also runs on each boot) +- name: Enable & (Re)Start iiab-check-firmware.service (also runs on each boot) -- finalizing 2-or-4 symlink chains e.g. /lib/firmware/cypress/X.{bin|blob} -> /lib/firmware/cypress/X.{bin|blob}.iiab -> CHOSEN-FIRMWARE-FILE-OR-LINK systemd: name: iiab-check-firmware.service daemon_reload: yes diff --git a/roles/firmware/tasks/main.yml b/roles/firmware/tasks/main.yml index a199f2630..dfd094acb 100644 --- a/roles/firmware/tasks/main.yml +++ b/roles/firmware/tasks/main.yml @@ -1,14 +1,30 @@ -# Please set 'wifi_hotspot_capacity_rpi_fix: True' in /etc/iiab/local_vars.yml -# to restore support for 30-32 WiFi client devices on most Raspberry Pis that -# have internal WiFi. This installs firmware 7.45.98.65 for Zero W and RPi 3 -# and firmware 7.45.18.0 for RPi 3 B+ and RPi 4. Capacity testing writeup: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# Plz set 'rpi3bplus_rpi4_wifi_firmware' and 'rpizerow_rpi3_wifi_firmware' in +# /etc/iiab/local_vars.yml to increase (or modify) the number of student WiFi +# client devices that can access your Raspberry Pi's internal WiFi hotspot. + +# If IIAB's already installed, you should then run 'cd /opt/iiab/iiab' and +# then 'sudo ./runrole firmware' (DO RUN iiab-check-firmware FOR MORE TIPS!) + +# 2018-2023 Background & Progress: +# +# Raspberry Pi 3 used to support 32 WiFi connections but is now limited to [4-10] +# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# Opinions about Pi 4B/3B+ WiFi features [practical AP firmware for schools!] +# https://github.com/iiab/iiab/issues/2853#issuecomment-957836892 +# RPi WiFi hotspot firmware reliability fix, incl new/better choices for 3B+ & 4 +# https://github.com/iiab/iiab/pull/3103 +# Set WiFi firmware in /lib/firmware/cypress due to RasPiOS & Ubuntu changes +# https://github.com/iiab/iiab/pull/3482 +# RISK: What USB 3.0 stick/drive patterns degrade a Raspberry Pi's 2.4GHz WiFi? +# https://github.com/iiab/iiab/issues/2638 + +# β–Ί SEE "MONITOR FIRMWARE UPDATES in 3 places especially" in tasks/download.yml β—„ - name: Install firmware (for RPi internal WiFi) include_tasks: install.yml - #when: firmware_installed is undefined + when: firmware_installed is undefined -# Two variable are placed in /etc/iiab/iiab_state.yml: +# Two variables are placed in /etc/iiab/iiab_state.yml: # # - firmware_downloaded (set in download.yml) is used in install.yml # diff --git a/roles/firmware/templates/iiab-check-firmware b/roles/firmware/templates/iiab-check-firmware index aeda2366e..f10cd752b 100644 --- a/roles/firmware/templates/iiab-check-firmware +++ b/roles/firmware/templates/iiab-check-firmware @@ -1,66 +1,71 @@ #!/bin/bash -WARN=0 -DATE=$(date +%F-%T) +# The 1st time /usr/bin/iiab-check-firmware runs (at the end of +# firmware/tasks/install.yml) 2-4 lynchpin top links are put in place, +# finalizing symlink chains like: +# +# /lib/firmware/cypress/X.{bin|blob} -> +# /lib/firmware/cypress/X.{bin|blob}.iiab -> +# CHOSEN-FIRMWARE-FILE-OR-LINK +# +# Also backing up top-of-chain originals (file or link!) by moving these to: +# +# /lib/firmware/cypress/.YYYY-MM-DD-HH:MM:SS +# +# NOTE these are "doubly timestamped" to preserve BOTH last-modif & moving date. -# 2021-08-18: bash scripts using default_vars.yml &/or local_vars.yml +# 2023-02-25: bash scripts using default_vars.yml &/or local_vars.yml # https://github.com/iiab/iiab-factory/blob/master/iiab -# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L13 +# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L10-14 # https://github.com/iiab/iiab/blob/master/roles/network/templates/gateway/iiab-gen-iptables#L48-L52 -# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L25-L34 -# https://github.com/iiab/iiab/blob/master/roles/openvpn/templates/iiab-support READS AND WRITES, INCL NON-BOOLEAN +# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L23-L39 +# https://github.com/iiab/iiab/blob/master/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support READS AND WRITES, INCL NON-BOOLEAN -if grep -q '^wifi_hotspot_capacity_rpi_fix:\s\+[fF]alse\b' /etc/iiab/local_vars.yml ; then - echo "'wifi_hotspot_capacity_rpi_fix: False' found in /etc/iiab/local_vars.yml" - echo "...so WiFi firmware will NOT be checked or replaced." +iiab_var_value() { + v1=$(grep "^$1:\s" /opt/iiab/iiab/vars/default_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + v2=$(grep "^$1:\s" /etc/iiab/local_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + [ "$v2" != "" ] && echo $v2 || echo $v1 # [ "$v2" ] ALSO WORKS +} - exit 0 -fi - -echo -e "'wifi_hotspot_capacity_rpi_fix: True' presumed..." -echo -e "...in /etc/iiab/local_vars.yml (or /opt/iiab/iiab/vars/default_vars.yml ?)\n" - -if ! $(diff -q /lib/firmware/brcm/brcmfmac43455-sdio.bin.iiab /lib/firmware/brcm/brcmfmac43455-sdio.bin); then - mv /lib/firmware/brcm/brcmfmac43455-sdio.bin /lib/firmware/brcm/brcmfmac43455-sdio.bin.$DATE - cp /lib/firmware/brcm/brcmfmac43455-sdio.bin.iiab /lib/firmware/brcm/brcmfmac43455-sdio.bin - echo "Replacing /lib/firmware/brcm/brcmfmac43455-sdio.bin" - WARN=1 -fi - -if ! $(diff -q /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob.iiab /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob); then - mv /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob.$DATE - cp /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob.iiab /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob - echo "Replacing /lib/firmware/brcm/brcmfmac43455-sdio.clm_blob" - WARN=1 -fi - -if ! $(diff -q /lib/firmware/brcm/brcmfmac43430-sdio.bin.iiab /lib/firmware/brcm/brcmfmac43430-sdio.bin); then - mv /lib/firmware/brcm/brcmfmac43430-sdio.bin /lib/firmware/brcm/brcmfmac43430-sdio.bin.$DATE - cp /lib/firmware/brcm/brcmfmac43430-sdio.bin.iiab /lib/firmware/brcm/brcmfmac43430-sdio.bin - cp /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob.iiab /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob - echo "Replacing /lib/firmware/brcm/brcmfmac43430-sdio.bin" - WARN=1 -fi - -if ! $(diff -q /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob.iiab /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob); then - mv /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob.$DATE - cp /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob.iiab /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob - echo "Replacing /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob" - WARN=1 -fi - -if [ "$WARN" = "1" ]; then - echo -e "\n \e[41;1mWiFi Firmware has been replaced, per iiab/iiab#823.\e[0m" - echo -e " \e[41;1mReboot is required to activate.\e[0m\n" - touch /.fw_replaced - #echo "rebooting..." - #reboot -else - echo -e " WiFi Firmware check \e[42;1mPASSED\e[0m, per iiab/iiab#823." # Or \e[92m for green on black - echo -e " (Assuming you've rebooted since it was replaced!)\n" - if [ -f /.fw_replaced ]; then - rm /.fw_replaced +link_fw() { + if [[ $(readlink /lib/firmware/cypress/$1) != $1.iiab ]] ; then + echo + mv /lib/firmware/cypress/$1 /lib/firmware/cypress/$1.$(date +%F-%T) + ln -s $1.iiab /lib/firmware/cypress/$1 + echo -e "\e[1mSymlinked /lib/firmware/cypress/$1 -> $1.iiab\e[0m" + touch /tmp/.fw_modified fi +} + +if [[ $(iiab_var_value rpi3bplus_rpi4_wifi_firmware) != "os" ]] ; then + link_fw cyfmac43455-sdio.bin + link_fw cyfmac43455-sdio.clm_blob fi -# exit 0 +if [[ $(iiab_var_value rpizerow_rpi3_wifi_firmware) != "os" ]] ; then + link_fw cyfmac43430-sdio.bin + link_fw cyfmac43430-sdio.clm_blob +fi + +if [ -f /tmp/.fw_modified ]; then + bash /etc/profile.d/iiab-firmware-warn.sh +else + echo -e "\n\e[1mWiFi Firmware links in /lib/firmware/cypress appear \e[92mCORRECT\e[0m\e[1m, per iiab/iiab#3482\e[0m" + echo + echo -e "\e[100;1m(No reboot appears necessary!)\e[0m" + echo + echo -e "NOTE: If you change rpi3bplus_rpi4_wifi_firmware or rpizerow_rpi3_wifi_firmware" + echo -e "settings in /etc/iiab/local_vars.yml, please then run:" + echo + echo -e " cd /opt/iiab/iiab" + echo -e " sudo iiab-hotspot-off # NO LONGER NEC? eg to restore 'wifi_up_down: True'" + echo -e " sudo ./runrole --reinstall firmware" + echo -e " sudo iiab-network # SOMETIMES NECESSARY" + echo -e " sudo iiab-hotspot-on # NO LONGER NEC? eg to restore 'wifi_up_down: True'" + echo -e " sudo reboot\n" + #echo + #echo -e "Disconnect your power cord before rebooting, for better WiFi firmware results.\n" +fi + +# \e[1m = bright white \e[100;1m = bright white, on gray \n\e[41;1m = bright white, on red +# \e[42;1m = bright white, on bright green \e[92m = green on black diff --git a/roles/firmware/templates/iiab-firmware-warn.sh b/roles/firmware/templates/iiab-firmware-warn.sh index 55120ffbd..f9507496b 100644 --- a/roles/firmware/templates/iiab-firmware-warn.sh +++ b/roles/firmware/templates/iiab-firmware-warn.sh @@ -1,12 +1,9 @@ #!/bin/bash -if [ -f /.fw_replaced ]; then - echo -e "\n \e[41;1mWiFi Firmware has been replaced, per iiab/iiab#823.\e[0m" - if grep -q '^wifi_hotspot_capacity_rpi_fix:\s\+[fF]alse\b' /etc/iiab/local_vars.yml ; then - echo -e " \e[100;1mIf you want these warnings to stop, run:\e[0m" - echo - echo -e " \e[100;1msudo rm /.fw_replaced\e[0m\n" - else - echo -e " \e[41;1mReboot is required to activate.\e[0m\n" - fi +if [ -f /tmp/.fw_modified ]; then + echo -e "\n\e[41;1mWiFi Firmware link(s) modified, per iiab/iiab#3482: PLEASE REBOOT!\e[0m" + echo + echo -e "If you want this warning to stop, reboot to remove /tmp/.fw_modified\n" fi + +# \e[1m = bright white \e[100;1m = bright white, on gray \n\e[41;1m = bright white, on red diff --git a/roles/gitea/defaults/main.yml b/roles/gitea/defaults/main.yml index 20164beb2..0032f1d3d 100644 --- a/roles/gitea/defaults/main.yml +++ b/roles/gitea/defaults/main.yml @@ -9,7 +9,7 @@ # Info needed to install Gitea: -gitea_version: 1.15 # 2021-03-07: Grabs latest point release from this branch. Rather than hardcoding (e.g. 1.14.5) every few weeks. +gitea_version: "1.22" # 2022-01-30: Grabs latest from this MAJOR/MINOR release branch. Rather than exhaustively hard-coding point releases (e.g. 1.14.5) every few weeks. Quotes nec if trailing zero. iset_suffixes: i386: 386 x86_64: amd64 @@ -17,9 +17,9 @@ iset_suffixes: armv6l: arm-6 armv7l: arm-6 # "arm-7" used to work, but no longer since 2019-04-20's Gitea 1.8.0: https://github.com/iiab/iiab/issues/1673 https://github.com/iiab/iiab/pull/1713 -- 2019-07-31: ARM7 support will return at some point, according to: https://github.com/go-gitea/gitea/pull/7037#issuecomment-516735216 (what about ARM8 support for RPi 4?) -gitea_iset_suffix: "{{ iset_suffixes[ansible_architecture] | default('unknown') }}" +gitea_iset_suffix: "{{ iset_suffixes[ansible_machine] | default('unknown') }}" # A bit safer than ansible_architecture (see kiwix/defaults/main.yml) -gitea_download_url: "https://dl.gitea.io/gitea/{{ gitea_version }}/gitea-{{ gitea_version }}-linux-{{ gitea_iset_suffix }}" +gitea_download_url: "https://dl.gitea.com/gitea/{{ gitea_version }}/gitea-{{ gitea_version }}-linux-{{ gitea_iset_suffix }}" gitea_integrity_url: "{{ gitea_download_url }}.asc" gitea_root_directory: "{{ content_base }}/gitea" # /library/gitea diff --git a/roles/gitea/tasks/nginx.yml b/roles/gitea/tasks/enable-or-disable.yml similarity index 62% rename from roles/gitea/tasks/nginx.yml rename to roles/gitea/tasks/enable-or-disable.yml index 2014a0d03..3401c3fdd 100644 --- a/roles/gitea/tasks/nginx.yml +++ b/roles/gitea/tasks/enable-or-disable.yml @@ -1,3 +1,19 @@ +- name: Enable & Restart 'gitea' systemd service, if gitea_enabled + systemd: + name: gitea + daemon_reload: yes + enabled: yes + state: restarted + when: gitea_enabled + +- name: Disable & Stop 'gitea' systemd service, if not gitea_enabled + systemd: + name: gitea + enabled: no + state: stopped + when: not gitea_enabled + + - name: Enable http://box{{ gitea_url }} via NGINX, by installing {{ nginx_conf_dir }}/gitea-nginx.conf from template template: src: gitea-nginx.conf.j2 diff --git a/roles/gitea/tasks/install.yml b/roles/gitea/tasks/install.yml index fa934c71b..eed1559f8 100644 --- a/roles/gitea/tasks/install.yml +++ b/roles/gitea/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 1. Prepare to install Gitea: create user and directory structure - name: Shut down existing Gitea instance (if we're reinstalling) @@ -43,10 +48,10 @@ msg: "Could not find a binary for the CPU architecture \"{{ ansible_architecture }}\"" when: gitea_iset_suffix == "unknown" -- name: Download Gitea binary {{ gitea_download_url }} to {{ gitea_install_path }} (0775, ~104 MB) +- name: Download Gitea binary {{ gitea_download_url }} to {{ gitea_install_path }} (0775, ~134 MB, SLOW DOWNLOAD CAN TAKE ~15 MIN) get_url: url: "{{ gitea_download_url }}" - dest: "{{ gitea_install_path }}" # e.g. /library/gitea/bin/gitea-1.14 + dest: "{{ gitea_install_path }}" # e.g. /library/gitea/bin/gitea-1.21 mode: 0775 timeout: "{{ download_timeout }}" @@ -56,16 +61,16 @@ dest: "{{ gitea_checksum_path }}" timeout: "{{ download_timeout }}" -- name: Verify Gitea binary with GPG signature +- name: Verify Gitea binary with GPG signature ("BAD signature" FALSE ALARMS continue as of 2023-07-16, despite their claims at https://docs.gitea.com/installation/install-from-binary#verify-gpg-signature) shell: | - gpg --keyserver pgp.mit.edu --recv {{ gitea_gpg_key }} + gpg --keyserver keys.openpgp.org --recv {{ gitea_gpg_key }} gpg --verify {{ gitea_checksum_path }} {{ gitea_install_path }} ignore_errors: yes - name: Symlink {{ gitea_link_path }} -> {{ gitea_install_path }} file: src: "{{ gitea_install_path }}" - path: "{{ gitea_link_path }}" + path: "{{ gitea_link_path }}" # /library/gitea/gitea owner: gitea group: gitea state: link @@ -105,6 +110,17 @@ # 5. RECORD Gitea AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'gitea_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: gitea + option: gitea_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'gitea_installed: True'" set_fact: gitea_installed: True diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml index 265532558..335911c96 100644 --- a/roles/gitea/tasks/main.yml +++ b/roles/gitea/tasks/main.yml @@ -19,46 +19,37 @@ quiet: yes -- name: Install Gitea {{ gitea_version }} if 'gitea_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: gitea_installed is undefined +- block: + - name: Install Gitea {{ gitea_version }} if 'gitea_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: gitea_installed is undefined -- name: Enable & Restart 'gitea' systemd service, if gitea_enabled - systemd: - name: gitea - daemon_reload: yes - enabled: yes - state: restarted - when: gitea_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'gitea' systemd service, if not gitea_enabled - systemd: - name: gitea - enabled: no - state: stopped - when: not gitea_enabled + - name: Add 'gitea' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: gitea + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Gitea + - option: description + value: '"Gitea is like GitHub for more offline communities: Git with a cup of tea"' + - option: gitea_install + value: "{{ gitea_install }}" + - option: gitea_enabled + value: "{{ gitea_enabled }}" + - option: gitea_run_directory + value: "{{ gitea_run_directory }}" + - option: gitea_url + value: "{{ gitea_url }}" -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + rescue: - -- name: Add 'gitea' to list of services at {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab_state.yml - section: gitea - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Gitea - - option: description - value: '"Gitea is like GitHub for more offline communities: Git with a cup of tea"' - - option: gitea_install - value: "{{ gitea_install }}" - - option: gitea_enabled - value: "{{ gitea_enabled }}" - - option: gitea_run_directory - value: "{{ gitea_run_directory }}" - - option: gitea_url - value: "{{ gitea_url }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/gitea/templates/app.ini.j2 b/roles/gitea/templates/app.ini.j2 index 00d503fdb..98add8b15 100644 --- a/roles/gitea/templates/app.ini.j2 +++ b/roles/gitea/templates/app.ini.j2 @@ -2,7 +2,8 @@ ; Copy required sections to your own app.ini (default is custom/conf/app.ini) ; and modify as needed. -; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. +; see https://docs.gitea.com/administration/config-cheat-sheet for additional documentation. +; https://docs.gitea.com/next/administration/config-cheat-sheet ; App name that shows in every page title APP_NAME = {{ gitea_display_name }} @@ -23,9 +24,11 @@ DEFAULT_PRIVATE = last ; Global limit of repositories per user, applied at creation time. -1 means no limit MAX_CREATION_LIMIT = -1 ; Mirror sync queue length, increase if mirror syncing starts hanging -MIRROR_QUEUE_LENGTH = 1000 +; 2023-07-16 ERROR: MIRROR_QUEUE_LENGTH = 1000 +; `[repository].MIRROR_QUEUE_LENGTH`. Use new options in `[queue.mirror]` ; Patch test queue length, increase if pull request patch testing starts hanging -PULL_REQUEST_QUEUE_LENGTH = 1000 +; 2023-07-16 ERROR: PULL_REQUEST_QUEUE_LENGTH = 1000 +; `[repository].PULL_REQUEST_QUEUE_LENGTH`. Use new options in `[queue.pr_patch_checker]` ; Preferred Licenses to place at the top of the List ; The name here must match the filename in conf/license or custom/conf/license PREFERRED_LICENSES = Apache License 2.0,MIT License @@ -201,13 +204,22 @@ PPROF_DATA_PATH = data/tmp/pprof LANDING_PAGE = home ; Enables git-lfs support. true or false, default is false. LFS_START_SERVER = false -; Where your lfs files reside, default is data/lfs. -LFS_CONTENT_PATH = {{ gitea_lfs_root }} ; LFS authentication secret, change this yourself LFS_JWT_SECRET = ; LFS authentication validity period (in time.Duration), pushes taking longer than this may fail. LFS_HTTP_AUTH_EXPIRY = 20m +; lfs [Large File Storage] storage will override storage +; +[lfs] +;STORAGE_TYPE = local +; +; Where your lfs files reside, default is data/lfs. +PATH = {{ gitea_lfs_root }} +; +; override the minio base path if storage type is minio +;MINIO_BASE_PATH = lfs/ + ; Define allowed algorithms and their minimum key length (use -1 to disable a type) [ssh.minimum_key_sizes] ED25519 = 256 @@ -240,7 +252,8 @@ ISSUE_INDEXER_PATH = indexers/issues.bleve ; repo indexer by default disabled, since it uses a lot of disk space REPO_INDEXER_ENABLED = false REPO_INDEXER_PATH = indexers/repos.bleve -UPDATE_BUFFER_LEN = 20 +; 2023-07-16 ERROR: UPDATE_BUFFER_LEN = 20 +; `[indexer].UPDATE_BUFFER_LEN`. Use new options in `[queue.issue_indexer]` MAX_FILE_SIZE = 1048576 [admin] @@ -360,7 +373,8 @@ PAGING_NUM = 10 [mailer] ENABLED = false ; Buffer length of channel, keep it as it is if you don't know what it is. -SEND_BUFFER_LEN = 100 +; 2023-07-16 ERROR: SEND_BUFFER_LEN = 100 +; `[mailer].SEND_BUFFER_LEN`. Use new options in `[queue.mailer]` ; Name displayed in mail title SUBJECT = %(APP_NAME)s ; Mail server diff --git a/roles/iiab-admin/README.rst b/roles/iiab-admin/README.rst index 55def7bde..2dbadaa62 100644 --- a/roles/iiab-admin/README.rst +++ b/roles/iiab-admin/README.rst @@ -13,7 +13,7 @@ iiab-admin README ================= -`Internet-in-a-Box `_ (IIAB) encourages you to pay attention to the security of your learning community. +`Internet-in-a-Box `_ (IIAB) encourages you to pay attention to the security of your learning community. This Ansible playbook is one of the very first that runs when you install IIAB, and we hope reading this helps you understand your choices: @@ -21,11 +21,11 @@ Configure user 'iiab-admin' --------------------------- * `admin-user.yml `_ configures a Linux user that will give you access to IIAB's Admin Console (http://box.lan/admin) after IIAB is installed β€” and can also help you at the command-line with IIAB community support commands like {iiab-diagnostics, iiab-hotspot-on, iiab-check-firmware, etc}. - * If initial creation of the user and password was somehow not already taken care of by IIAB's 1-line installer (http://download.iiab.io) or by your underlying OS, that too will be taken care of here. + * If initial creation of the user and password was somehow not already taken care of by IIAB's 1-line installer (https://download.iiab.io) or by your underlying OS, that too will be taken care of here. * By default this user is ``iiab-admin`` with password ``g0adm1n`` * *Do change the default password if you haven't yet, by running:* **sudo passwd iiab-admin** * After IIAB is installed, you can also change the password by logging into Admin Console (http://box.lan/admin) > Utilities > Change Password. -* If you prefer to use a pre-existing user like ``pi`` or ``ubuntu`` (or any other username) customize the variable ``iiab_admin_user`` in your `/etc/iiab/local_vars.yml `_ (preferably do this prior to installing IIAB!) +* If you prefer to use a pre-existing user like ``pi`` or ``ubuntu`` (or any other username) customize the variable ``iiab_admin_user`` in your `/etc/iiab/local_vars.yml `_ (preferably do this prior to installing IIAB!) * You can set ``iiab_admin_can_sudo: False`` if you want a strict security lockdown (if you're really sure you won't need IIAB community support commands like `/usr/bin/iiab-diagnostics <../../scripts/iiab-diagnostics.README.md>`_, `/usr/bin/iiab-hotspot-on <../network/templates/network/iiab-hotspot-on>`_, `iiab-check-firmware <../firmware/templates/iiab-check-firmware>`_, etc!) * You can also set ``iiab_admin_user_install: False`` if you're sure you know how to do all this `account and sudo configuration `_ manually. @@ -36,14 +36,14 @@ Security #. ``iiab-admin`` (specified by ``admin_console_group`` in `/opt/iiab/iiab/vars/default_vars.yml <../../vars/default_vars.yml>`_ and `/opt/iiab/iiab-admin-console/vars/default_vars.yml `_) #. ``sudo`` * Please read much more about what escalated (root) actions are authorized when you log into IIAB's Admin Console, and how this works: https://github.com/iiab/iiab-admin-console/blob/master/Authentication.md -* If your IIAB includes OpenVPN, ``/root/.ssh/authorized_keys`` should be installed by `roles/openvpn/tasks/install.yml <../openvpn/tasks/install.yml>`_ to facilitate remote community support. Feel free to remove this as mentioned here: http://wiki.laptop.org/go/IIAB/Security +* If your IIAB includes Tailscale (VPN), ``/root/.ssh/authorized_keys`` should be installed by `roles/tailscale/tasks/install.yml <../tailscale/tasks/install.yml>`_ to facilitate remote community support. Feel free to remove this as mentioned here: https://wiki.iiab.io/go/Security * Auto-checking for the default/published password (as specified by ``iiab_admin_published_pwd`` in `/opt/iiab/iiab/vars/default_vars.yml <../../vars/default_vars.yml>`_) is implemented in `/etc/profile.d `_ (and `/etc/xdg/lxsession/LXDE-pi `_ when it exists, i.e. on Raspberry Pi OS with desktop). Example ======= * If you later change your mind about ``sudo`` privileges for user 'iiab-admin' (as specified by ``iiab_admin_user``) then do this: - #. Go ahead and change the value of ``iiab_admin_can_sudo`` (to either True or False) in `/etc/iiab/local_vars.yml `_ + #. Go ahead and change the value of ``iiab_admin_can_sudo`` (to either True or False) in `/etc/iiab/local_vars.yml `_ #. Make sure that ``iiab_admin_user_install: True`` is also set. #. Then re-run this Ansible playbook, by running ``cd /opt/iiab/iiab`` followed by ``sudo ./runrole --reinstall iiab-admin`` @@ -56,16 +56,16 @@ Historical Notes Remote Support Tools -------------------- -The `iiab-diagnostics <../../scripts/iiab-diagnostics.README.md>`_ and `OpenVPN `_ options mentioned above can greatly help you empower your community, typically during the implementation phase of your project, even if Linux is new to you. +The `iiab-diagnostics <../../scripts/iiab-diagnostics.README.md>`_ and `Tailscale (VPN) `_ options mentioned above can greatly help you empower your community, typically during the implementation phase of your project, even if Linux is new to you. -Similarly, `access.yml `_ adds a couple text mode tools β€” extremely helpful over expensive / low-bandwidth connections: +Similarly, `tasks/main.yml `_ adds a couple text mode tools β€” extremely helpful over expensive / low-bandwidth connections: * `lynx `_ * `screen `_ *More great tools to help you jumpstart community action at a distance:* -* http://FAQ.IIAB.IO > "How can I remotely manage my Internet-in-a-Box?" +* `FAQ.IIAB.IO `_ > "How can I remotely manage my Internet-in-a-Box?" Admin Console ------------- diff --git a/roles/iiab-admin/tasks/access.yml b/roles/iiab-admin/tasks/access.yml deleted file mode 100644 index e7281c4dc..000000000 --- a/roles/iiab-admin/tasks/access.yml +++ /dev/null @@ -1,6 +0,0 @@ -- name: "Install text mode packages, useful during remote access: screen, lynx" - package: - name: - - lynx - - screen - state: present diff --git a/roles/iiab-admin/tasks/access.yml.unused b/roles/iiab-admin/tasks/access.yml.unused new file mode 100644 index 000000000..639a3d8a6 --- /dev/null +++ b/roles/iiab-admin/tasks/access.yml.unused @@ -0,0 +1,6 @@ +- name: "Install text-mode packages, useful during remote access: lynx, screen" + package: + name: + - lynx + - screen + state: present diff --git a/roles/iiab-admin/tasks/main.yml b/roles/iiab-admin/tasks/main.yml index ce4451003..fabe0bffe 100644 --- a/roles/iiab-admin/tasks/main.yml +++ b/roles/iiab-admin/tasks/main.yml @@ -2,8 +2,17 @@ # https://github.com/iiab/iiab/blob/master/roles/iiab-admin/README.rst -- name: Install lynx, screen - include_tasks: access.yml +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: "Install text-mode packages, useful during remote access: lynx, screen" + package: + name: + - lynx + - screen + state: present - name: Install sudo & /etc/sudoers with logging to /var/log/sudo.log include_tasks: sudo-prereqs.yml @@ -19,7 +28,7 @@ # (1) by the OS installer # (2) by the OS's graphical desktop tools # (3) at the command-line: sudo passwd iiab-admin -# (4) by IIAB's 1-line installer: http://download.iiab.io +# (4) by IIAB's 1-line installer: https://download.iiab.io # (5) by this role: roles/iiab-admin/tasks/admin-user.yml # (6) by IIAB's Admin Console during installation # ...and/or... @@ -31,6 +40,17 @@ # RECORD iiab-admin AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'iiab_admin_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: iiab-admin + option: iiab_admin_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'iiab_admin_installed: True'" set_fact: iiab_admin_installed: True diff --git a/roles/iiab-admin/tasks/pwd-warnings.yml b/roles/iiab-admin/tasks/pwd-warnings.yml index d1379b3fb..600a935bb 100644 --- a/roles/iiab-admin/tasks/pwd-warnings.yml +++ b/roles/iiab-admin/tasks/pwd-warnings.yml @@ -1,31 +1,36 @@ -- name: Install /etc/profile.d/sshpwd-profile-iiab.sh from template, to issue warnings (during shell/ssh logins) if iiab-admin password is the default +# 2022-07-22: SIMILAR TO roles/www_options/tasks/main.yml FOR browser +# AND roles/network/tasks/netwarn.yml FOR iiab-network + + +- name: Install /etc/profile.d/iiab-pwdwarn-profile.sh from template, to issue warnings (during shell/ssh logins) if iiab-admin password is the default template: - src: sshpwd-profile-iiab.sh.j2 - dest: /etc/profile.d/sshpwd-profile-iiab.sh + src: iiab-pwdwarn-profile.sh.j2 + dest: /etc/profile.d/iiab-pwdwarn-profile.sh mode: '0644' -- name: Is /etc/xdg/lxsession/LXDE-pi a directory? +- name: Does directory /home/{{ iiab_admin_user }}/.config/labwc/ exist? stat: - path: /etc/xdg/lxsession/LXDE-pi - register: lx + path: /home/{{ iiab_admin_user }}/.config/labwc/ + register: labwc_dir -- name: "If so, install from template: /etc/xdg/lxsession/LXDE-pi/sshpwd-lxde-iiab.sh" +- name: "If so, install from template: /usr/local/sbin/iiab-pwdwarn-labwc" template: - src: sshpwd-lxde-iiab.sh.j2 - dest: /etc/xdg/lxsession/LXDE-pi/sshpwd-lxde-iiab.sh + src: iiab-pwdwarn-labwc.j2 + dest: /usr/local/sbin/iiab-pwdwarn-labwc mode: '0755' - when: lx.stat.isdir is defined and lx.stat.isdir # and is_raspbian + when: labwc_dir.stat.exists and labwc_dir.stat.isdir -# 2019-03-07: This popup (/etc/xdg/lxsession/LXDE-pi/sshpwd-lxde-iiab.sh) does +# 2019-03-07: This pop-up (/etc/xdg/lxsession/LXDE-pi/sshpwd-lxde-iiab.sh) did # not actually appear when triggered by /etc/xdg/autostart/pprompt-iiab.desktop # (or pprompt.desktop as Raspbian has working since 2018-11-13!) Too bad as it -# would be really nice to standardize this popup across Ubermix & all distros.. +# would be really nice to standardize pop-ups across Ubermix & all distros... # Is this a permissions/security issue presumably? Official autostart spec is: # https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html # Raspbian's 2016-2018 evolution here: https://github.com/iiab/iiab/issues/1537 -- name: ...and put a line in /etc/xdg/lxsession/LXDE-pi/autostart to trigger popups +- name: ...and put a line in /home/{{ iiab_admin_user }}/.config/labwc/autostart to trigger iiab-pwdwarn-labwc (& pop-up as nec) lineinfile: - path: /etc/xdg/lxsession/LXDE-pi/autostart - line: "@/etc/xdg/lxsession/LXDE-pi/sshpwd-lxde-iiab.sh" - when: lx.stat.isdir is defined and lx.stat.isdir # and is_raspbian + path: /home/{{ iiab_admin_user }}/.config/labwc/autostart # iiab-admin + create: yes + line: '/usr/local/sbin/iiab-pwdwarn-labwc &' + when: labwc_dir.stat.exists and labwc_dir.stat.isdir diff --git a/roles/iiab-admin/tasks/sudo-prereqs.yml b/roles/iiab-admin/tasks/sudo-prereqs.yml index 1b608fef1..9370666b2 100644 --- a/roles/iiab-admin/tasks/sudo-prereqs.yml +++ b/roles/iiab-admin/tasks/sudo-prereqs.yml @@ -1,6 +1,6 @@ - name: 'Install package: sudo' package: - name: sudo # (1) Should be installed prior to installing IIAB, (2) Can also be installed by roles/1-prep's roles/openvpn/tasks/install.yml, (3) Is definitely installed by 1-prep here, (4) Used to be installed by roles/2-common/tasks/packages.yml (but that's too late!) + name: sudo # (1) Should be installed prior to installing IIAB, (2) Can be installed by 1-prep's roles/tailscale/tasks/install.yml, (3) Can be installed by 1-prep's roles/iiab-admin/tasks/sudo-prereqs.yml here, (4) Used to be installed by roles/2-common/tasks/packages.yml (but that's too late!) - name: Temporarily make file /etc/sudoers editable (0640) file: diff --git a/roles/iiab-admin/templates/sshpwd-lxde-iiab.sh.j2 b/roles/iiab-admin/templates/iiab-pwdwarn-labwc.j2 similarity index 85% rename from roles/iiab-admin/templates/sshpwd-lxde-iiab.sh.j2 rename to roles/iiab-admin/templates/iiab-pwdwarn-labwc.j2 index fe7e8ae1b..373d3888d 100755 --- a/roles/iiab-admin/templates/sshpwd-lxde-iiab.sh.j2 +++ b/roles/iiab-admin/templates/iiab-pwdwarn-labwc.j2 @@ -19,14 +19,18 @@ check_user_pwd() { # enough when user does not exist. Or uncomment to FORCE ERROR CODE 2. # Either way, overall bash script still returns exit code 0 ("success") - # sudo works below (unlike in sshpwd-profile-iiab.sh) b/c RaspiOS ships w/ + # sudo works below (unlike in sshpwd-profile-iiab.sh) b/c RasPiOS ships w/ # /etc/sudoers.d/010_pi-nopasswd containing "pi ALL=(ALL) NOPASSWD: ALL" # (read access to /etc/shadow is otherwise restricted to just root and # group www-data i.e. Apache, NGINX get special access). SEE: #2431, #2561 # 2021-08-28: New OS's use 'yescrypt' so use Perl instead of Python (#2949) # This also helps avoid parsing the (NEW) 4th sub-field in $y$j9T$SALT$HASH - field2=$(grep "^$1:" /etc/shadow | cut -d: -f2) + + # 2022-09-21 #3368: Sets field2 to "" if sudo -n fails to read /etc/shadow + # 2022-10-18 #3404: Redirect stderr to /dev/null, as RasPiOS might one day + # force an annoying pop-up, as Mint did (due to sshpwd-profile-iiab.sh.j2) + field2=$(sudo -n grep "^$1:" /etc/shadow 2>/dev/null | cut -d: -f2) [[ $(perl -e "print crypt('$2', '$field2')") == $field2 ]] # # $meth (hashing method) is typically '6' which implies 5000 rounds @@ -37,8 +41,8 @@ check_user_pwd() { # [ $(python3 -c "import crypt; print(crypt.crypt('$2', '\$$meth\$$salt'))") == "\$$meth\$$salt\$$hash" ] } -#grep -q "^PasswordAuthentication\s\+no\b" /etc/ssh/sshd_config && return -#systemctl is-active {{ sshd_service }} || return +# grep -q "^PasswordAuthentication\s\+no\b" /etc/ssh/sshd_config && return +# systemctl is-active ssh || return # #3444: Or use Ansible var sshd_service if check_user_pwd "{{ iiab_admin_user }}" "{{ iiab_admin_published_pwd }}" ; then # iiab-admin g0adm1n zenity --warning --width=600 --text="Published password in use by user '{{ iiab_admin_user }}'.\n\nTHIS IS A SECURITY RISK - please change its password using IIAB's Admin Console (http://box.lan/admin) -> Utilities -> Change Password.\n\nSee 'What are the default passwords?' at http://FAQ.IIAB.IO" diff --git a/roles/iiab-admin/templates/sshpwd-profile-iiab.sh.j2 b/roles/iiab-admin/templates/iiab-pwdwarn-profile.sh.j2 similarity index 91% rename from roles/iiab-admin/templates/sshpwd-profile-iiab.sh.j2 rename to roles/iiab-admin/templates/iiab-pwdwarn-profile.sh.j2 index 24d87886c..9d18eece1 100755 --- a/roles/iiab-admin/templates/sshpwd-profile-iiab.sh.j2 +++ b/roles/iiab-admin/templates/iiab-pwdwarn-profile.sh.j2 @@ -16,7 +16,8 @@ check_user_pwd() { #[ $(id -un) = "root" ] || return 2 #[ $(id -un) = "root" ] || [ $(id -un) = "iiab-admin" ] || return 2 - [ -r /etc/shadow ] || return 2 # FORCE ERROR if /etc/shadow not readable + + #[ -r /etc/shadow ] || return 2 # FORCE ERROR if /etc/shadow not readable # *BUT* overall bash script still returns exit code 0 ("success"). #id -u $1 > /dev/null 2>&1 || return 2 # Not needed if return 1 is good @@ -25,7 +26,10 @@ check_user_pwd() { # 2021-08-28: New OS's use 'yescrypt' so use Perl instead of Python (#2949) # This also helps avoid parsing the (NEW) 4th sub-field in $y$j9T$SALT$HASH - field2=$(grep "^$1:" /etc/shadow | cut -d: -f2) + + # 2022-09-21 #3368: Sets field2 to "" if sudo -n fails to read /etc/shadow + # 2022-10-18 #3404: Redirect stderr to /dev/null, to avoid Mint pop-up + field2=$(sudo -n grep "^$1:" /etc/shadow 2> /dev/null | cut -d: -f2) [[ $(perl -e "print crypt('$2', '$field2')") == $field2 ]] # # $meth (hashing method) is typically '6' which implies 5000 rounds diff --git a/roles/internetarchive/README.md b/roles/internetarchive/README.md index 49d8d3f0f..bd32849c3 100644 --- a/roles/internetarchive/README.md +++ b/roles/internetarchive/README.md @@ -8,7 +8,7 @@ Access to our library of millions of books, journals, audio and video recordings This Ansible role installs the Internet Archive's dweb-mirror project on Internet-in-a-Box (IIAB). Use this to build up a dynamic offline library -arising from the materials you can explore at http://dweb.archive.org +arising from the materials you can explore at https://dweb.archive.org The Offline Internet Archive server: @@ -248,7 +248,7 @@ and just checks the content is up to date. ## Managing collections on Internet Archive -You can create and manage your own collections on the [Internet Archive site](http://www.archive.org). +You can create and manage your own collections on the [Internet Archive site](https://www.archive.org). Other people can then crawl those collections. First get in touch with Mitra Ardron at `mitra@archive.org`, as processes may have changed since this is written. diff --git a/roles/internetarchive/tasks/nginx.yml b/roles/internetarchive/tasks/enable-or-disable.yml similarity index 62% rename from roles/internetarchive/tasks/nginx.yml rename to roles/internetarchive/tasks/enable-or-disable.yml index 0469e58c4..47cebe214 100644 --- a/roles/internetarchive/tasks/nginx.yml +++ b/roles/internetarchive/tasks/enable-or-disable.yml @@ -1,3 +1,19 @@ +- name: Enable & Restart 'internetarchive' systemd service, if internetarchive_enabled + systemd: + name: internetarchive + daemon_reload: yes + enabled: yes + state: restarted + when: internetarchive_enabled + +- name: Disable & Stop 'internetarchive' systemd service, if not internetarchive_enabled + systemd: + name: internetarchive + enabled: no + state: stopped + when: not internetarchive_enabled + + - name: Enable http://box/archive via NGINX, by installing {{ nginx_conf_dir }}/internetarchive-nginx.conf from template template: src: internetarchive-nginx.conf.j2 # TO DO: roles/internetarchive/templates/internetarchive-nginx.conf.j2 diff --git a/roles/internetarchive/tasks/install.yml b/roles/internetarchive/tasks/install.yml index d44586042..2821a9ffd 100644 --- a/roles/internetarchive/tasks/install.yml +++ b/roles/internetarchive/tasks/install.yml @@ -9,10 +9,10 @@ include_role: name: nodejs -- name: Assert that 10.x <= nodejs_version ({{ nodejs_version }}) <= 16.x +- name: Assert that 10.x <= nodejs_version ({{ nodejs_version }}) <= 22.x assert: - that: nodejs_version is version('10.x', '>=') and nodejs_version is version('16.x', '<=') - fail_msg: "Internet Archive install cannot proceed, as it currently requires Node.js 10.x - 16.x, and your nodejs_version is set to {{ nodejs_version }}. Please check the value of nodejs_version in /opt/iiab/iiab/vars/default_vars.yml and possibly also /etc/iiab/local_vars.yml" + that: nodejs_version is version('10.x', '>=') and nodejs_version is version('22.x', '<=') + fail_msg: "Internet Archive install cannot proceed, as it currently requires Node.js 10.x - 22.x, and your nodejs_version is set to {{ nodejs_version }}. Please check the value of nodejs_version in /opt/iiab/iiab/vars/default_vars.yml and possibly also /etc/iiab/local_vars.yml" quiet: yes - name: "Set 'yarn_install: True' and 'yarn_enabled: True'" @@ -30,6 +30,11 @@ state: present +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 2. CREATE 2 DIRS, WIPE /opt/iiab/internetarchive/node_modules & RUN YARN - name: mkdir {{ internetarchive_dir }} @@ -42,8 +47,8 @@ state: absent path: "{{ internetarchive_dir }}/node_modules" -- name: Run 'yarn add @internetarchive/dweb-mirror' to download/populate {{ internetarchive_dir }}/node_modules (CAN TAKE ~5 MINUTES) - shell: yarn config set child-concurrency 1 && yarn add @internetarchive/dweb-mirror +- name: Run 'yarn add https://github.com/internetarchive/dweb-mirror' to download/populate {{ internetarchive_dir }}/node_modules (CAN TAKE ~5 MINUTES) + shell: yarn config set child-concurrency 1 && yarn add https://github.com/internetarchive/dweb-mirror args: chdir: "{{ internetarchive_dir }}" creates: "{{ internetarchive_dir }}/node_modules/@internetarchive/dweb-mirror/internetarchive" @@ -64,6 +69,17 @@ # 4. RECORD Internet Archive AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'internetarchive_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: internetarchive + option: internetarchive_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'internetarchive_installed: True'" set_fact: internetarchive_installed: True diff --git a/roles/internetarchive/tasks/main.yml b/roles/internetarchive/tasks/main.yml index c878287a3..7e3a8a2dd 100644 --- a/roles/internetarchive/tasks/main.yml +++ b/roles/internetarchive/tasks/main.yml @@ -19,76 +19,60 @@ quiet: yes -# 2020-02-11: @mitra42 & @holta agree (#2247) that the following 2-stanza -# "UPDATE internetarchive" block should run whenever one isn't installing -# (or reinstalling) internetarchive, for now. We're aware this means slowness -# during "./runrole internetarchive" but that's very intentional for now -- as -# it leads to more testing of more recent versions of internetarchive, which -# is strongly desired. Finally, these current norms can and probably will be -# changed in future, when broader IIAB norms develop around "./runrole -# --upgrade internetarchive" or "./runrole --update internetarchive" or such, -# as may evolve @ https://github.com/iiab/iiab/pull/2238#discussion_r376168178 +- block: -- block: # BEGIN 2-STANZA BLOCK + # 2020-02-11: @mitra42 & @holta agree (#2247) that the following 2-stanza + # "UPDATE internetarchive" portion should run whenever one isn't installing + # (or reinstalling) internetarchive, for now. We're aware this means slowness + # during "./runrole internetarchive" but that's very intentional for now -- as + # it leads to more testing of more recent versions of internetarchive, which + # is strongly desired. Finally, these current norms can and probably will be + # changed in future, when broader IIAB norms develop around "./runrole + # --upgrade internetarchive" or "./runrole --update internetarchive" or such, + # as may evolve @ https://github.com/iiab/iiab/pull/2238#discussion_r376168178 - name: "UPGRADE: Stop 'internetarchive' systemd service, if internetarchive_installed is defined" systemd: name: internetarchive daemon_reload: yes state: stopped + when: internetarchive_installed is defined - name: "UPGRADE: Run 'yarn upgrade' in {{ internetarchive_dir }}, if internetarchive_installed is defined" shell: yarn config set child-concurrency 1 && yarn install && yarn upgrade args: chdir: "{{ internetarchive_dir }}" + when: internetarchive_installed is defined - when: internetarchive_installed is defined # END 2-STANZA BLOCK + # "ELSE" INSTALL... -# "ELSE" INSTALL... - -- name: Install Internet Archive if 'internetarchive_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: internetarchive_installed is undefined + - name: Install Internet Archive if 'internetarchive_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: internetarchive_installed is undefined -# ENABLE/DISABLE/RESTART SYSTEMD SERVICE & WEB SERVERS AS NEC ? - -- name: Enable & Restart 'internetarchive' systemd service, if internetarchive_enabled - systemd: - name: internetarchive - daemon_reload: yes - enabled: yes - state: restarted - when: internetarchive_enabled - -- name: Disable & Stop 'internetarchive' systemd service, if not internetarchive_enabled - systemd: - name: internetarchive - enabled: no - state: stopped - when: not internetarchive_enabled - -# - name: Enable/Disable/Restart Apache if primary -# include_tasks: apache.yml -# when: apache_installed is defined and not nginx_enabled - -- name: Enable/Disable/Restart NGINX if primary - include_tasks: nginx.yml - #when: nginx_enabled + - include_tasks: enable-or-disable.yml -- name: Add 'internetarchive' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: internetarchive - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Internet Archive - - option: description - value: '"Take the Internet Archive experience and materials offline, in a decentralized way!"' - - option: internetarchive_install - value: "{{ internetarchive_install }}" - - option: internetarchive_enabled - value: "{{ internetarchive_enabled }}" + - name: Add 'internetarchive' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: internetarchive + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Internet Archive + - option: description + value: '"Take the Internet Archive experience and materials offline, in a decentralized way!"' + - option: internetarchive_install + value: "{{ internetarchive_install }}" + - option: internetarchive_enabled + value: "{{ internetarchive_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/jupyterhub/README.md b/roles/jupyterhub/README.md index be6fc5719..6a48cacf5 100644 --- a/roles/jupyterhub/README.md +++ b/roles/jupyterhub/README.md @@ -1,5 +1,7 @@ ## JupyterHub programming environment with student Notebooks +### CAUTION: Internet-in-a-Box (IIAB) does not support JupyterHub on 32-bit OS's, where installation will likely fail ([#3639](https://github.com/iiab/iiab/issues/3639)). + #### Secondary schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing β€” A New Way to Think About Programming β€” allowing students to integrate science experiment results and program output within their own blog-like "Jupyter Notebooks." * Jupyter Notebooks are widely used in the scientific community: @@ -9,10 +11,11 @@ * [JupyterHub changelog](https://jupyterhub.readthedocs.io/en/stable/changelog.html#changelog) * Students create their own accounts on first use β€” e.g. at http://box.lan/jupyterhub β€” just as if they're logging in regularly (unfortunately the login screen doesn't make that clear, but the teacher _does not_ need to be involved!) * A student can then sign in with their username and password, to gain access to their files (Jupyter Notebooks). - * The teacher should set and protect JupyterHub's overall `Admin` password, just in case. As with student accounts, the login screen doesn't make that clear β€” so just log in with username `Admin` β€” using any password that you want to become permanent. -* Individual student folders are created in `/var/lib/private/` on the Internet-in-a-Box (IIAB) server: + * The teacher should set and protect JupyterHub's overall `Admin` password, just in case. As with student accounts, the login screen unfortunately doesn't make that clear β€” so just log in with username `Admin` β€” using any password that you want to become permanent. +* Individual student folders are created in `/var/lib/private/` on your Internet-in-a-Box (IIAB) server: * A student will only be able to see their own work β€” they do not have privileges outside of their own folder. * Students may upload Jupyter Notebooks to the IIAB server, and download the current state of their work via a normal browser. + * Linux administrators can read more about JupyterHub's [Local Users](https://github.com/jupyterhub/systemdspawner#local-users) and [c.SystemdSpawner.dynamic_users = True](https://github.com/jupyterhub/systemdspawner#dynamic_users) ### Settings @@ -26,10 +29,11 @@ In some rare circumstances, it may be necessary to restart JupyterHub's systemd sudo systemctl restart jupyterhub ``` -FYI `/opt/iiab/jupyterhub` is a Python 3 virtual environment, that can be activated with the usual formula: +FYI `/opt/iiab/jupyterhub` is a Python 3 virtual environment, that can be activated (and deactivated) with the usual: ``` source /opt/iiab/jupyterhub/bin/activate +(jupyterhub) root@box:~# deactivate ``` Passwords are hashed using 4096 rounds of the latest Blowfish (bcrypt's $2b$ algorithm) and stored in: @@ -42,19 +46,19 @@ Passwords are hashed using 4096 rounds of the latest Blowfish (bcrypt's $2b$ alg Users can change their password by logging in, and then visiting URL: http://box.lan/jupyterhub/auth/change-password -NOTE: This is the only way to change the password for user 'Admin', because Control Panel > Admin (below) does not permit deletion of this account. +NOTE: This is the only way to change the password for user `Admin`, because **File > Hub Control Panel > Admin** (below) does not permit deletion of this account. -### Control Panel > Admin page, to manage other accounts +### File > Hub Control Panel > Admin, to manage accounts The `Admin` user (and any users given `Admin` privilege) can reset user passwords by deleting the user from JupyterHub's **Admin** page (below). This logs the user out, but does not remove any of their data or home directories. The user can then set a new password in the usual way β€” simply by logging in. Example: -1. As a user with `Admin` privilege, click **Control Panel** in the top right of your JupyterHub: +1. As a user with `Admin` privilege, click **File > Hub Control Panel** in your JupyterHub: - ![Control panel button in notebook, top right](control-panel-button1.png) + ![image](https://user-images.githubusercontent.com/2458907/217602766-ab6a9d3c-9f92-496e-a0e8-6c18a084e960.png) -2. In the Control Panel, open the **Admin** link in the top left: +2. At the top of the Control Panel, click **Admin**: - ![Admin button in control panel, top left](admin-access-button1.png) + ![image](https://user-images.githubusercontent.com/2458907/217602473-f4f9fd40-b4c1-45e1-88c5-54c6d4b604ff.png) This opens up the JupyterHub Admin page, where you can add / delete users, start / stop peoples’ servers and see who is online. @@ -70,8 +74,22 @@ The `Admin` user (and any users given `Admin` privilege) can reset user password _WARNING: If on login users see "500 : Internal Server Error", you may need to remove ALL files of the form_ `/run/jupyter-johndoe-singleuser` +### Logging + +To see JupyterHub's (typically very long!) log, run: + +``` +journalctl -u jupyterhub +``` + +Sometimes other logs might also be available, e.g.: + +``` +journalctl -u jupyter-admin-singleuser +``` + ### PAWS/Jupyter Notebooks for Python Beginners While PAWS is a little bit off topic, if you have an interest in Wikipedia, please do see this 23m 42s video ["Intro to PAWS/Jupyter notebooks for Python beginners"](https://www.youtube.com/watch?v=AUZkioRI-aA&list=PLeoTcBlDanyNQXBqI1rVXUqUTSSiuSIXN&index=8) by Chico Venancio, from 2021-06-01. -He explains PAWS as a "powerful Python execution environment http://paws.wmcloud.org [allowing] ordinary folks to write interactive scripts to work with Wikimedia content." +He explains PAWS as a "powerful Python execution environment https://paws.wmcloud.org = https://wikitech.wikimedia.org/wiki/PAWS [allowing] ordinary folks to write interactive scripts to work with Wikimedia content." diff --git a/roles/jupyterhub/tasks/install.yml b/roles/jupyterhub/tasks/install.yml index 38f98b370..57a503014 100644 --- a/roles/jupyterhub/tasks/install.yml +++ b/roles/jupyterhub/tasks/install.yml @@ -13,10 +13,20 @@ when: nodejs_installed is undefined -- name: "Install package: python3-venv" - package: - name: python3-venv - state: present +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + +# 2025-02-16 +#- name: "Install package: python3-psutil" +# package: +# name: python3-psutil +# state: present + +- name: Remove previous virtual environment {{ jupyterhub_venv }} + file: + path: "{{ jupyterhub_venv }}" + state: absent - name: Make 3 directories to hold JupyterHub config file: @@ -33,21 +43,35 @@ global: yes state: latest -- name: "pip install 7 packages into virtual environment: {{ jupyterhub_venv }} (~229 MB)" +- name: "pip install 3 packages into virtual environment: {{ jupyterhub_venv }} (~316 MB total, after 2 Ansible calls)" pip: name: - pip - wheel - - ipywidgets - jupyterhub + virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyterhub + #virtualenv_site_packages: no + virtualenv_command: python3 -m venv "{{ jupyterhub_venv }}" # 2025-02-16 + #virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}" # 2021-07-29: This works on RasPiOS 10, Debian 11, Ubuntu 20.04 and Mint 20 -- however if you absolutely must use the older Debian 10 -- you can work around errors "can't find Rust compiler" and "This package requires Rust >=1.41.0" if you (1) revert this line to 'virtualenv_command: virtualenv' AND (2) uncomment the line just below + #virtualenv_python: python3 # 2021-07-29: Was needed when above line was 'virtualenv_command: virtualenv' (generally for Python 2) + extra_args: "--no-cache-dir --prefer-binary" # 2021-11-30, 2022-07-07: The "--pre" flag had earlier been needed, for beta-like pre-releases of JupyterHub 2.0.0 + +# 2022-07-07: Attempting to "pip install" all 7 together (3 above + 4 below) +# fails on OS's like 64-bit RasPiOS (but interestingly works on Ubuntu 22.04!) +# https://github.com/iiab/iiab/issues/3283 + +- name: Break up jupyterhub/jupyterlab pip installs into 2 parts (3 packages above + 4 packages here) due to mutual dependency deadlock on some OS's + pip: + name: - jupyterlab - jupyterhub_firstuseauthenticator - jupyterhub-systemdspawner - virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyterhub - virtualenv_site_packages: no - virtualenv_command: python3 -m venv "{{ jupyterhub_venv }}" # 2021-07-29: This works on RaspiOS 10, Debian 11, Ubuntu 20.04 and Mint 20 -- however if you absolutely must use the older Debian 10 -- you can work around errors "can't find Rust compiler" and "This package requires Rust >=1.41.0" if you (1) revert this line to 'virtualenv_command: virtualenv' AND (2) uncomment the line just below - #virtualenv_python: python3 # 2021-07-29: Was needed when above line was 'virtualenv_command: virtualenv' (generally for Python 2) - extra_args: "--no-cache-dir --pre" # 2021-11-30: The "--pre" flag should likely be removed after JupyterHub 2.0.0 is released. + - ipywidgets + virtualenv: "{{ jupyterhub_venv }}" + #virtualenv_site_packages: no + virtualenv_command: python3 -m venv "{{ jupyterhub_venv }}" # 2025-02-16 + #virtualenv_command: python3 -m venv --system-site-packages "{{ jupyterhub_venv }}" + extra_args: "--no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560 - name: "Install from template: {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py" template: @@ -59,20 +83,21 @@ src: jupyterhub.service.j2 dest: /etc/systemd/system/jupyterhub.service -- name: Install {{ jupyterhub_venv }}/bin/getsite.py from template, to fetch site_packages path, e.g. {{ jupyterhub_venv }}/lib/python{{ python_ver }}/site-packages - template: - src: getsite.py.j2 - dest: "{{ jupyterhub_venv }}/bin/getsite.py" - mode: 0755 - -- name: Install patch_FUA.sh from template -- to (1) fix async password-changing page, and (2) force usernames to lowercase -- patching $SITE_PACKAGES/firstuseauthenticator/firstuseauthenticator.py - template: - src: patch_FUA.sh.j2 - dest: "{{ jupyterhub_venv }}/bin/patch_FUA.sh" - mode: 0755 - -- name: "Run the above two, via: {{ jupyterhub_venv }}/bin/patch_FUA.sh" - command: "{{ jupyterhub_venv }}/bin/patch_FUA.sh" +# 2022-07-07: No longer needed, thx to upstream fixes +# - name: Install {{ jupyterhub_venv }}/bin/getsite.py from template, to fetch site_packages path, e.g. {{ jupyterhub_venv }}/lib/python{{ python_version }}/site-packages +# template: +# src: getsite.py.j2 +# dest: "{{ jupyterhub_venv }}/bin/getsite.py" +# mode: 0755 +# +# - name: Install patch_FUA.sh from template -- to (1) fix async password-changing page, and (2) force usernames to lowercase -- patching $SITE_PACKAGES/firstuseauthenticator/firstuseauthenticator.py +# template: +# src: patch_FUA.sh.j2 +# dest: "{{ jupyterhub_venv }}/bin/patch_FUA.sh" +# mode: 0755 +# +# - name: "Run the above two, via: {{ jupyterhub_venv }}/bin/patch_FUA.sh" +# command: "{{ jupyterhub_venv }}/bin/patch_FUA.sh" - name: Install patch_http-warning.sh from template, to turn off the warning about http insecurity, in {{ jupyterhub_venv }}/share/jupyterhub/templates/login.html template: @@ -86,6 +111,17 @@ # RECORD JupyterHub AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'jupyterhub_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyterhub + option: jupyterhub_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'jupyterhub_installed: True'" set_fact: jupyterhub_installed: True diff --git a/roles/jupyterhub/tasks/main.yml b/roles/jupyterhub/tasks/main.yml index 01acf8154..9f2d31d13 100644 --- a/roles/jupyterhub/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -19,26 +19,33 @@ quiet: yes -- name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: jupyterhub_installed is undefined +- block: + - name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: jupyterhub_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'jupyterhub' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyterhub + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: JupyterHub + - option: description + value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing β€” A New Way to Think About Programming β€” allowing students to integrate science experiment results and program output within their notebook/document/blog."' + - option: jupyterhub_install + value: "{{ jupyterhub_install }}" + - option: jupyterhub_enabled + value: "{{ jupyterhub_enabled }}" -- name: Add 'jupyterhub' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: jupyterhub - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: JupyterHub - - option: description - value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing β€” A New Way to Think About Programming β€” allowing students to integrate science experiment results and program output within their notebook/document/blog."' - - option: jupyterhub_install - value: "{{ jupyterhub_install }}" - - option: jupyterhub_enabled - value: "{{ jupyterhub_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/jupyterhub/templates/getsite.py.j2 b/roles/jupyterhub/templates/getsite.py.j2.unused similarity index 100% rename from roles/jupyterhub/templates/getsite.py.j2 rename to roles/jupyterhub/templates/getsite.py.j2.unused diff --git a/roles/jupyterhub/templates/jupyterhub_config.py.j2 b/roles/jupyterhub/templates/jupyterhub_config.py.j2 index a3c5b077f..5abc7deb5 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py.j2 +++ b/roles/jupyterhub/templates/jupyterhub_config.py.j2 @@ -1,5 +1,18 @@ +# 2023-02-10 /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py update: +# https://jupyterhub.readthedocs.io/en/stable/getting-started/config-basics.html +# +# 1) To generate this 1500+ line stub, I first ran JupyterHub 3.1.1's: +# /opt/iiab/jupyterhub/bin/jupyterhub --generate-config +# 2) Then I manually inserted 8 of IIAB's 10 legacy custom lines below, from: +# grep ^c /opt/iiab/iiab/roles/jupyterhub/templates/jupyterhub_config.py.j2 +# 3) Finally I added the following line on @jvonau's suggestion: (#3475) +# c.ConfigurableHTTPProxy.pid_file = "/run/jupyterhub-proxy.pid" + + # Configuration file for jupyterhub. +c = get_config() #noqa + #------------------------------------------------------------------------------ # Application(SingletonConfigurable) configuration #------------------------------------------------------------------------------ @@ -18,6 +31,53 @@ # Default: 30 # c.Application.log_level = 30 +## Configure additional log handlers. +# +# The default stderr logs handler is configured by the log_level, log_datefmt +# and log_format settings. +# +# This configuration can be used to configure additional handlers (e.g. to +# output the log to a file) or for finer control over the default handlers. +# +# If provided this should be a logging configuration dictionary, for more +# information see: +# https://docs.python.org/3/library/logging.config.html#logging-config- +# dictschema +# +# This dictionary is merged with the base logging configuration which defines +# the following: +# +# * A logging formatter intended for interactive use called +# ``console``. +# * A logging handler that writes to stderr called +# ``console`` which uses the formatter ``console``. +# * A logger with the name of this application set to ``DEBUG`` +# level. +# +# This example adds a new handler that writes to a file: +# +# .. code-block:: python +# +# c.Application.logging_config = { +# 'handlers': { +# 'file': { +# 'class': 'logging.FileHandler', +# 'level': 'DEBUG', +# 'filename': '', +# } +# }, +# 'loggers': { +# '': { +# 'level': 'DEBUG', +# # NOTE: if you don't list the default "console" +# # handler here then it will be disabled +# 'handlers': ['console', 'file'], +# }, +# } +# } +# Default: {} +# c.Application.logging_config = {} + ## Instead of starting the Application, dump configuration to stdout # Default: False # c.Application.show_config = False @@ -60,11 +120,13 @@ # Default: 30 # c.JupyterHub.activity_resolution = 30 -## Grant admin users permission to access single-user servers. +## DEPRECATED since version 2.0.0. # -# Users should be properly informed if this is enabled. +# The default admin role has full permissions, use custom RBAC scopes instead to +# create restricted administrator roles. +# https://jupyterhub.readthedocs.io/en/stable/rbac/index.html # Default: False -c.JupyterHub.admin_access = True +# c.JupyterHub.admin_access = False ## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. # Default: set() @@ -78,14 +140,23 @@ c.JupyterHub.admin_access = True # Default: False # c.JupyterHub.answer_yes = False +## The default amount of records returned by a paginated endpoint +# Default: 50 +# c.JupyterHub.api_page_default_limit = 50 + +## The maximum amount of records that can be returned at once +# Default: 200 +# c.JupyterHub.api_page_max_limit = 200 + ## PENDING DEPRECATION: consider using services # -# Dict of token:username to be loaded into the database. +# Dict of token:username to be loaded into the database. # -# Allows ahead-of-time generation of API tokens for use by externally managed -# services, which authenticate as JupyterHub users. +# Allows ahead-of-time generation of API tokens for use by externally managed services, +# which authenticate as JupyterHub users. # -# Consider using services for general services that talk to the JupyterHub API. +# Consider using services for general services that talk to the +# JupyterHub API. # Default: {} # c.JupyterHub.api_tokens = {} @@ -112,49 +183,53 @@ c.JupyterHub.admin_access = True # Currently installed: # - default: jupyterhub.auth.PAMAuthenticator # - dummy: jupyterhub.auth.DummyAuthenticator +# - null: jupyterhub.auth.NullAuthenticator # - pam: jupyterhub.auth.PAMAuthenticator # Default: 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' ## The base URL of the entire application. # -# Add this to the beginning of all JupyterHub URLs. Use base_url to run -# JupyterHub within an existing website. +# Add this to the beginning of all JupyterHub URLs. +# Use base_url to run JupyterHub within an existing website. # -# .. deprecated: 0.9 -# Use JupyterHub.bind_url +# .. deprecated: 0.9 +# Use JupyterHub.bind_url # Default: '/' +# c.JupyterHub.base_url = '/' c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # -# This is the address on which the proxy will bind. Sets protocol, ip, base_url +# This is the address on which the proxy will bind. +# Sets protocol, ip, base_url # Default: 'http://:8000' # c.JupyterHub.bind_url = 'http://:8000' ## Whether to shutdown the proxy when the Hub shuts down. # -# Disable if you want to be able to teardown the Hub while leaving the proxy -# running. +# Disable if you want to be able to teardown the Hub while leaving the +# proxy running. # -# Only valid if the proxy was starting by the Hub process. +# Only valid if the proxy was starting by the Hub process. # -# If both this and cleanup_servers are False, sending SIGINT to the Hub will -# only shutdown the Hub, leaving everything else running. +# If both this and cleanup_servers are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. # -# The Hub should be able to resume from database state. +# The Hub should be able to resume from database state. # Default: True # c.JupyterHub.cleanup_proxy = True ## Whether to shutdown single-user servers when the Hub shuts down. # -# Disable if you want to be able to teardown the Hub while leaving the single- -# user servers running. +# Disable if you want to be able to teardown the Hub while leaving the +# single-user servers running. # -# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only -# shutdown the Hub, leaving everything else running. +# If both this and cleanup_proxy are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. # -# The Hub should be able to resume from database state. +# The Hub should be able to resume from database state. # Default: True # c.JupyterHub.cleanup_servers = True @@ -184,33 +259,54 @@ c.JupyterHub.base_url = '/jupyterhub' # Default: False # c.JupyterHub.confirm_no_ssl = False -## Number of days for a login cookie to be valid. Default is two weeks. +## Number of days for a login cookie to be valid. +# Default is two weeks. # Default: 14 # c.JupyterHub.cookie_max_age_days = 14 ## The cookie secret to use to encrypt cookies. # -# Loaded from the JPY_COOKIE_SECRET env variable by default. +# Loaded from the JPY_COOKIE_SECRET env variable by default. # -# Should be exactly 256 bits (32 bytes). -# Default: b'' +# Should be exactly 256 bits (32 bytes). +# Default: traitlets.Undefined +# c.JupyterHub.cookie_secret = traitlets.Undefined c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## File in which to store the cookie secret. # Default: 'jupyterhub_cookie_secret' # c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' -## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) -# Default: '/opt/iiab/jupyter/share/jupyterhub' -# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' +## Custom scopes to define. +# +# For use when defining custom roles, +# to grant users granular permissions +# +# All custom scopes must have a description, +# and must start with the prefix `custom:`. +# +# For example:: +# +# custom_scopes = { +# "custom:jupyter_server:read": { +# "description": "read-only access to a single-user server", +# }, +# } +# Default: {} +# c.JupyterHub.custom_scopes = {} -## Include any kwargs to pass to the database connection. See -# sqlalchemy.create_engine for details. +## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) +# Default: '/opt/iiab/jupyterhub/share/jupyterhub' +# c.JupyterHub.data_files_path = '/opt/iiab/jupyterhub/share/jupyterhub' + +## Include any kwargs to pass to the database connection. +# See sqlalchemy.create_engine for details. # Default: {} # c.JupyterHub.db_kwargs = {} ## url for the database. e.g. `sqlite:///jupyterhub.sqlite` # Default: 'sqlite:///jupyterhub.sqlite' +# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## log all database transactions. This has A LOT of output @@ -221,8 +317,13 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: False # c.JupyterHub.debug_proxy = False -## If named servers are enabled, default name of server to spawn or open, e.g. by -# user-redirect. +## If named servers are enabled, default name of server to spawn or open when no +# server is specified, e.g. by user-redirect. +# +# Note: This has no effect if named servers are not enabled, and does _not_ +# change the existence or behavior of the default server named `''` (the empty +# string). This only affects which named server is launched when no server is +# specified, e.g. by links to `/hub/user-redirect/lab/tree/mynotebook.ipynb`. # Default: '' # c.JupyterHub.default_server_name = '' @@ -245,30 +346,28 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: traitlets.Undefined # c.JupyterHub.default_url = traitlets.Undefined -## Dict authority:dict(files). Specify the key, cert, and/or ca file for an -# authority. This is useful for externally managed proxies that wish to use -# internal_ssl. +## Dict authority:dict(files). Specify the key, cert, and/or +# ca file for an authority. This is useful for externally managed +# proxies that wish to use internal_ssl. # -# The files dict has this format (you must specify at least a cert):: +# The files dict has this format (you must specify at least a cert):: # -# { -# 'key': '/path/to/key.key', -# 'cert': '/path/to/cert.crt', -# 'ca': '/path/to/ca.crt' -# } +# { +# 'key': '/path/to/key.key', +# 'cert': '/path/to/cert.crt', +# 'ca': '/path/to/ca.crt' +# } # -# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', -# 'proxy-client-ca', and 'services-ca'. +# The authorities you can override: 'hub-ca', 'notebooks-ca', +# 'proxy-api-ca', 'proxy-client-ca', and 'services-ca'. # -# Use with internal_ssl +# Use with internal_ssl # Default: {} # c.JupyterHub.external_ssl_authorities = {} -## Register extra tornado Handlers for jupyterhub. +## DEPRECATED. # -# Should be of the form ``("", Handler)`` -# -# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. +# If you need to register additional HTTP endpoints please use services instead. # Default: [] # c.JupyterHub.extra_handlers = [] @@ -282,6 +381,14 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: [] # c.JupyterHub.extra_log_handlers = [] +## Alternate header to use as the Host (e.g., X-Forwarded-Host) +# when determining whether a request is cross-origin +# +# This may be useful when JupyterHub is running behind a proxy that rewrites +# the Host header. +# Default: '' +# c.JupyterHub.forwarded_host_header = '' + ## Generate certs used for internal ssl # Default: False # c.JupyterHub.generate_certs = False @@ -303,19 +410,19 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: '' # c.JupyterHub.hub_bind_url = '' -## The ip or hostname for proxies and spawners to use for connecting to the Hub. +## The ip or hostname for proxies and spawners to use +# for connecting to the Hub. # -# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different -# from the connect address. +# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different +# from the connect address. # -# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise -# use `hub_ip`. +# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, +# otherwise use `hub_ip`. # -# Note: Some spawners or proxy implementations might not support hostnames. -# Check your spawner or proxy documentation to see if they have extra -# requirements. +# Note: Some spawners or proxy implementations might not support hostnames. Check your +# spawner or proxy documentation to see if they have extra requirements. # -# .. versionadded:: 0.8 +# .. versionadded:: 0.8 # Default: '' # c.JupyterHub.hub_connect_ip = '' @@ -346,39 +453,59 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## The ip address for the Hub process to *bind* to. # -# By default, the hub listens on localhost only. This address must be accessible -# from the proxy and user servers. You may need to set this to a public ip or '' -# for all interfaces if the proxy or user servers are in containers or on a -# different host. +# By default, the hub listens on localhost only. This address must be accessible from +# the proxy and user servers. You may need to set this to a public ip or '' for all +# interfaces if the proxy or user servers are in containers or on a different host. # -# See `hub_connect_ip` for cases where the bind and connect address should -# differ, or `hub_bind_url` for setting the full bind URL. +# See `hub_connect_ip` for cases where the bind and connect address should differ, +# or `hub_bind_url` for setting the full bind URL. # Default: '127.0.0.1' # c.JupyterHub.hub_ip = '127.0.0.1' ## The internal port for the Hub process. # -# This is the internal port of the hub itself. It should never be accessed -# directly. See JupyterHub.port for the public port to use when accessing -# jupyterhub. It is rare that this port should be set except in cases of port -# conflict. +# This is the internal port of the hub itself. It should never be accessed directly. +# See JupyterHub.port for the public port to use when accessing jupyterhub. +# It is rare that this port should be set except in cases of port conflict. # -# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. +# See also `hub_ip` for the ip and `hub_bind_url` for setting the full +# bind URL. # Default: 8081 # c.JupyterHub.hub_port = 8081 +## The routing prefix for the Hub itself. +# +# Override to send only a subset of traffic to the Hub. Default is to use the +# Hub as the default route for all requests. +# +# This is necessary for normal jupyterhub operation, as the Hub must receive +# requests for e.g. `/user/:name` when the user's server is not running. +# +# However, some deployments using only the JupyterHub API may want to handle +# these events themselves, in which case they can register their own default +# target with the proxy and set e.g. `hub_routespec = /hub/` to serve only the +# hub's own pages, or even `/hub/api/` for api-only operation. +# +# Note: hub_routespec must include the base_url, if any. +# +# .. versionadded:: 1.4 +# Default: '/' +# c.JupyterHub.hub_routespec = '/' + ## Trigger implicit spawns after this many seconds. # -# When a user visits a URL for a server that's not running, they are shown a -# page indicating that the requested server is not running with a button to -# spawn the server. +# When a user visits a URL for a server that's not running, +# they are shown a page indicating that the requested server +# is not running with a button to spawn the server. # -# Setting this to a positive value will redirect the user after this many -# seconds, effectively clicking this button automatically for the users, -# automatically beginning the spawn process. +# Setting this to a positive value will redirect the user +# after this many seconds, effectively clicking this button +# automatically for the users, +# automatically beginning the spawn process. # -# Warning: this can result in errors and surprising behavior when sharing access -# URLs to actual servers, since the wrong server is likely to be started. +# Warning: this can result in errors and surprising behavior +# when sharing access URLs to actual servers, +# since the wrong server is likely to be started. # Default: 0 # c.JupyterHub.implicit_spawn_seconds = 0 @@ -398,29 +525,30 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: 10 # c.JupyterHub.init_spawners_timeout = 10 -## The location to store certificates automatically created by JupyterHub. +## The location to store certificates automatically created by +# JupyterHub. # -# Use with internal_ssl +# Use with internal_ssl # Default: 'internal-ssl' # c.JupyterHub.internal_certs_location = 'internal-ssl' ## Enable SSL for all internal communication # -# This enables end-to-end encryption between all JupyterHub components. -# JupyterHub will automatically create the necessary certificate authority and -# sign notebook certificates as they're created. +# This enables end-to-end encryption between all JupyterHub components. +# JupyterHub will automatically create the necessary certificate +# authority and sign notebook certificates as they're created. # Default: False # c.JupyterHub.internal_ssl = False -## The public facing ip of the whole JupyterHub application (specifically -# referred to as the proxy). +## The public facing ip of the whole JupyterHub application +# (specifically referred to as the proxy). # -# This is the address on which the proxy will listen. The default is to listen -# on all interfaces. This is the only address through which JupyterHub should be -# accessed by users. +# This is the address on which the proxy will listen. The default is to +# listen on all interfaces. This is the only address through which JupyterHub +# should be accessed by users. # -# .. deprecated: 0.9 -# Use JupyterHub.bind_url +# .. deprecated: 0.9 +# Use JupyterHub.bind_url # Default: '' # c.JupyterHub.ip = '' @@ -434,14 +562,36 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## Dict of 'group': ['usernames'] to load at startup. # -# This strictly *adds* groups and users to groups. +# This strictly *adds* groups and users to groups. # -# Loading one set of groups, then starting JupyterHub again with a different set -# will not remove users or groups from previous launches. That must be done -# through the API. +# Loading one set of groups, then starting JupyterHub again with a different +# set will not remove users or groups from previous launches. +# That must be done through the API. # Default: {} # c.JupyterHub.load_groups = {} +## List of predefined role dictionaries to load at startup. +# +# For instance:: +# +# load_roles = [ +# { +# 'name': 'teacher', +# 'description': 'Access to users' information and group membership', +# 'scopes': ['users', 'groups'], +# 'users': ['cyclops', 'gandalf'], +# 'services': [], +# 'groups': [] +# } +# ] +# +# All keys apart from 'name' are optional. +# See all the available scopes in the JupyterHub REST API documentation. +# +# Default roles are defined in roles.py. +# Default: [] +# c.JupyterHub.load_roles = [] + ## The date format used by logging formatters for %(asctime)s # See also: Application.log_datefmt # c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' @@ -454,6 +604,10 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # See also: Application.log_level # c.JupyterHub.log_level = 30 +## +# See also: Application.logging_config +# c.JupyterHub.logging_config = {} + ## Specify path to a logo image to override the Jupyter logo in the banner. # Default: '' # c.JupyterHub.logo_file = '' @@ -464,20 +618,62 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Setting this can limit the total resources a user can consume. # # If set to 0, no limit is enforced. +# +# Can be an integer or a callable/awaitable based on the handler object: +# +# :: +# +# def named_server_limit_per_user_fn(handler): +# user = handler.current_user +# if user and user.admin: +# return 0 +# return 5 +# +# c.JupyterHub.named_server_limit_per_user = named_server_limit_per_user_fn # Default: 0 # c.JupyterHub.named_server_limit_per_user = 0 -## File to write PID Useful for daemonizing JupyterHub. +## Expiry (in seconds) of OAuth access tokens. +# +# The default is to expire when the cookie storing them expires, +# according to `cookie_max_age_days` config. +# +# These are the tokens stored in cookies when you visit +# a single-user server or service. +# When they expire, you must re-authenticate with the Hub, +# even if your Hub authentication is still valid. +# If your Hub authentication is valid, +# logging in may be a transparent redirect as you refresh the page. +# +# This does not affect JupyterHub API tokens in general, +# which do not expire by default. +# Only tokens issued during the oauth flow +# accessing services and single-user servers are affected. +# +# .. versionadded:: 1.4 +# OAuth token expires_in was not previously configurable. +# .. versionchanged:: 1.4 +# Default now uses cookie_max_age_days so that oauth tokens +# which are generally stored in cookies, +# expire when the cookies storing them expire. +# Previously, it was one hour. +# Default: 0 +# c.JupyterHub.oauth_token_expires_in = 0 + +## File to write PID +# Useful for daemonizing JupyterHub. # Default: '' # c.JupyterHub.pid_file = '' +c.ConfigurableHTTPProxy.pid_file = "/run/jupyterhub-proxy.pid" ## The public facing port of the proxy. # -# This is the port on which the proxy will listen. This is the only port through -# which JupyterHub should be accessed by users. +# This is the port on which the proxy will listen. +# This is the only port through which JupyterHub +# should be accessed by users. # -# .. deprecated: 0.9 -# Use JupyterHub.bind_url +# .. deprecated: 0.9 +# Use JupyterHub.bind_url # Default: 8000 # c.JupyterHub.port = 8000 @@ -493,9 +689,9 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # Default: '' # c.JupyterHub.proxy_auth_token = '' -## Interval (in seconds) at which to check if the proxy is running. -# Default: 30 -# c.JupyterHub.proxy_check_interval = 30 +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.check_running_interval +# Default: 5 +# c.JupyterHub.proxy_check_interval = 5 ## The class to use for configuring the JupyterHub proxy. # @@ -517,9 +713,9 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## Recreate all certificates used within JupyterHub on restart. # -# Note: enabling this feature requires restarting all notebook servers. +# Note: enabling this feature requires restarting all notebook servers. # -# Use with internal_ssl +# Use with internal_ssl # Default: False # c.JupyterHub.recreate_internal_certs = False @@ -538,29 +734,29 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## Dict of token:servicename to be loaded into the database. # -# Allows ahead-of-time generation of API tokens for use by externally managed -# services. +# Allows ahead-of-time generation of API tokens for use by externally +# managed services. # Default: {} # c.JupyterHub.service_tokens = {} ## List of service specification dictionaries. # -# A service +# A service # -# For instance:: +# For instance:: # -# services = [ -# { -# 'name': 'cull_idle', -# 'command': ['/path/to/cull_idle_servers.py'], -# }, -# { -# 'name': 'formgrader', -# 'url': 'http://127.0.0.1:1234', -# 'api_token': 'super-secret', -# 'environment': -# } -# ] +# services = [ +# { +# 'name': 'cull_idle', +# 'command': ['/path/to/cull_idle_servers.py'], +# }, +# { +# 'name': 'formgrader', +# 'url': 'http://127.0.0.1:1234', +# 'api_token': 'super-secret', +# 'environment': +# } +# ] # Default: [] # c.JupyterHub.services = [] @@ -585,21 +781,25 @@ c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' # e.g. `c.JupyterHub.spawner_class = 'localprocess'` # # Currently installed: +# - systemd: systemdspawner.SystemdSpawner +# - systemdspawner: systemdspawner.SystemdSpawner # - default: jupyterhub.spawner.LocalProcessSpawner # - localprocess: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # Default: 'jupyterhub.spawner.LocalProcessSpawner' +# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' +c.SystemdSpawner.dynamic_users = True ## Path to SSL certificate file for the public facing interface of the proxy # -# When setting this, you should also set ssl_key +# When setting this, you should also set ssl_key # Default: '' # c.JupyterHub.ssl_cert = '' ## Path to SSL key file for the public facing interface of the proxy # -# When setting this, you should also set ssl_cert +# When setting this, you should also set ssl_cert # Default: '' # c.JupyterHub.ssl_key = '' @@ -618,17 +818,18 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Run single-user servers on subdomains of this host. # -# This should be the full `https://hub.domain.tld[:port]`. +# This should be the full `https://hub.domain.tld[:port]`. # -# Provides additional cross-site protections for javascript served by single- -# user servers. +# Provides additional cross-site protections for javascript served by +# single-user servers. # -# Requires `.hub.domain.tld` to resolve to the same host as +# Requires `.hub.domain.tld` to resolve to the same host as # `hub.domain.tld`. # -# In general, this is most easily achieved with wildcard DNS. +# In general, this is most easily achieved with wildcard DNS. # -# When using SSL (i.e. always) this also requires a wildcard SSL certificate. +# When using SSL (i.e. always) this also requires a wildcard SSL +# certificate. # Default: '' # c.JupyterHub.subdomain_host = '' @@ -644,54 +845,69 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # Default: {} # c.JupyterHub.tornado_settings = {} -## Trust user-provided tokens (via JupyterHub.service_tokens) to have good -# entropy. +## Trust user-provided tokens (via JupyterHub.service_tokens) +# to have good entropy. # -# If you are not inserting additional tokens via configuration file, this flag -# has no effect. +# If you are not inserting additional tokens via configuration file, +# this flag has no effect. # -# In JupyterHub 0.8, internally generated tokens do not pass through additional -# hashing because the hashing is costly and does not increase the entropy of -# already-good UUIDs. +# In JupyterHub 0.8, internally generated tokens do not +# pass through additional hashing because the hashing is costly +# and does not increase the entropy of already-good UUIDs. # -# User-provided tokens, on the other hand, are not trusted to have good entropy -# by default, and are passed through many rounds of hashing to stretch the -# entropy of the key (i.e. user-provided tokens are treated as passwords instead -# of random keys). These keys are more costly to check. +# User-provided tokens, on the other hand, are not trusted to have good entropy by default, +# and are passed through many rounds of hashing to stretch the entropy of the key +# (i.e. user-provided tokens are treated as passwords instead of random keys). +# These keys are more costly to check. # -# If your inserted tokens are generated by a good-quality mechanism, e.g. -# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost -# of checking authentication tokens. +# If your inserted tokens are generated by a good-quality mechanism, +# e.g. `openssl rand -hex 32`, then you can set this flag to True +# to reduce the cost of checking authentication tokens. # Default: False # c.JupyterHub.trust_user_provided_tokens = False ## Names to include in the subject alternative name. # -# These names will be used for server name verification. This is useful if -# JupyterHub is being run behind a reverse proxy or services using ssl are on -# different hosts. +# These names will be used for server name verification. This is useful +# if JupyterHub is being run behind a reverse proxy or services using ssl +# are on different hosts. # -# Use with internal_ssl +# Use with internal_ssl # Default: [] # c.JupyterHub.trusted_alt_names = [] ## Downstream proxy IP addresses to trust. # -# This sets the list of IP addresses that are trusted and skipped when -# processing the `X-Forwarded-For` header. For example, if an external proxy is -# used for TLS termination, its IP address should be added to this list to -# ensure the correct client IP addresses are recorded in the logs instead of the -# proxy server's IP address. +# This sets the list of IP addresses that are trusted and skipped when processing +# the `X-Forwarded-For` header. For example, if an external proxy is used for TLS +# termination, its IP address should be added to this list to ensure the correct +# client IP addresses are recorded in the logs instead of the proxy server's IP +# address. # Default: [] # c.JupyterHub.trusted_downstream_ips = [] ## Upgrade the database automatically on start. # -# Only safe if database is regularly backed up. Only SQLite databases will be -# backed up to a local file automatically. +# Only safe if database is regularly backed up. +# Only SQLite databases will be backed up to a local file automatically. # Default: False # c.JupyterHub.upgrade_db = False +## Return 503 rather than 424 when request comes in for a non-running server. +# +# Prior to JupyterHub 2.0, we returned a 503 when any request came in for a user +# server that was currently not running. By default, JupyterHub 2.0 will return +# a 424 - this makes operational metric dashboards more useful. +# +# JupyterLab < 3.2 expected the 503 to know if the user server is no longer +# running, and prompted the user to start their server. Set this config to true +# to retain the old behavior, so JupyterLab < 3.2 can continue to show the +# appropriate UI when the user server is stopped. +# +# This option will be removed in a future release. +# Default: False +# c.JupyterHub.use_legacy_stopped_server_status_code = False + ## Callable to affect behavior of /user-redirect/ # # Receives 4 parameters: 1. path - URL path that was provided after /user- @@ -709,13 +925,17 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' #------------------------------------------------------------------------------ ## Base class for spawning single-user notebook servers. # -# Subclass this, and override the following methods: +# Subclass this, and override the following methods: # -# - load_state - get_state - start - stop - poll +# - load_state +# - get_state +# - start +# - stop +# - poll # -# As JupyterHub supports multiple users, an instance of the Spawner subclass is -# created for each user. If there are 20 JupyterHub users, there will be 20 -# instances of the subclass. +# As JupyterHub supports multiple users, an instance of the Spawner subclass +# is created for each user. If there are 20 JupyterHub users, there will be 20 +# instances of the subclass. ## Extra arguments to be passed to the single-user server. # @@ -862,12 +1082,32 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # Default: 30 # c.Spawner.http_timeout = 30 +## The URL the single-user server should connect to the Hub. +# +# If the Hub URL set in your JupyterHub config is not reachable from spawned +# notebooks, you can set differnt URL by this config. +# +# Is None if you don't need to change the URL. +# Default: None +# c.Spawner.hub_connect_url = None + ## The IP address (or hostname) the single-user server should listen on. # +# Usually either '127.0.0.1' (default) or '0.0.0.0'. +# # The JupyterHub proxy implementation should be able to send packets to this # interface. -# Default: '' -# c.Spawner.ip = '' +# +# Subclasses which launch remotely or in containers should override the default +# to '0.0.0.0'. +# +# .. versionchanged:: 2.0 +# Default changed to '127.0.0.1', from ''. +# In most cases, this does not result in a change in behavior, +# as '' was interpreted as 'unspecified', +# which used the subprocesses' own default, itself usually '127.0.0.1'. +# Default: '127.0.0.1' +# c.Spawner.ip = '127.0.0.1' ## Minimum number of bytes a single-user notebook server is guaranteed to have # available. @@ -918,6 +1158,35 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # Default: '' # c.Spawner.notebook_dir = '' +## Allowed scopes for oauth tokens issued by this server's oauth client. +# +# This sets the maximum and default scopes +# assigned to oauth tokens issued by a single-user server's +# oauth client (i.e. tokens stored in browsers after authenticating with the server), +# defining what actions the server can take on behalf of logged-in users. +# +# Default is an empty list, meaning minimal permissions to identify users, +# no actions can be taken on their behalf. +# +# If callable, will be called with the Spawner as a single argument. +# Callables may be async. +# Default: traitlets.Undefined +# c.Spawner.oauth_client_allowed_scopes = traitlets.Undefined + +## Allowed roles for oauth tokens. +# +# Deprecated in 3.0: use oauth_client_allowed_scopes +# +# This sets the maximum and default roles +# assigned to oauth tokens issued by a single-user server's +# oauth client (i.e. tokens stored in browsers after authenticating with the server), +# defining what actions the server can take on behalf of logged-in users. +# +# Default is an empty list, meaning minimal permissions to identify users, +# no actions can be taken on their behalf. +# Default: traitlets.Undefined +# c.Spawner.oauth_roles = traitlets.Undefined + ## An HTML form for options a user can specify on launching their server. # # The surrounding `
` element and the submit button are already provided. @@ -1021,8 +1290,8 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## List of SSL alt names # -# May be set in config if all spawners should have the same value(s), or set at -# runtime by Spawner that know their names. +# May be set in config if all spawners should have the same value(s), +# or set at runtime by Spawner that know their names. # Default: [] # c.Spawner.ssl_alt_names = [] @@ -1046,6 +1315,9 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Set of users that will have admin rights on this JupyterHub. # +# Note: As of JupyterHub 2.0, full admin rights should not be required, and more +# precise permissions can be managed via roles. +# # Admin users have extra privileges: # - Use the admin panel to see list of users logged in # - Add / remove users in some authenticators @@ -1057,6 +1329,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() +# c.Authenticator.admin_users = set() c.Authenticator.admin_users = set(['admin']) c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" @@ -1064,7 +1337,8 @@ c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" # # Use this with supported authenticators to restrict which users can log in. # This is an additional list that further restricts users, beyond whatever -# restrictions the authenticator has in place. +# restrictions the authenticator has in place. Any user in this list is granted +# the 'user' role on hub startup. # # If empty, does not perform any additional restriction. # @@ -1073,28 +1347,43 @@ c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" # Default: set() # c.Authenticator.allowed_users = set() -## The max age (in seconds) of authentication info before forcing a refresh of -# user auth info. +## The max age (in seconds) of authentication info +# before forcing a refresh of user auth info. # -# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. +# Refreshing auth info allows, e.g. requesting/re-validating auth +# tokens. # -# See :meth:`.refresh_user` for what happens when user auth info is refreshed -# (nothing by default). +# See :meth:`.refresh_user` for what happens when user auth info is refreshed +# (nothing by default). # Default: 300 # c.Authenticator.auth_refresh_age = 300 ## Automatically begin the login process # -# rather than starting with a "Login with..." link at `/hub/login` +# rather than starting with a "Login with..." link at `/hub/login` # -# To work, `.login_url()` must give a URL other than the default `/hub/login`, -# such as an oauth handler or another automatic login handler, registered with -# `.get_handlers()`. +# To work, `.login_url()` must give a URL other than the default `/hub/login`, +# such as an oauth handler or another automatic login handler, +# registered with `.get_handlers()`. # -# .. versionadded:: 0.8 +# .. versionadded:: 0.8 # Default: False # c.Authenticator.auto_login = False +## Automatically begin login process for OAuth2 authorization requests +# +# When another application is using JupyterHub as OAuth2 provider, it sends +# users to `/hub/api/oauth2/authorize`. If the user isn't logged in already, and +# auto_login is not set, the user will be dumped on the hub's home page, without +# any context on what to do next. +# +# Setting this to true will automatically redirect users to login if they aren't +# logged in *only* on the `/hub/api/oauth2/authorize` endpoint. +# +# .. versionadded:: 1.5 +# Default: False +# c.Authenticator.auto_login_oauth2_authorize = False + ## Set of usernames that are not allowed to log in. # # Use this with supported authenticators to restrict which users can not log in. @@ -1112,36 +1401,48 @@ c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" ## Delete any users from the database that do not pass validation # -# When JupyterHub starts, `.add_user` will be called on each user in the -# database to verify that all users are still valid. +# When JupyterHub starts, `.add_user` will be called +# on each user in the database to verify that all users are still valid. # -# If `delete_invalid_users` is True, any users that do not pass validation will -# be deleted from the database. Use this if users might be deleted from an -# external system, such as local user accounts. +# If `delete_invalid_users` is True, +# any users that do not pass validation will be deleted from the database. +# Use this if users might be deleted from an external system, +# such as local user accounts. # -# If False (default), invalid users remain in the Hub's database and a warning -# will be issued. This is the default to avoid data loss due to config changes. +# If False (default), invalid users remain in the Hub's database +# and a warning will be issued. +# This is the default to avoid data loss due to config changes. # Default: False # c.Authenticator.delete_invalid_users = False ## Enable persisting auth_state (if available). # -# auth_state will be encrypted and stored in the Hub's database. This can -# include things like authentication tokens, etc. to be passed to Spawners as -# environment variables. +# auth_state will be encrypted and stored in the Hub's database. +# This can include things like authentication tokens, etc. +# to be passed to Spawners as environment variables. # -# Encrypting auth_state requires the cryptography package. +# Encrypting auth_state requires the cryptography package. # -# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one -# (or more, separated by ;) 32B encryption keys. These can be either base64 or -# hex-encoded. +# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must +# contain one (or more, separated by ;) 32B encryption keys. +# These can be either base64 or hex-encoded. # -# If encryption is unavailable, auth_state cannot be persisted. +# If encryption is unavailable, auth_state cannot be persisted. # -# New in JupyterHub 0.8 +# New in JupyterHub 0.8 # Default: False # c.Authenticator.enable_auth_state = False +## Let authenticator manage user groups +# +# If True, Authenticator.authenticate and/or .refresh_user +# may return a list of group names in the 'groups' field, +# which will be assigned to the user. +# +# All group-assignment APIs are disabled if this is True. +# Default: False +# c.Authenticator.manage_groups = False + ## An optional hook function that you can implement to do some bootstrapping work # during authentication. For example, loading user account details from an # external system. @@ -1176,20 +1477,20 @@ c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" ## Force refresh of auth prior to spawn. # -# This forces :meth:`.refresh_user` to be called prior to launching a server, to -# ensure that auth state is up-to-date. +# This forces :meth:`.refresh_user` to be called prior to launching +# a server, to ensure that auth state is up-to-date. # -# This can be important when e.g. auth tokens that may have expired are passed -# to the spawner via environment variables from auth_state. +# This can be important when e.g. auth tokens that may have expired +# are passed to the spawner via environment variables from auth_state. # -# If refresh_user cannot refresh the user auth data, launch will fail until the -# user logs in again. +# If refresh_user cannot refresh the user auth data, +# launch will fail until the user logs in again. # Default: False # c.Authenticator.refresh_pre_spawn = False ## Dictionary mapping authenticator usernames to JupyterHub users. # -# Primarily used to normalize OAuth user names to local users. +# Primarily used to normalize OAuth user names to local users. # Default: {} # c.Authenticator.username_map = {} @@ -1211,29 +1512,11 @@ c.Authenticator.dbm_path = "{{ jupyterhub_venv }}/etc/passwords.dbm" #------------------------------------------------------------------------------ ## Encapsulate encryption configuration # -# Use via the encryption_config singleton below. +# Use via the encryption_config singleton below. # Default: [] # c.CryptKeeper.keys = [] ## The number of threads to allocate for encryption -# Default: 4 -# c.CryptKeeper.n_threads = 4 - -#------------------------------------------------------------------------------ -# Pagination(Configurable) configuration -#------------------------------------------------------------------------------ -## Default number of entries per page for paginated results. -# Default: 100 -# c.Pagination.default_per_page = 100 - -## Maximum number of entries per page for paginated results. -# Default: 250 -# c.Pagination.max_per_page = 250 - -#------------------------------------------------------------------------------ -# Systemdspawner config -#------------------------------------------------------------------------------ -c.SystemdSpawner.dynamic_users = True -c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' - +# Default: 2 +# c.CryptKeeper.n_threads = 2 diff --git a/roles/jupyterhub/templates/patch_FUA.sh.j2 b/roles/jupyterhub/templates/patch_FUA.sh.j2.unused similarity index 100% rename from roles/jupyterhub/templates/patch_FUA.sh.j2 rename to roles/jupyterhub/templates/patch_FUA.sh.j2.unused diff --git a/roles/kalite/tasks/enable-or-disable.yml b/roles/kalite/tasks/enable-or-disable.yml new file mode 100644 index 000000000..fca843870 --- /dev/null +++ b/roles/kalite/tasks/enable-or-disable.yml @@ -0,0 +1,14 @@ +- name: Enable & (Re)Start 'kalite-serve' service, if kalite_enabled + systemd: + daemon_reload: yes + name: kalite-serve + enabled: yes + state: restarted + when: kalite_enabled + +- name: Disable & Stop 'kalite-serve' service, if not kalite_enabled + systemd: + name: kalite-serve + enabled: no + state: stopped + when: not kalite_enabled diff --git a/roles/kalite/tasks/install.yml b/roles/kalite/tasks/install.yml index c53230138..5738c7301 100644 --- a/roles/kalite/tasks/install.yml +++ b/roles/kalite/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Download {{ kalite_requirements }} to {{ pip_packages_dir }}/kalite.txt get_url: url: "{{ kalite_requirements }}" @@ -10,36 +15,46 @@ # ignore_errors: yes # when: is_raspbian -- name: 'Install packages: python2, python-setuptools, virtualenv (for Python 2)' +- name: 'Install packages: python2, python-setuptools, virtualenv (for Python 2) -- if Ubuntu 22.04 / Mint 21' package: name: - python2 - python-setuptools # Provides setuptools-44 on recent OS's (last version compatible with python2) - - virtualenv # For Ansible module 'pip' when used with 'virtualenv_command: /usr/bin/virtualenv' and 'virtualenv_python: python2.7' -- compare package 'python3-venv' used by roles {calibre-web, jupyterhub, lokole} + - virtualenv # Drags in 'python3-virtualenv' which in turn drags in 'python3-pip' -- for Ansible module 'pip' when used with 'virtualenv_command: /usr/bin/virtualenv' and 'virtualenv_python: python2.7' -- compare package 'python3-venv' used by roles {calibre-web, jupyterhub, lokole} state: present - #when: not (is_debian_9 or is_debian_10 or is_ubuntu_16 or is_ubuntu_17 or is_ubuntu_18 or is_ubuntu_19) - # 2020-03-31: Testing for {is_raspbian_9, is_raspbian_10} is not currently nec, as testing for {is_debian_9, is_debian_10} covers that already. + when: is_ubuntu_2204 # Also covers is_linuxmint_21 -- name: Use pip to pin setuptools to 44 in {{ kalite_venv }} if Raspbian/Debian > 10 or Ubuntu > 19 +- name: Run scripts/install_python2.sh to install python2 and virtualenv -- if Debian 12 or RasPiOS 12 + command: "{{ iiab_dir }}/scripts/install_python2.sh" + when: is_debian_12 # Also covers is_raspbian_12 + +- name: Use pip to pin setuptools to 44 in {{ kalite_venv }} -- if Ubuntu 22.04 / Mint 21, Ubuntu 23.10, Debian 12 or RasPiOS 12 pip: name: setuptools==44 virtualenv: "{{ kalite_venv }}" # /usr/local/kalite/venv virtualenv_site_packages: no - virtualenv_command: /usr/bin/virtualenv + virtualenv_command: virtualenv # Traditionally /usr/bin/virtual/env -- but install_python2.sh (for Ubuntu 23.10+) sets up /usr/local/bin/virtualenv virtualenv_python: python2.7 extra_args: "--no-use-pep517 --no-cache-dir --no-python-version-warning" - when: not (is_debian_9 or is_debian_10 or is_ubuntu_16 or is_ubuntu_17 or is_ubuntu_18 or is_ubuntu_19) - # long form of (is_debian_11+ or is_ubuntu_20+) + when: is_ubuntu_2204 or is_ubuntu_2310 or is_debian_12 # Also covers is_linuxmint_21 and is_raspbian_12 -- name: Use pip to install ka-lite-static to {{ kalite_venv }} +- name: Use pip to install ka-lite-static to {{ kalite_venv }} -- if Ubuntu 22.04 / Mint 21, Ubuntu 23.10, Debian 12 or RasPiOS 12 pip: name: ka-lite-static version: "{{ kalite_version }}" virtualenv: "{{ kalite_venv }}" virtualenv_site_packages: no - virtualenv_command: /usr/bin/virtualenv + virtualenv_command: virtualenv virtualenv_python: python2.7 extra_args: "--no-cache-dir" + when: is_ubuntu_2204 or is_ubuntu_2310 or is_debian_12 # Also covers is_linuxmint_21 and is_raspbian_12 + +# 2024-04-30: Sadly no longer works with Ubuntu 24.04 LTS final release (#3731). +# So roles/kalite is OS-restricted during initial install, SEE: roles/7-edu-apps/tasks/main.yml +# CLARIF: If install_python2_kalite-venv_u2404.sh proves no longer useful, it will deprecated in coming months. +- name: Run scripts/install_python2_kalite-venv_u2404.sh -- if Ubuntu 24.04+ or Mint 22 + command: bash "{{ iiab_dir }}/scripts/install_python2_kalite-venv_u2404.sh" + when: is_ubuntu and not is_linuxmint and os_ver is version('ubuntu-2404', '>=') or is_linuxmint_22 - name: "Install from templates: venv wrapper /usr/bin/kalite, unit file /etc/systemd/system/kalite-serve.service" template: @@ -50,30 +65,11 @@ - { src: 'kalite.sh.j2', dest: '/usr/bin/kalite', mode: '0755' } - { src: 'kalite-serve.service.j2', dest: '/etc/systemd/system/kalite-serve.service', mode: '0644' } -# Useless stanza, for 2 reasons: (1) http://box/kalite was never made to work -# (2) /etc/apache2/sites-available does not exist on many IIAB's w/o Apache -# - name: "Install from template: /etc/{{ apache_conf_dir }}/kalite.conf (useless, as http://box/kalite was never made to work)" -# template: -# src: kalite.conf -# dest: "/etc/{{ apache_conf_dir }}" # apache2/sites-available on debuntu -# when: apache_installed is defined - -- name: Fix KA Lite bug in regex parsing ifconfig output (ifcfg/parser.py) for @m-anish's network names that contain dashes, if Raspbian/Debian > 10 or Ubuntu > 19 +- name: Fix KA Lite bug in regex parsing ifconfig output (ifcfg/parser.py) for @m-anish's network names that contain dashes # WAS: if Raspbian/Debian > 10 or Ubuntu > 19 replace: path: "{{ kalite_venv }}/lib/python2.7/site-packages/kalite/packages/dist/ifcfg/parser.py" # /usr/local/kalite/venv regexp: 'a-zA-Z0-9' replace: 'a-zA-Z0-9\-' - when: not (is_debian_9 or is_debian_10 or is_ubuntu_16 or is_ubuntu_17 or is_ubuntu_18 or is_ubuntu_19) - # 2020-03-31: Testing for {is_raspbian_9, is_raspbian_10} is not currently nec, as testing for {is_debian_9, is_debian_10} covers that already. - # JV: why not just is_ubuntu_20? AH: to make this work on Ubuntu 21+ and ideally Debian/RaspiOS 11+ too? - -- name: Fix KA Lite bug in regex parsing ifconfig output (ifcfg/parser.py) for @m-anish's network names that contain dashes, if Raspbian/Debian < 11 or Ubuntu < 20 - replace: - path: "{{ kalite_venv }}/local/lib/python2.7/site-packages/kalite/packages/dist/ifcfg/parser.py" - regexp: 'a-zA-Z0-9' - replace: 'a-zA-Z0-9\-' - when: is_debian_9 or is_debian_10 or is_ubuntu_16 or is_ubuntu_17 or is_ubuntu_18 or is_ubuntu_19 - # 2020-03-31: Testing for {is_raspbian_9, is_raspbian_10} is not currently nec, as testing for {is_debian_9, is_debian_10} covers that already. - name: Create dir {{ kalite_root }} file: @@ -90,6 +86,17 @@ # RECORD KA Lite AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'kalite_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: kalite + option: kalite_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'kalite_installed: True'" set_fact: kalite_installed: True diff --git a/roles/kalite/tasks/main.yml b/roles/kalite/tasks/main.yml index 817895f07..3786a9c38 100644 --- a/roles/kalite/tasks/main.yml +++ b/roles/kalite/tasks/main.yml @@ -19,43 +19,37 @@ quiet: yes -- name: Install KA Lite if 'kalite_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: kalite_installed is undefined +- block: + - name: Install KA Lite if 'kalite_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: kalite_installed is undefined -- name: Enable & (Re)Start 'kalite-serve' service, if kalite_enabled - systemd: - daemon_reload: yes - name: kalite-serve - enabled: yes - state: restarted - when: kalite_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'kalite-serve' service, if not kalite_enabled - systemd: - name: kalite-serve - enabled: no - state: stopped - when: not kalite_enabled + - name: Add 'kalite' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: kalite + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: "KA Lite" + - option: description + value: '"KA Lite downloads Khan Academy videos for offline use, with exercises and accounts if students want to track their own progress."' + - option: kalite_install + value: "{{ kalite_install }}" + - option: kalite_enabled + value: "{{ kalite_enabled }}" + - option: path + value: "{{ kalite_root }}" + - option: port + value: "{{ kalite_server_port }}" + rescue: -- name: Add 'kalite' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: kalite - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: "KA Lite" - - option: description - value: '"KA Lite downloads Khan Academy videos for offline use, with exercises and accounts if students want to track their own progress."' - - option: kalite_install - value: "{{ kalite_install }}" - - option: kalite_enabled - value: "{{ kalite_enabled }}" - - option: path - value: "{{ kalite_root }}" - - option: port - value: "{{ kalite_server_port }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/kiwix/README.rst b/roles/kiwix/README.rst index 0a6aa1741..db77fd05e 100644 --- a/roles/kiwix/README.rst +++ b/roles/kiwix/README.rst @@ -3,21 +3,21 @@ Kiwix README ============ Kiwix develops ZIM file creation & rendering tools for offline action, -as summarized at: http://wiki.kiwix.org/wiki/Software +as summarized at: https://wiki.kiwix.org/wiki/Software -Internet-in-a-Box uses the kiwix-serve and kiwix-manage executables (in -/opt/iiab/kiwix/bin) to set up and render ZIM files such as Wikipedia, and -other educational materials: http://download.kiwix.org/zim/ +Internet-in-a-Box uses `kiwix-tools `_ executables like kiwix-manage, kiwix-serve and kiwix-search (in +``/opt/iiab/kiwix/bin``) to set up and render ZIM files (such as Wikipedia, and +other educational materials) typically from https://download.kiwix.org/zim/ Locations --------- -- Your ZIM files go in /library/zims/content -- Your ZIM index files go in directories under /library/zims/index (these index files are increasingly no longer necessary, as most ZIM files produced since 2017 contain an internal search index instead!) -- The URL is http://box/kiwix or http://box.lan/kiwix (both proxied for AWStats) -- Use URL http://box:3000/kiwix/ if you want to avoid the proxy +- Your ZIM files go in ``/library/zims/content`` +- Your ZIM index files used to go in directories under ``/library/zims/index`` (these index files are increasingly no longer necessary, as most ZIM files produced since 2017 contain an internal search index instead!) +- The URL is http://box/kiwix or http://box.lan/kiwix (both proxied for AWStats, Matomo, ETC) +- Use URL http://box:3000/kiwix if you want to avoid the proxy -Your local ZIM catalog (at /library/zims/library.xml) can be regenerated by running: -/usr/bin/iiab-make-kiwix-lib +Your ``/library/zims/library.xml`` (containing essential metadata for the ZIM files you've installed) can be regenerated if necessary, by running: +``/usr/bin/iiab-make-kiwix-lib`` -See "How do I add ZIM files, like Wikipedia?" at http://FAQ.IIAB.IO +See also "How do I add ZIM files, like Wikipedia?" at http://FAQ.IIAB.IO diff --git a/roles/kiwix/defaults/main.yml b/roles/kiwix/defaults/main.yml index 2920d60b1..52e881796 100644 --- a/roles/kiwix/defaults/main.yml +++ b/roles/kiwix/defaults/main.yml @@ -8,11 +8,11 @@ # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -# INSTRUCTIONS TO REINSTALL Kiwix: -# (1) VERIFY THESE VARS IN /etc/iiab/local_vars.yml +# ONLINE UPGRADE INSTRUCTIONS: +# (1) VERIFY VARS IN /etc/iiab/local_vars.yml # kiwix_install: True # kiwix_enabled: True -# (2) RUN: cd /opt/iiab/iiab; ./runrole --reinstall kiwix +# (2) RUN: cd /opt/iiab/iiab; sudo ./runrole --reinstall kiwix # FYI /library/zims contains 3 important things: @@ -21,14 +21,30 @@ # - index = directory for legacy *.zim.idx's kiwix_library_xml: "{{ iiab_zim_path }}/library.xml" -# 3 lines below specify which version(s) of kiwix-tools to download from... -# http://download.iiab.io/packages/ ...as originally obtained from... -# http://download.kiwix.org/release/kiwix-tools/ ...or sometimes... -# http://download.kiwix.org/nightly/ +kiwix_base_url: https://download.kiwix.org/release/kiwix-tools/ +#kiwix_base_url: https://download.kiwix.org/nightly/2022-10-04/ +#kiwix_base_url: "{{ iiab_download_url }}/" # e.g. https://download.iiab.io/packages/ -kiwix_version_armhf: kiwix-tools_linux-armhf-2021-12-24 -kiwix_version_linux64: kiwix-tools_linux-x86_64-2021-12-24 -kiwix_version_i686: kiwix-tools_linux-i586-2021-12-24 +kiwix_arch_dict: # 'dpkg --print-architecture' key would be: (to mitigate #3516 in future, if truly nec?) + #i386: # ? + i686: i586 # ? + x86_64: x86_64 # amd64 + armv6l: armv6 # armhf + armv7l: armv8 # armhf BEWARE: armhf version of kiwix-tools suddenly FAILS on 64-bit RasPiOS, since 3.5.0 released 2023-04-28 -- #3574, PR #3576 + aarch64: aarch64 # arm64 BEWARE: "32-bit" RasPiOS suddenly boots 64-bit kernel since March 2023 -- #3516, explained at https://github.com/iiab/iiab/pull/3422#issuecomment-1533441463 + +# ansible_architecture might also work, if not quite as well: +# https://stackoverflow.com/questions/66828315/what-is-the-difference-between-ansible-architecture-and-ansible-machine-on-a/66828837#66828837 +# CLAIM: 'ansible_machine might be "i686", whereas ansible_architecture on the same host would be "i386"' +# https://stackoverflow.com/questions/44713880/how-do-i-make-decision-based-on-arch-in-ansible-playbooks/44714226#44714226 +kiwix_arch: "{{ kiwix_arch_dict[ansible_machine] | default('unsupported') }}" + +# Latest official kiwix-tools release, per Kiwix permalink redirects: +# https://www.kiwix.org/en/downloads/kiwix-serve/ +# https://github.com/kiwix/container-images/issues/236 +# https://github.com/kiwix/kiwix-tools/issues/623 +kiwix_tar_gz: "kiwix-tools_linux-{{ kiwix_arch }}.tar.gz" +#kiwix_tar_gz: "kiwix-tools_linux-{{ kiwix_arch }}-3.3.0-1.tar.gz" # Version can be hard-coded if you prefer (as was done til 2022-10-04) # kiwix_src_file_i686: "kiwix-linux-i686.tar.bz2" # v0.9 for i686 published May 2014 ("use it to test legacy ZIM content") diff --git a/roles/kiwix/tasks/enable-or-disable.yml b/roles/kiwix/tasks/enable-or-disable.yml index 9f813f4ad..a139a6551 100644 --- a/roles/kiwix/tasks/enable-or-disable.yml +++ b/roles/kiwix/tasks/enable-or-disable.yml @@ -13,30 +13,46 @@ systemd: name: kiwix-serve enabled: yes - state: started # Not needed...but can't hurt + state: started when: kiwix_enabled -# TO DO: BOTH CRON ENTRIES BELOW *SHOULD* BE DELETED "when: not kiwix_enabled" - # In the past kiwix-serve did not stay running, so we'd been doing this hourly. # @mgautierfr & others suggest kiwix-serve might be auto-restarted w/o cron in # future, whenever service fails, if this really catches all cases?? # https://github.com/iiab/iiab/issues/484#issuecomment-342151726 -- name: Make a crontab entry to restart kiwix-serve at 4AM (debuntu) - lineinfile: - # mn hr dy mo day-of-week[Sunday=0] username command-to-be-executed - line: "0 4 * * * root /bin/systemctl restart kiwix-serve.service" - dest: /etc/crontab - when: kiwix_enabled and is_debuntu -- name: Make a crontab entry to restart kiwix-serve at 4AM (redhat) -# * * * * * user-name command to be executed - lineinfile: - # mn hr dy mo day-of-week[Sunday=0] username command-to-be-executed - line: "0 4 * * * root /usr/bin/systemctl restart kiwix-serve.service" - dest: /etc/crontab - when: kiwix_enabled and is_redhat +- name: Set cron to restart kiwix-serve 4AM daily, if kiwix_enabled + cron: + name: kiwix-serve daily restart + minute: "0" + hour: "4" + job: /usr/bin/systemctl restart kiwix-serve.service + user: root + cron_file: kiwix-serve_daily # i.e. /etc/cron.d/kiwix-serve_daily instead of /var/spool/cron/crontabs/root or /etc/cron.daily/* or /etc/crontab + when: kiwix_enabled + +- name: Remove 4AM daily cron, if not kiwix_enabled + cron: + name: kiwix-serve daily restart + cron_file: kiwix-serve_daily + state: absent + when: not kiwix_enabled + +# - name: Make a crontab entry to restart kiwix-serve at 4AM (debuntu) +# lineinfile: +# # mn hr dy mo day-of-week[Sunday=0] username command-to-be-executed +# line: "0 4 * * * root /usr/bin/systemctl restart kiwix-serve.service" +# dest: /etc/crontab +# when: kiwix_enabled + +# - name: Make a crontab entry to restart kiwix-serve at 4AM (redhat) +# # * * * * * user-name command to be executed +# lineinfile: +# # mn hr dy mo day-of-week[Sunday=0] username command-to-be-executed +# line: "0 4 * * * root /usr/bin/systemctl restart kiwix-serve.service" +# dest: /etc/crontab +# when: kiwix_enabled and is_redhat - name: Enable/Disable/Restart NGINX diff --git a/roles/kiwix/tasks/install.yml b/roles/kiwix/tasks/install.yml index 52647ffe9..a78f71d21 100644 --- a/roles/kiwix/tasks/install.yml +++ b/roles/kiwix/tasks/install.yml @@ -1,49 +1,62 @@ -# 0. SET CPU ARCHITECTURE +# 0. VERIFY CPU/OS ARCHITECTURE SUPPORTED -- name: "Initialize 'kiwix_src_dir: False' just in case CPU architecture is not supported" - set_fact: - kiwix_src_dir: False - -- name: "Set fact 'kiwix_src_dir: {{ kiwix_version_armhf }}' (armv6l or armv71 or aarch64)" - set_fact: - kiwix_src_dir: "{{ kiwix_version_armhf }}" - when: ansible_machine == "armv6l" or ansible_machine == "armv7l" or ansible_machine == "aarch64" - -- name: "Set fact 'kiwix_src_dir: {{ kiwix_version_linux64 }}' (x86_64)" - set_fact: - kiwix_src_dir: "{{ kiwix_version_linux64 }}" - when: ansible_machine == "x86_64" - -- name: "Set fact 'kiwix_src_dir: {{ kiwix_version_i686 }}' (i686)" - set_fact: - kiwix_src_dir: "{{ kiwix_version_i686 }}" - when: ansible_machine == "i686" -# COMMENT OUT LINE ABOVE TO TEST i686 CODE PATH ON X86_64 (WORKS NOV 2017) - -- name: Force Ansible to exit (FAIL) if kiwix-tools appears unavailable for your architecture ({{ ansible_machine }}) +- name: Force Ansible to exit (FAIL) if kiwix-tools appears unavailable for your CPU/OS architecture ({{ ansible_machine }}) fail: - msg: "WARNING: kiwix-tools SOFTWARE APPEARS UNAVAILABLE FOR YOUR {{ ansible_machine }} OS/ARCHITECTURE." - when: not kiwix_src_dir - -- name: "Set fact 'kiwix_src_file: {{ kiwix_src_dir }}.tar.gz'" - set_fact: - kiwix_src_file: "{{ kiwix_src_dir }}.tar.gz" + msg: "WARNING: kiwix-tools SOFTWARE APPEARS UNAVAILABLE FOR YOUR {{ ansible_machine }} CPU/OS ARCHITECTURE." + when: kiwix_arch == "unsupported" -# 1. PUT IN PLACE: /opt/iiab/downloads/kiwix-tools_linux-*.tar.gz, essential dirs, and test.zim if nec (library.xml is created later, by enable-or-disable.yml) +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 -- name: Download {{ iiab_download_url }}/{{ kiwix_src_file }} to /opt/iiab/downloads + +# 1. PUT IN PLACE: /opt/iiab/downloads/kiwix-tools_linux-*.tar.gz, move /opt/iiab/kiwix/bin aside if nec, create essential dirs, and test.zim if nec (library.xml is created later, by enable-or-disable.yml) + +# 2022-10-04: get_url might be removed in future (unarchive below can handle +# everything!) Conversely: (1) unarchive doesn't support timeout (2) one day +# /opt/iiab/downloads might have practical value beyond hoarding (unlikely!) +- name: Download {{ kiwix_base_url }}{{ kiwix_tar_gz }} into /opt/iiab/downloads (ACTUAL filename should include kiwix-tools version, or nightly build date) get_url: - url: "{{ iiab_download_url }}/{{ kiwix_src_file }}" # http://download.iiab.io/packages - dest: "{{ downloads_dir }}/{{ kiwix_src_file }}" # /opt/iiab/downloads + url: "{{ kiwix_base_url }}{{ kiwix_tar_gz }}" # e.g. https://download.kiwix.org/release/kiwix-tools/ + kiwix-tools_linux-x86_64.tar.gz + dest: "{{ downloads_dir }}" # /opt/iiab/downloads + #force: yes # Already implied b/c dest is a dir! (to recover from incomplete downloads, etc) timeout: "{{ download_timeout }}" + register: kiwix_dl # PATH /opt/iiab/downloads + ACTUAL filename put in kiwix_dl.dest, for unarchive ~28 lines below + +# - name: "2023-05-14: TEMPORARY PATCH REVERTING TO KIWIX-TOOLS 3.4.0 IF BUGGY 32-BIT (armhf) VERSION 3.5.0 IS DETECTED -- #3574" +# get_url: +# url: https://download.kiwix.org/release/kiwix-tools/kiwix-tools_linux-armhf-3.4.0.tar.gz +# dest: "{{ downloads_dir }}" +# timeout: "{{ download_timeout }}" +# #register: kiwix_dl # CLOBBERS kiwix_dl.dest WHEN THIS STANZA DOES NOT RUN :/ +# when: kiwix_dl.dest == "/opt/iiab/downloads/kiwix-tools_linux-armhf-3.5.0.tar.gz" +# +# # Ansible does not allow changing individuals subfields in a dictionary, but +# # this crude hack works, overwriting the entire kiwix_dl dictionary var with +# # the single (needed) key/value pair. (Or "register: tmp_dl" could be set +# # above, if its other [subfields, key/value pairs, etc] really mattered...) +# - name: "2023-05-15: TEMPORARY PATCH REVERTING TO KIWIX-TOOLS 3.4.0 IF BUGGY 32-BIT (armhf) VERSION 3.5.0 IS DETECTED -- #3574" +# set_fact: +# kiwix_dl: +# dest: /opt/iiab/downloads/kiwix-tools_linux-armhf-3.4.0.tar.gz +# when: kiwix_dl.dest == "/opt/iiab/downloads/kiwix-tools_linux-armhf-3.5.0.tar.gz" + +- name: Does {{ kiwix_path }}/bin already exist? (as a directory, symlink or file) + stat: + path: "{{ kiwix_path }}/bin" # /opt/iiab/kiwix + register: kiwix_bin + +- name: If so, move {{ kiwix_path }}/bin to {{ kiwix_path }}/bin.DATE_TIME_TZ + shell: "mv {{ kiwix_path }}/bin {{ kiwix_path }}/bin.$(date +%F_%T_%Z)" + when: kiwix_bin.stat.exists - name: "Create dirs, including parent dirs: {{ kiwix_path }}/bin (executables), {{ iiab_zim_path }}/content (ZIM files), {{ iiab_zim_path }}/index (legacy indexes) (by default 0755)" file: path: "{{ item }}" state: directory with_items: - - "{{ kiwix_path }}/bin" # /opt/iiab/kiwix + - "{{ kiwix_path }}/bin" - "{{ iiab_zim_path }}/content" # /library/zims - "{{ iiab_zim_path }}/index" @@ -63,13 +76,13 @@ # 2. INSTALL KIWIX-TOOLS EXECUTABLES -- name: Unarchive {{ kiwix_src_file }} to /tmp # e.g. kiwix-tools_linux-armhf-3.1.2-3.tar.gz +- name: Unarchive {{ kiwix_dl.dest }} to {{ kiwix_path }}/bin -- untar with '--strip-components=1' to chop tarball's top-level dir from path unarchive: - src: "{{ downloads_dir }}/{{ kiwix_src_file }}" - dest: /tmp - -- name: Move /tmp/{{ kiwix_src_dir }}/* to permanent location {{ kiwix_path }}/bin - shell: "mv /tmp/{{ kiwix_src_dir }}/* {{ kiwix_path }}/bin/" # /opt/iiab/kiwix + src: "{{ kiwix_dl.dest }}" # See ~28 lines above, e.g. /opt/iiab/downloads/kiwix-tools_linux-x86_64-3.3.0-1.tar.gz + dest: "{{ kiwix_path }}/bin" + extra_opts: --strip-components=1 + owner: root # 2023-05-14: When unpacking let's avoid bogus owner/group, + group: root # arising from UID/GID on Kiwix's build machine. # 3. ENABLE MODS FOR APACHE PROXY IF DEBUNTU @@ -103,7 +116,6 @@ systemd: daemon_reload: yes -# install kiwix app - name: Install Kiwix Android app include_tasks: kiwix-apk.yml when: kiwix_incl_apk @@ -111,6 +123,17 @@ # 5. RECORD Kiwix AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'kiwix_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: kiwix + option: kiwix_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'kiwix_installed: True'" set_fact: kiwix_installed: True diff --git a/roles/kiwix/tasks/kiwix-apk.yml b/roles/kiwix/tasks/kiwix-apk.yml index 667a45fa8..fa03667f3 100644 --- a/roles/kiwix/tasks/kiwix-apk.yml +++ b/roles/kiwix/tasks/kiwix-apk.yml @@ -6,12 +6,12 @@ - name: Download kiwix.apk to {{ doc_root }}{{ kiwix_apk_url }} get_url: - url: "{{ kiwix_apk_src }}" # https://download.kiwix.org/release/kiwix-android/kiwix.apk + url: "{{ kiwix_apk_src }}" # e.g. https://download.kiwix.org/release/kiwix-android/kiwix.apk formerly kiwix-3.5.0.apk dest: "{{ doc_root }}{{ kiwix_apk_url }}" timeout: "{{ download_timeout }}" - name: Symlink {{ doc_root }}{{ kiwix_apk_url }}/zims -> {{ iiab_zim_path }}/content file: src: "{{ iiab_zim_path }}/content" # /library/zims/content - path: "{{ doc_root }}{{ kiwix_apk_url }}/zims" # /library/www/html/softare/kiwix/zims + path: "{{ doc_root }}{{ kiwix_apk_url }}/zims" # /library/www/html/software/kiwix/zims state: link diff --git a/roles/kiwix/tasks/main.yml b/roles/kiwix/tasks/main.yml index 742e698d9..22c8820dc 100644 --- a/roles/kiwix/tasks/main.yml +++ b/roles/kiwix/tasks/main.yml @@ -19,38 +19,47 @@ quiet: yes -- name: Install Kiwix if 'kiwix_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: kiwix_installed is undefined +- block: + - name: Install Kiwix if 'kiwix_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: kiwix_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'kiwix' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" + section: kiwix + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Kiwix + - option: description + value: '"Part of https://github.com/kiwix/kiwix-tools/ -- kiwix-serve is the most used web server for ZIM files."' + - option: kiwix_install + value: "{{ kiwix_install }}" + - option: kiwix_enabled + value: "{{ kiwix_enabled }}" + - option: kiwix_tar_gz + value: "{{ kiwix_tar_gz }}" + - option: kiwix_url + value: "{{ kiwix_url }}" + - option: kiwix_url_plus_slash + value: "{{ kiwix_url_plus_slash }}" + - option: kiwix_path + value: "{{ kiwix_path }}" + - option: kiwix_port + value: "{{ kiwix_port }}" + - option: iiab_zim_path + value: "{{ iiab_zim_path }}" + - option: kiwix_library_xml + value: "{{ kiwix_library_xml }}" -- name: Add 'kiwix' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" - section: kiwix - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Kiwix - - option: description - value: '"Part of https://github.com/kiwix/kiwix-tools/ -- kiwix-serve is the most used web server for ZIM files."' - - option: kiwix_install - value: "{{ kiwix_install }}" - - option: kiwix_enabled - value: "{{ kiwix_enabled }}" - - option: kiwix_url - value: "{{ kiwix_url }}" - - option: kiwix_url_plus_slash - value: "{{ kiwix_url_plus_slash }}" - - option: kiwix_path - value: "{{ kiwix_path }}" - - option: kiwix_port - value: "{{ kiwix_port }}" - - option: iiab_zim_path - value: "{{ iiab_zim_path }}" - - option: kiwix_library_xml - value: "{{ kiwix_library_xml }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/kiwix/templates/iiab-make-kiwix-lib b/roles/kiwix/templates/iiab-make-kiwix-lib index 083b87116..f945bf2a4 100644 --- a/roles/kiwix/templates/iiab-make-kiwix-lib +++ b/roles/kiwix/templates/iiab-make-kiwix-lib @@ -19,12 +19,18 @@ if flock -n -e 200; then : # write to {{ kiwix_library_xml }}.tmp to minimize kiwix down # zim map could be out of sync for a few seconds # using new version that does deltas - cp $KIWIXLIB $KIWIXLIB.tmp - /usr/bin/iiab-make-kiwix-lib.py - {{ systemctl_program }} stop kiwix-serve - rm $KIWIXLIB + if [ -f $KIWIXLIB ]; then + cp $KIWIXLIB $KIWIXLIB.tmp + /usr/bin/iiab-make-kiwix-lib.py + else + /usr/bin/iiab-make-kiwix-lib.py -f # force rebuild of library.xml + fi + /usr/bin/systemctl stop kiwix-serve + if [ -f $KIWIXLIB ]; then + rm $KIWIXLIB + fi mv $KIWIXLIB.tmp $KIWIXLIB - {{ systemctl_program }} start kiwix-serve + /usr/bin/systemctl start kiwix-serve else echo "Can't get wait lock for iiab-make-kiwix-lib.py"; exit 1; diff --git a/roles/kolibri/README.rst b/roles/kolibri/README.rst index 803ad433e..ff3777519 100644 --- a/roles/kolibri/README.rst +++ b/roles/kolibri/README.rst @@ -24,7 +24,7 @@ Please look in `/opt/iiab/iiab/roles/kolibri/defaults/main.yml `_) the installation will set up the following defaults:: +When kolibri_provision is enabled (e.g. in `/etc/iiab/local_vars.yml `_) the installation will set up the following defaults:: kolibri_facility: Kolibri-in-a-Box kolibri_language: en # See KOLIBRI_SUPPORTED_LANGUAGES at the bottom of https://github.com/learningequality/kolibri/blob/develop/kolibri/utils/i18n.py diff --git a/roles/kolibri/defaults/main.yml b/roles/kolibri/defaults/main.yml index 0354eb1c4..80eb0c352 100644 --- a/roles/kolibri/defaults/main.yml +++ b/roles/kolibri/defaults/main.yml @@ -3,11 +3,21 @@ # kolibri_language: en # See KOLIBRI_SUPPORTED_LANGUAGES at the bottom of https://github.com/learningequality/kolibri/blob/develop/kolibri/utils/i18n.py +# Kolibri folder to store its data and configuration files. +# kolibri_home: "{{ content_base }}/kolibri" # /library/kolibri + +# kolibri_user: kolibri # Whereas a vanilla install of Kolibri auto-identifies +# and saves a 'desktop-like' user like {iiab-admin, pi} to /etc/kolibri/username +# (generally the user with lowest UID >= 1000) to allow access to USB devices: +# https://kolibri.readthedocs.io/en/latest/install/ubuntu-debian.html#changing-the-owner-of-kolibri-system-service +# https://github.com/learningequality/kolibri-installer-debian/issues/115 + # kolibri_http_port: 8009 # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! + # 2019-09-27: Pinning to a particular version is unfortunately NOT supported # with our new apt approach (.deb installer) at this time. # 2019-06-21: Uncomment this pinning line if you want a particular version of @@ -16,7 +26,12 @@ # https://github.com/iiab/iiab/issues/1675 # https://github.com/learningequality/kolibri/issues/5664 -kolibri_deb_url: https://learningequality.org/r/kolibri-deb-latest +# 2024-04-08: Kolibri 0.16.1+ restores install via apt +# https://github.com/learningequality/kolibri/issues/11892#issuecomment-2043073998 +# 2022-07-30: UNCOMMENT ONE OF THE FOLLOWING LINES TO TEST A PARTICULAR .deb INSTALL +# kolibri_deb_url: https://learningequality.org/r/kolibri-deb-latest +# 2024-02-17: https://github.com/learningequality/kolibri/issues/11892 +# kolibri_deb_url: https://learningequality.org/r/kolibri-deb-next # 2019-11-21 issue #2045 - above URL had redirected to this broken Kolibri 0.12.9 release: # https://storage.googleapis.com/le-releases/downloads/kolibri/v0.12.9/kolibri_0.12.9-0ubuntu1_all.deb # @@ -29,19 +44,11 @@ kolibri_deb_url: https://learningequality.org/r/kolibri-deb-latest # Corresponding to: # https://launchpad.net/~learningequality/+archive/ubuntu/kolibri -# Kolibri folder to store its data and configuration files. -kolibri_home: "{{ content_base }}/kolibri" # /library/kolibri - kolibri_url_without_slash: /kolibri kolibri_url: "{{ kolibri_url_without_slash }}/" # /kolibri/ kolibri_exec_path: /usr/bin/kolibri -kolibri_user: kolibri # Whereas a vanilla install of Kolibri auto-identifies -# and saves a 'desktop' user like {iiab-admin, pi} to /etc/kolibri/username, -# towards guaranteeing access to USB devices, per: -# https://kolibri.readthedocs.io/en/latest/install.html#changing-the-owner-of-kolibri-system-service - # To populate /library/kolibri with essential/minimum files and dirs. This # provisions Kolibri with facility name, admin acnt / password, preset type, # and language. You can set this to 'False' when reinstalling Kolibri: diff --git a/roles/kolibri/tasks/nginx.yml b/roles/kolibri/tasks/enable-or-disable.yml similarity index 64% rename from roles/kolibri/tasks/nginx.yml rename to roles/kolibri/tasks/enable-or-disable.yml index 379339b68..8204b3aee 100644 --- a/roles/kolibri/tasks/nginx.yml +++ b/roles/kolibri/tasks/enable-or-disable.yml @@ -1,3 +1,19 @@ +- name: Enable & Start 'kolibri' systemd service, if kolibri_enabled + systemd: + name: kolibri + daemon_reload: yes + enabled: yes + state: started + when: kolibri_enabled + +- name: Disable & Stop 'kolibri' systemd service, if not kolibri_enabled + systemd: + name: kolibri + enabled: no + state: stopped + when: not kolibri_enabled + + - name: Enable http://box{{ kolibri_url }} via NGINX, by installing {{ nginx_conf_dir }}/kolibri-nginx.conf from template # http://box/kolibri template: src: kolibri-nginx.conf.j2 diff --git a/roles/kolibri/tasks/install.yml b/roles/kolibri/tasks/install.yml index 77ec7692e..d95f36044 100644 --- a/roles/kolibri/tasks/install.yml +++ b/roles/kolibri/tasks/install.yml @@ -1,13 +1,43 @@ +# 2022-09-08 @jredrejo's Ansible install scripts may provide guidelines: +# https://github.com/learningequality/pi-gen/blob/master/stage2/04-hostapd/common.yml +# https://github.com/learningequality/pi-gen/blob/master/stage2/04-hostapd/install.yml +# https://github.com/learningequality/pi-gen/blob/master/stage2/04-hostapd/offline.yml +# https://github.com/learningequality/pi-gen/blob/master/stage2/04-hostapd/online.yml + +# Install Kolibri Β» Debian/Ubuntu +# https://kolibri.readthedocs.io/en/latest/install/ubuntu-debian.html + +# Advanced management +# https://kolibri.readthedocs.io/en/latest/manage/advanced.html + +# Working with Kolibri from the command line +# https://kolibri.readthedocs.io/en/latest/manage/command_line.html + +# Customize Kolibri settings with the [ /library/kolibri/options.ini ] file +# https://kolibri.readthedocs.io/en/latest/manage/options_ini.html + +# Test Kolibri server performance +# https://kolibri.readthedocs.io/en/latest/manage/performance.html + +# Provisioning many servers +# https://kolibri.readthedocs.io/en/latest/install/provision.html + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Create Linux user {{ kolibri_user }} and add it to groups {{ apache_user }}, disk user: name: "{{ kolibri_user }}" - groups: - - "{{ apache_user }}" - - disk + groups: "{{ apache_user }}" # 2023-03-29: Not really necessary (Kolibri is demonstrated to work without group 'www-data'). But it likely doesn't hurt. + #- disk # 2023-03-29: Tested to be unnec with USB sticks (with 64-bit RasPiOS). FWIW group 'disk' is "Mostly equivalent to root access" according to https://wiki.debian.org/SystemGroups state: present shell: /bin/false system: yes create_home: no + home: "{{ kolibri_home }}" - name: Create directory {{ kolibri_home }} for Kolibri content, configuration, sqlite3 databases ({{ kolibri_user }}:{{ apache_user }}, by default 0755) file: @@ -31,12 +61,99 @@ content: 'KOLIBRI_HOME="{{ kolibri_home }}"' dest: /etc/kolibri/daemon.conf -- name: apt install latest Kolibri .deb from {{ kolibri_deb_url }} (populates {{ kolibri_home }}, migrates database) # i.e. /library/kolibri + +# https://kolibri.readthedocs.io/en/latest/install/ubuntu-debian.html claims: +# "When you use the PPA installation method, upgrades to newer versions +# will be automatic, provided there is internet access available." +# +# IN REALITY: apt upgrading Kolibri is messy, as up-to-5 debconf screens prompt +# PPL WHO DON'T KNOW with the wrong default username, instead of 'kolibri' :/ +# https://github.com/learningequality/kolibri-installer-debian/pull/117 + +# 2022-08-31: keyring /etc/apt/trusted.gpg DEPRECATED as detailed on #3343 +- name: Download Kolibri's apt key to /usr/share/keyrings/learningequality-kolibri.gpg + shell: | + gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys DC5BAA93F9E4AE4F0411F97C74F88ADB3194DD81 + gpg --yes --output /usr/share/keyrings/learningequality-kolibri.gpg --export DC5BAA93F9E4AE4F0411F97C74F88ADB3194DD81 + +# 2024-06-25: Strongly consider PPA "kolibri-proposed" in future... +# https://github.com/learningequality/kolibri/issues/11892 +# https://kolibri.readthedocs.io/en/latest/install/ubuntu-debian.html +- name: Add signed Kolibri PPA 'jammy' + apt_repository: + repo: "deb [signed-by=/usr/share/keyrings/learningequality-kolibri.gpg] http://ppa.launchpad.net/learningequality/kolibri/ubuntu jammy main" +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') or is_linuxmint_21 or is_debian_12 +# #when: is_ubuntu_2204 or is_ubuntu_2210 or is_debian_12 # MINT 21 COVERED BY is_ubuntu_2204 + +# - name: Add signed Kolibri PPA 'focal' (if other/older OS's) +# apt_repository: +# repo: "deb [signed-by=/usr/share/keyrings/learningequality-kolibri.gpg] http://ppa.launchpad.net/learningequality/kolibri/ubuntu focal main" +# when: not (is_ubuntu and os_ver is version('ubuntu-2204', '>=') or is_linuxmint_21 or is_debian_12) +# #when: not (is_ubuntu_2204 or is_ubuntu_2210 or is_debian_12) + +# - name: Add Kolibri PPA repo 'ppa:learningequality/kolibri' (if is_ubuntu and not is_linuxmint) +# apt_repository: +# repo: ppa:learningequality/kolibri +# when: is_ubuntu and not is_linuxmint + +# 2022-08-19: 'add-apt-repository ppa:learningequality/kolibri' works at CLI on +# Mint 21 (creating /etc/apt/sources.list.d/learningequality-kolibri-jammy.list) +# BUT equivalent Ansible command (STANZA ABOVE) failed with error... +# "Failed to update apt cache: E:The repository 'http://ppa.launchpad.net/learningequality/kolibri/ubuntu vanessa Release' does not have a Release file." +# ...so for now we special case Mint, similar to Debian (BOTH STANZAS BELOW!) + +# 2022-08-19: https://github.com/learningequality/kolibri/issues/9647 also asks +# about the warning below, arising no matter if codename is 'focal' or 'jammy' +# with Kolibri 0.15.6 on Mint 21 -- if you run '/usr/bin/kolibri --version': +# +# /usr/lib/python3/dist-packages/pkg_resources/__init__.py:116: PkgResourcesDeprecationWarning: 0.1.43ubuntu1 is an invalid version and will not be supported in a future release +# warnings.warn( + +# 2022-08-19: 'apt-key list' & 'apt-key del 3194 DD81' are useful if you also +# want to clear out Kolibri's key from the DEPRECATED /etc/apt/trusted.gpg + +# - name: Add Kolibri PPA repo 'ppa:learningequality/kolibri' with codename 'jammy' (if is_linuxmint_21) +# apt_repository: +# repo: ppa:learningequality/kolibri +# codename: jammy # CONSOLIDATE THIS SPECIAL CASE STANZA WITH UBUNTU ABOVE IN FUTURE? +# when: is_linuxmint_21 + +# - name: Add Kolibri PPA repo 'ppa:learningequality/kolibri' with codename 'focal' (if is_debian or is_linuxmint_20) +# apt_repository: +# repo: ppa:learningequality/kolibri +# codename: focal # UPDATE THIS TO 'jammy' AFTER "RasPiOS Bookworm" (based on Debian 12) IS RELEASED! (ETA Q3 2023) +# when: is_debian or is_linuxmint_20 + + +# 2024-08-07: Hack no longer needed! As Kolibri 0.17.0 now installs via "kolibri" PPA (https://launchpad.net/~learningequality/+archive/ubuntu/kolibri). +# Hopefully "kolibri-proposed" PPA will install 0.18 pre-releases soon, on Python 3.13 too! https://github.com/learningequality/kolibri/issues/11892 + +# - name: '2024-06-25 TEMPORARY HACK: Hard code kolibri_deb_url to Kolibri 0.17.x (pre-release or final release) if Python >= 3.12 -- kolibri-proposed PPA should do this automatically in future!' +# set_fact: +# kolibri_deb_url: https://github.com/learningequality/kolibri/releases/download/v0.17.0/kolibri_0.17.0-0ubuntu1_all.deb +# when: python_version is version('3.12', '>=') # For Ubuntu 24.04, Mint 22, pre-releases of Ubuntu 24.10, and Debian 13 (even if/when "Trixie" changes from Python 3.12 to 3.13!) Regarding PPA kolibri-proposed not quite being ready yet, see: learningequality/kolibri#11316 -> learningequality/kolibri#11892 + +- name: apt install kolibri (using apt source specified above, if kolibri_deb_url ISN'T defined) apt: - deb: "{{ kolibri_deb_url }}" # https://learningequality.org/r/kolibri-deb-latest - environment: - KOLIBRI_HOME: "{{ kolibri_home }}" # these don't do a thing for now but - KOLIBRI_USER: "{{ kolibri_user }}" # both can't hurt & Might Help Later + name: kolibri + when: kolibri_deb_url is undefined + # environment: + # KOLIBRI_HOME: "{{ kolibri_home }}" # 2023-03-27: These don't do a thing + # KOLIBRI_USER: "{{ kolibri_user }}" # for now. + +- name: apt install {{ kolibri_deb_url }} (if kolibri_deb_url IS defined) + apt: + deb: "{{ kolibri_deb_url }}" # e.g. https://learningequality.org/r/kolibri-deb-latest + when: kolibri_deb_url is defined + # environment: + # KOLIBRI_HOME: "{{ kolibri_home }}" # 2023-03-27: These don't do a thing + # KOLIBRI_USER: "{{ kolibri_user }}" # for now. + + +- name: Run 'rm -rf /root/.kolibri' to remove "unavoidable" pollution created above + file: + state: absent + path: /root/.kolibri - name: 'Install from template: /etc/systemd/system/kolibri.service' template: @@ -45,31 +162,35 @@ - name: Stop 'kolibri' systemd service, for Kolibri provisioning (after daemon_reload) systemd: - name: kolibri daemon_reload: yes + name: kolibri state: stopped # 2019-10-01: Should no longer be nec, thanks to /etc/kolibri/daemon.conf # containing KOLIBRI_HOME="/library/kolibri" (above) -#- name: Run Kolibri migrations to begin populating {{ kolibri_home }} # i.e. /library/kolibri -# shell: export KOLIBRI_HOME="{{ kolibri_home }}" && "{{ kolibri_exec_path }}" manage migrate -# ignore_errors: yes -# become: yes -# become_user: "{{ kolibri_user }}" -# when: kolibri_provision +# - name: Run Kolibri migrations to begin populating {{ kolibri_home }} # i.e. /library/kolibri +# shell: export KOLIBRI_HOME="{{ kolibri_home }}" && "{{ kolibri_exec_path }}" manage migrate +# ignore_errors: yes +# become: yes +# become_user: "{{ kolibri_user }}" +# when: kolibri_provision # 2020-01-05: Deprecated per https://github.com/iiab/iiab/issues/2103 -#- name: Set Kolibri default language ({{ kolibri_language }}) -# shell: export KOLIBRI_HOME="{{ kolibri_home }}" && "{{ kolibri_exec_path }}" language setdefault "{{ kolibri_language }}" -# ignore_errors: yes -# become: yes -# become_user: "{{ kolibri_user }}" -# when: kolibri_provision +# - name: Set Kolibri default language ({{ kolibri_language }}) +# shell: export KOLIBRI_HOME="{{ kolibri_home }}" && "{{ kolibri_exec_path }}" language setdefault "{{ kolibri_language }}" +# ignore_errors: yes +# become: yes +# become_user: "{{ kolibri_user }}" +# when: kolibri_provision +# Run "kolibri manage help provisiondevice" to see CLI options, e.g.: +# --facility_settings FACILITY_SETTINGS +# JSON file containing facility settings +# --device_settings DEVICE_SETTINGS +# JSON file containing device settings - name: 'Provision Kolibri, while setting: facility name, admin acnt / password, preset type, and language' shell: > - export KOLIBRI_HOME="{{ kolibri_home }}" && "{{ kolibri_exec_path }}" manage provisiondevice --facility "{{ kolibri_facility }}" --superusername "{{ kolibri_admin_user }}" --superuserpassword "{{ kolibri_admin_password }}" --preset "{{ kolibri_preset }}" --language_id "{{ kolibri_language }}" @@ -78,26 +199,44 @@ become: yes become_user: "{{ kolibri_user }}" when: kolibri_provision + environment: + KOLIBRI_HOME: "{{ kolibri_home }}" # 2023-03-27: Required! + #KOLIBRI_USER: "{{ kolibri_user }}" # 2023-03-27: Not nec due to /etc/kolibri/username ? -- name: chown -R {{ kolibri_user }}:{{ apache_user }} {{ kolibri_home }} for good measure? - file: - path: "{{ kolibri_home }}" # /library/kolibri - owner: "{{ kolibri_user }}" # kolibri - group: "{{ apache_user }}" # www-data (on Debian/Ubuntu/Raspbian) - recurse: yes - when: kolibri_provision +# 2023-03-25: Likely overkill (let's strongly consider removing this stanza?) +# Certainly, setting owner (recursively) is advised when moving /library/kolibri : +# https://kolibri.readthedocs.io/en/latest/install/ubuntu-debian.html#changing-the-owner-of-kolibri-system-service +# 2023-03-27: Commented out on a provisional basis (Spring Cleaning) +# - name: chown -R {{ kolibri_user }}:{{ apache_user }} {{ kolibri_home }} for good measure? +# file: +# path: "{{ kolibri_home }}" # /library/kolibri +# owner: "{{ kolibri_user }}" # kolibri +# group: "{{ apache_user }}" # www-data (on Debian/Ubuntu/Raspbian) +# recurse: yes +# when: kolibri_provision # 2019-10-07: Moved to roles/httpd/tasks/main.yml # 2019-09-29: roles/kiwix/tasks/kiwix_install.yml installs 4 Apache modules # for similar purposes (not all nec?) Only 1 (proxy_http) is needed here. -#- name: Enable Apache module proxy_http for http://box{{ kolibri_url }} # i.e. http://box/kolibri -# apache2_module: -# name: proxy_http +# - name: Enable Apache module proxy_http for http://box{{ kolibri_url }} # i.e. http://box/kolibri +# apache2_module: +# name: proxy_http # RECORD Kolibri AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'kolibri_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: kolibri + option: kolibri_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'kolibri_installed: True'" set_fact: kolibri_installed: True diff --git a/roles/kolibri/tasks/main.yml b/roles/kolibri/tasks/main.yml index aebecece9..1af098232 100644 --- a/roles/kolibri/tasks/main.yml +++ b/roles/kolibri/tasks/main.yml @@ -19,53 +19,46 @@ quiet: yes -#- name: "Set 'kolibri_provision: False' for a more lightweight (re)install" -# set_fact: -# kolibri_provision: False -# when: ??? +- block: -- name: Install Kolibri, if 'kolibri_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: kolibri_installed is undefined + #- name: "Set 'kolibri_provision: False' for a more lightweight (re)install" + # set_fact: + # kolibri_provision: False + # when: ??? + + - name: Install Kolibri, if 'kolibri_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: kolibri_installed is undefined -- name: Enable & Start 'kolibri' systemd service, if kolibri_enabled - systemd: - name: kolibri - daemon_reload: yes - enabled: yes - state: started - when: kolibri_enabled - -- name: Disable & Stop 'kolibri' systemd service, if not kolibri_enabled - systemd: - name: kolibri - enabled: no - state: stopped - when: not kolibri_enabled - -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + - include_tasks: enable-or-disable.yml -- name: Add 'kolibri' variable values to {{ iiab_ini_file }} # /etc/iiab/iiab.ini - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: kolibri - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Kolibri - - option: description - value: '"Kolibri is an open-source educational platform specially designed to provide offline access to a wide range of quality, openly licensed educational contents in low-resource contexts like rural schools, refugee camps, orphanages, and also in non-formal school programs."' - - option: kolibri_install - value: "{{ kolibri_install }}" - - option: kolibri_enabled - value: "{{ kolibri_enabled }}" - - option: kolibri_url - value: "{{ kolibri_url }}" - - option: kolibri_path - value: "{{ kolibri_exec_path }}" - - option: kolibri_port - value: "{{ kolibri_http_port }}" + - name: Add 'kolibri' variable values to {{ iiab_ini_file }} # /etc/iiab/iiab.ini + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: kolibri + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Kolibri + - option: description + value: '"Kolibri is an open-source educational platform specially designed to provide offline access to a wide range of quality, openly licensed educational contents in low-resource contexts like rural schools, refugee camps, orphanages, and also in non-formal school programs."' + - option: kolibri_install + value: "{{ kolibri_install }}" + - option: kolibri_enabled + value: "{{ kolibri_enabled }}" + - option: kolibri_url + value: "{{ kolibri_url }}" + - option: kolibri_path + value: "{{ kolibri_exec_path }}" + - option: kolibri_port + value: "{{ kolibri_http_port }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/kolibri/templates/kolibri.service.j2 b/roles/kolibri/templates/kolibri.service.j2 index a886aa73e..21d7631b9 100644 --- a/roles/kolibri/templates/kolibri.service.j2 +++ b/roles/kolibri/templates/kolibri.service.j2 @@ -10,7 +10,7 @@ Environment=KOLIBRI_HTTP_PORT={{ kolibri_http_port }} Environment=KOLIBRI_URL_PATH_PREFIX={{ kolibri_url_without_slash }} User={{ kolibri_user }} Group={{ apache_user }} -# 2020-10-03: Kolibri was timing out on RaspiOS & Ubuntu 20 NUC: iiab/iiab#2555 +# 2020-10-03: Kolibri was timing out on RasPiOS & Ubuntu 20 NUC: iiab/iiab#2555 TimeoutStartSec=1200 # The following is the systemd default, which is too much for most teachers in # low-electricity environments (30-60 sec is about all they can handle before diff --git a/roles/lokole/README.rst b/roles/lokole/README.rst index cb9ebc8d7..53add2239 100644 --- a/roles/lokole/README.rst +++ b/roles/lokole/README.rst @@ -17,9 +17,9 @@ For an up-to-date list of supported languages, refer to the `Lokole translations Using It -------- -If your IIAB was `installed `_ with the Lokole web app[*] it can be accessed at http://box/lokole +If your IIAB was `installed `_ with the Lokole web app[*] it can be accessed at http://box/lokole -[*] If you're not sure, verify that your IIAB's `/etc/iiab/local_vars.yml `_ contains ``lokole_install: True`` and ``lokole_enabled: True`` +[*] If you're not sure, verify that your IIAB's `/etc/iiab/local_vars.yml `_ contains ``lokole_install: True`` and ``lokole_enabled: True`` By default in an offline community, ``lokole_sim_type: LocalOnly`` is set (e.g. instead of ``lokole_sim_type: Ethernet``) and email addresses will look like: @@ -85,7 +85,7 @@ The Lokole software can be configured to access the Internet via USB modem, SIM If configured to work with a USB modem or other form of Internet connection, Lokole will sync with the cloud server (operated by `Ascoderu `_) on a nightly basis to deliver and receive emails globally. *However, arranging this is extremely complicated.* You would need a compatible form of connection and an Internet expert familiar with modem protocols, MX records, etc. Ask that person to read the `Lokole software README `_ in its entirety, to help you understand whether this is realistic for your organization. -Lokole and Internet-in-a-Box would welcome a business plan (whether volunteer-based, grant-based or for-profit) from someone willing to operationalize this β€” making it relatively hassle-free for schools, clinics, libraries and orphanages around the world β€” that generally do not have access to technical experts. Please `contact us `_ if you have the capacity to help make such a social enterprise happen. +Lokole and Internet-in-a-Box would welcome a business plan (whether volunteer-based, grant-based or for-profit) from someone willing to operationalize this β€” making it relatively hassle-free for schools, clinics, libraries and orphanages around the world β€” that generally do not have access to technical experts. Please `contact us `_ if you have the capacity to help make such a social enterprise happen. Troubleshooting --------------- @@ -95,4 +95,4 @@ For further usage information and troubleshooting, refer to the `Lokole user man Known Issues ------------ -For an up-to-date list of open issues, please see the `Lokole project's issue tracker `_. See also `IIAB's issue tracker `_. +For an up-to-date list of open issues, please see the `Lokole project's issue tracker `_. See also `IIAB's issue tracker `_. diff --git a/roles/lokole/defaults/main.yml b/roles/lokole/defaults/main.yml index b8f4d030f..f5c283cae 100644 --- a/roles/lokole/defaults/main.yml +++ b/roles/lokole/defaults/main.yml @@ -14,6 +14,7 @@ # https://pypi.org/project/opwen-email-client/ ...OR... HARDCODE EITHER HERE: #lokole_commit: # OPTIONAL: a 40-char git hash, from https://github.com/ascoderu/lokole/commits/master #lokole_version: # OPTIONAL: e.g. master or 0.5.10 or a version number from https://pypi.org/project/opwen-email-client/#history +lokole_repo: https://github.com/ascoderu/lokole.git # the lokole git repo location to pull from if lokole_commit is defined lokole_admin_user: admin # lowercase is nec here (even though uppercase Admin/changeme is IIAB's OOB recommendation: BOTH WORK to log in to http://box/lokole) lokole_admin_password: changeme diff --git a/roles/lokole/tasks/install.yml b/roles/lokole/tasks/install.yml index 04098dce7..a002268fc 100644 --- a/roles/lokole/tasks/install.yml +++ b/roles/lokole/tasks/install.yml @@ -2,12 +2,16 @@ # https://github.com/iiab/iiab/blob/master/roles/www_base/templates/iiab-refresh-wiki-docs.sh#L51-L52 -- name: "Install 8 packages for Lokole: python3, python3-pip, python3-venv, python3-dev, python3-bcrypt, libffi-dev, libssl-dev, libopenjp2-7" +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: Install 12 packages for Lokole apt: name: - - python3 - - python3-pip - - python3-venv + #- python3 # 2022-12-21: IIAB pre-req, see scripts/local_facts.fact + #- python3-pip - python3-dev - python3-bcrypt # 2019-10-14: Should work across modern Linux OS's #- bcrypt does not exist on Ubuntu 19.10 @@ -23,15 +27,16 @@ - wvdial state: present + # For development purposes -- To install Lokole from a given commit, add the # following line to roles/lokole/defaults/main.yml: # lokole_commit: - name: "OPTIONAL: pip install opwen_email_client (Lokole, git commit {{ lokole_commit }}) from GitHub to {{ lokole_venv }}, if lokole_commit is defined" pip: - name: "git+https://github.com/ascoderu/lokole.git@{{ lokole_commit }}#egg=opwen_email_client" + name: "git+{{ lokole_repo }}@{{ lokole_commit }}#egg=opwen_email_client" virtualenv: "{{ lokole_venv }}" virtualenv_command: python3 -m venv "{{ lokole_venv }}" - extra_args: --no-cache-dir # To avoid caching issues e.g. soon after new releases hit https://pypi.org/project/opwen-email-client/ + extra_args: --no-cache-dir --force-reinstall # To avoid caching issues e.g. soon after new releases hit https://pypi.org/project/opwen-email-client/ when: lokole_commit is defined # For development purposes -- To install a given pip version of Lokole, add @@ -54,12 +59,19 @@ extra_args: --no-cache-dir # To avoid caching issues e.g. soon after new releases hit https://pypi.org/project/opwen-email-client/ when: lokole_commit is undefined and lokole_version is undefined -- name: Compile translations +# - name: Compile translations +# shell: | +# python_version=$(python3 -c 'from sys import version_info; print("%s.%s" % (version_info.major, version_info.minor));';) +# {{ lokole_venv }}/bin/pybabel compile -d {{ item }}/translations +# with_items: +# - "{{ lokole_venv }}/lib/python${python_version}/site-packages/opwen_email_client/webapp" + +# 2022-12-21: python_version determined by scripts/local_facts.fact -- to match templates/lokole-nginx.conf.j2 +- name: Compile translations for Python {{ python_version }} shell: | - python_version=$(python3 -c 'from sys import version_info; print("%s.%s" % (version_info.major, version_info.minor));';) {{ lokole_venv }}/bin/pybabel compile -d {{ item }}/translations with_items: - - "{{ lokole_venv }}/lib/python${python_version}/site-packages/opwen_email_client/webapp" + - "{{ lokole_venv }}/lib/python{{ python_version }}/site-packages/opwen_email_client/webapp" - name: Create system {{ lokole_user }} user ansible.builtin.user: @@ -126,6 +138,17 @@ # RECORD Lokole AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'lokole_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: lokole + option: lokole_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'lokole_installed: True'" set_fact: lokole_installed: True diff --git a/roles/lokole/tasks/main.yml b/roles/lokole/tasks/main.yml index 5d4bdc72b..45d47d129 100644 --- a/roles/lokole/tasks/main.yml +++ b/roles/lokole/tasks/main.yml @@ -19,53 +19,62 @@ quiet: yes -- name: Install Lokole if lokole_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: lokole_installed is undefined +- block: + + - name: Install Lokole if lokole_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: lokole_installed is undefined -- name: Do a 'systemctl daemon-reload' - systemd: - daemon_reload: yes - when: lokole_enabled + - name: Do a 'systemctl daemon-reload' + systemd: + daemon_reload: yes + when: lokole_enabled -- name: Enable & Restart supervisor systemd service, if lokole_enabled - systemd: - name: supervisor - enabled: yes - state: restarted - when: lokole_enabled + - name: Enable & Restart supervisor systemd service, if lokole_enabled + systemd: + name: supervisor + enabled: yes + state: restarted + when: lokole_enabled -- name: Disable & Stop supervisor systemd service, if not lokole_enabled - systemd: - name: supervisor - enabled: no - state: stopped - when: not lokole_enabled + - name: Disable & Stop supervisor systemd service, if not lokole_enabled + systemd: + name: supervisor + enabled: no + state: stopped + when: not lokole_enabled -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + - name: Enable/Disable/Restart NGINX + include_tasks: nginx.yml -- name: Add 'lokole' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab_state.yml - section: lokole - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Lokole - - option: description - value: '"Lokole is an email service that works offline, for rural communities. With a 3G/4G modem, you can arrange to batch-upload / batch-download emails once per night -- for almost no cost at all -- depending on mobile data plans in your country."' - #value: '"Lokole is an email service that works offline, for rural communities. In some cases, emails can also be transmitted to/from the Internet, taking advantage of discounted mobile data rates."' - - option: lokole_install - value: "{{ lokole_install }}" - - option: lokole_enabled - value: "{{ lokole_enabled }}" - - option: lokole_settings - value: "{{ lokole_settings }}" - - option: lokole_url - value: "{{ lokole_url }}" - - option: lokole_full_url - value: "{{ lokole_full_url }}" + - name: Add 'lokole' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: lokole + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Lokole + - option: description + value: '"Lokole is an email service that works offline, for rural communities. With a 3G/4G modem, you can arrange to batch-upload / batch-download emails once per night -- for almost no cost at all -- depending on mobile data plans in your country."' + #value: '"Lokole is an email service that works offline, for rural communities. In some cases, emails can also be transmitted to/from the Internet, taking advantage of discounted mobile data rates."' + - option: lokole_install + value: "{{ lokole_install }}" + - option: lokole_enabled + value: "{{ lokole_enabled }}" + - option: lokole_settings + value: "{{ lokole_settings }}" + - option: lokole_url + value: "{{ lokole_url }}" + - option: lokole_full_url + value: "{{ lokole_full_url }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/lokole/tasks/setup.yml b/roles/lokole/tasks/setup.yml index 1f49661c6..58a5ec716 100644 --- a/roles/lokole/tasks/setup.yml +++ b/roles/lokole/tasks/setup.yml @@ -3,10 +3,13 @@ name: supervisor state: started +# 2022-12-21: python_version determined by scripts/local_facts.fact -- to match templates/lokole-nginx.conf.j2 - name: Create Lokole admin user with password, for http://box{{ lokole_url }} # http://box/lokole shell: | while read envvar; do export "$envvar"; done < {{ lokole_run_dir }}/settings.env - {{ lokole_venv }}/bin/manage.py createadmin --name='{{ lokole_admin_user }}' --password='{{ lokole_admin_password }}' + cd {{ lokole_venv }}/lib/python{{ python_version }}/site-packages/ + export FLASK_APP="opwen_email_client.webapp:app" + {{ lokole_venv }}/bin/flask manage createadmin --name='{{ lokole_admin_user }}' --password='{{ lokole_admin_password }}' - name: Change owner of dbfiles file: diff --git a/roles/lokole/templates/lokole-nginx.conf.j2 b/roles/lokole/templates/lokole-nginx.conf.j2 index a2084a160..002961fcf 100644 --- a/roles/lokole/templates/lokole-nginx.conf.j2 +++ b/roles/lokole/templates/lokole-nginx.conf.j2 @@ -1,9 +1,9 @@ location = {{ lokole_url }}/favicon.ico { - alias {{ lokole_venv }}/lib/python{{ python_ver }}/site-packages/opwen_email_client/webapp/static/favicon.ico; + alias {{ lokole_venv }}/lib/python{{ python_version }}/site-packages/opwen_email_client/webapp/static/favicon.ico; } location ~ ^{{ lokole_url }}/static/(.*)$ { - alias {{ lokole_venv }}/lib/python{{ python_ver }}/site-packages/opwen_email_client/webapp/static/$1; + alias {{ lokole_venv }}/lib/python{{ python_version }}/site-packages/opwen_email_client/webapp/static/$1; } location {{ lokole_url }}/ { diff --git a/roles/lokole/templates/lokole_restarter.conf b/roles/lokole/templates/lokole_restarter.conf index 94f580e9c..ab0118625 100644 --- a/roles/lokole/templates/lokole_restarter.conf +++ b/roles/lokole/templates/lokole_restarter.conf @@ -1,5 +1,5 @@ [program:lokole_restarter] -command={{ lokole_venv }}/bin/manage.py restarter --directory={{ lokole_run_dir }}/lokole_restarter +command={{ lokole_venv }}/bin/flask manage restarter --directory={{ lokole_run_dir }}/lokole_restarter autostart=true autorestart=true startretries=3 @@ -7,4 +7,4 @@ stopasgroup=true stderr_logfile={{ lokole_log_dir }}/lokole_restarter.stderr.log stdout_logfile={{ lokole_log_dir }}/lokole_restarter.stdout.log user=root -environment=OPWEN_SETTINGS={{ lokole_settings }} +environment=FLASK_APP="opwen_email_client.webapp",OPWEN_SETTINGS={{ lokole_settings }} diff --git a/roles/matomo/README.adoc b/roles/matomo/README.adoc new file mode 100644 index 000000000..88a558407 --- /dev/null +++ b/roles/matomo/README.adoc @@ -0,0 +1,66 @@ += Matomo README + +https://matomo.org/[Matomo] is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership, that you can use with https://internet-in-a-box.org[Internet-in-a-Box] (IIAB). + +== Install it + +Prior to installing Matomo with IIAB, the default URL (http://box.lan/matomo) can be customized in https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F[/etc/iiab/local_vars.yml] + +One way to do that is by changing these 2 lines: + +---- +iiab_hostname: box +iiab_domain: lan +---- + +Or, you can change the Matomo URL by putting your IIAB IP Address in a line like: + +---- +matomo_host_url: http://192.168.0.199 +---- + +Either way, consider setting a Matomo username and password using lines like: + +---- +matomo_db_user: Admin +matomo_db_pass: changeme +---- + +Also ensure that your `/etc/iiab/local_vars.yml` contains these lines: + +---- +matomo_install: True +matomo_enabled: True +---- + +_Finally, continue to https://download.iiab.io[install IIAB], e.g. by running `sudo iiab`, until software installation is complete._ + +== Use it + +Log in to your IIAB's full Matomo URL, e.g. http://box.lan/matomo, as arranged above. + +Take a look at Matomo's official guides to further set this up: https://matomo.org/guides/ + + +WARNING: Matomo won't show any traffic statistics until after 1 day or reboot (which are the events that trigger the log scraper!) + +=== Getting Started + +Matomo is developed with commercial websites in mind. After navigating to http://box.lan/matomo and logging in with the username and password you set above, you will see a variety of references to revenue, marketplaces, and other terms focused on commercialization and advertising. Don't worry about that. + +The heart of Matomo's value for you is in the navigation bar on the left side of the page. Click on *Visitors* and then below *Visitors*, *Overview*, to see how many different users are visiting your site. The top of the page will show a graph of how many visits occur on each day (although your device may not keep track of time when it is off and has no connection to the Internet, so this graph might not be perfectly accurate). Below the graph, you'll see some overall statistics, like how many unique visitors you've had. Matomo thinks of visitors in terms of devices, so it won't know if two people are connecting to your Internet-in-a-Box using the same phone. There are several other interesting statistics here, like the average visit duration, or average time your visitors are spending using Internet-in-a-Box. + +Below the *Visitors* button is a second button, *Behavior*. Click on the *Pages* button after clicking *Behavior* and you can see the various pages that have been visited by your users. You may not see activity from the most recent day, since Matomo only updates its records once per day. + +=== IIAB Tips, Tricks, and Gotchas + +1. If your Internet-in-a-Box setup is without power and Internet access, it may not be able to keep time correctly. This is okay! But it means that the time-of-visit information in Matomo will not be correct. + +2. One thing Matomo can't track correctly is navigation within KA Lite (Khan Academy) pages. If your users are spending a lot of time here, it won't be visible in the Matomo statistics. + +3. Time Zones: The Matomo installer's default behavior in "Configure Matomo to track IIAB" is to pick up the system time zone when none is supplied. If this doesn't work, you can set the time zone to whatever you prefer from the Matomo home page. In testing, Matomo picked up the system time zone on a regular Multipass Ubuntu instance. However, it was unable to do so on a VirtualBox Ubuntu instance. Thus, we provide a fallback behavior "Fallback Configure Matomo to track IIAB" that picks an arbitrary time zone. The fallback fires only when the form with an empty time zone is submitted and returns a 200 status code instead of 302, indicating that form submission failed. + + +== Credits + +Carl Wivagg diff --git a/roles/matomo/defaults/main.yml b/roles/matomo/defaults/main.yml new file mode 100644 index 000000000..cf332c0e1 --- /dev/null +++ b/roles/matomo/defaults/main.yml @@ -0,0 +1,18 @@ +# matomo_install: True +# matomo_enabled: True + +# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml +# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! + +matomo_dl_url: https://builds.matomo.org/matomo.tar.gz +matomo_path: "{{ doc_base }}" # e.g. /library/www + +matomo_db_name: matomodb +matomo_db_user: Admin +matomo_db_pass: changeme + +#matomo_host_url: http://{{ ansible_default_ipv4.address }} +matomo_host_url: http://{{ iiab_hostname }}.{{ iiab_domain }} # e.g. http://box.lan +matomo_full_url: "{{ matomo_host_url }}/matomo/" + +matomo_cronjob: "sudo python3 {{ matomo_path }}/matomo/misc/log-analytics/import_logs.py --url={{ matomo_full_url }} --idsite=1 --recorders=4 --enable-http-errors --enable-http-redirects --enable-static --enable-bots /var/log/nginx/access.log" diff --git a/roles/matomo/tasks/install.yml b/roles/matomo/tasks/install.yml new file mode 100644 index 000000000..7de697f49 --- /dev/null +++ b/roles/matomo/tasks/install.yml @@ -0,0 +1,281 @@ +# The sections of code interacting with the Matomo website are modified from code found at https://git.coop/webarch/matomo/. This code is distributed under +# Version 3 of the GNU General Public License. We modified this code and applied it here in April 2022. The derived sections correspond to the tasks running +# from "HTTP Get Welcome" through "Finish Matomo Setup", lines 63 through 199. + + +- name: "WARNING: './runrole --reinstall matomo' CAN FAIL AS OF 2022-06-15, e.g. if /library/www/matomo already exists" + meta: noop + +# EXAMPLE OF ABOVE ERROR: + +# TASK [matomo : HTTP Get Welcome] *************************************************************************************************************************************** +# fatal: [127.0.0.1]: FAILED! => {"cache_control": "private, no-cache, no-store", "changed": false, "connection": "close", "content_type": "text/html; charset=utf-8", "date": "Wed, 15 Jun 2022 05:07:41 GMT", "elapsed": 0, "expires": "Thu, 19 Nov 1981 08:52:00 GMT", "msg": "Status code was 500 and not [200]: HTTP Error 500: Internal Server Error", "pragma": "no-cache", "redirected": false, "server": "nginx/1.18.0 (Ubuntu)", "set_cookie": "MATOMO_SESSID=psak3aem27vrdrt8t2f016600f; path=/; HttpOnly; SameSite=Lax", "status": 500, "transfer_encoding": "chunked", "url": "http://box.lan/matomo/index.php?action=welcome", "x_matomo_request_id": "fbfd2"} + + +- name: "Set 'mysql_install: True' and 'mysql_enabled: True'" + set_fact: + mysql_install: True + mysql_enabled: True + +- name: MYSQL - run 'mysql' role (attempt to install & enable MySQL / MariaDB) + include_role: + name: mysql + +- name: FAIL (STOP THE INSTALL) IF 'mysql_installed is undefined' + fail: + msg: "Matomo install cannot proceed, as MySQL / MariaDB is not installed." + when: mysql_installed is undefined + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# https://matomo.org/faq/on-premise/matomo-requirements/ +- name: Install Matomo's recommended PHP extensions + package: + name: + - php{{ php_version }}-curl + - php{{ php_version }}-gd + - php{{ php_version }}-cli + - php{{ php_version }}-mysql + - php{{ php_version }}-xml + - php{{ php_version }}-mbstring + +- name: "Run roles/www_options/tasks/php-settings.yml with 'nginx_high_php_limits: False' by default" + include_tasks: roles/www_options/tasks/php-settings.yml + when: php_settings_done is undefined + + +- name: Start MariaDB + #action: service name=mysql state=started + systemd: + name: "{{ mysql_service }}" + state: started + +- name: Create MariaDB Database for Matomo + community.mysql.mysql_db: + name: "{{ matomo_db_name }}" + #login_unix_socket: /var/run/mysqld/mysqld.sock + +- name: Add Admin User to MariaDB Database + community.mysql.mysql_user: + name: "{{ matomo_db_user }}" + password: "{{ matomo_db_pass }}" + update_password: on_create # OR SHOULD './runrole --reinstall matomo' FORCE A COMPLETELY CLEAN INSTALL? + priv: "{{ matomo_db_name }}.*:ALL" + #login_unix_socket: /var/run/mysqld/mysqld.sock + +- name: Download and Extract Matomo (~3 min) + unarchive: + src: "{{ matomo_dl_url }}" # e.g. https://builds.matomo.org/matomo.tar.gz + dest: "{{ matomo_path }}" # e.g. /library/www + remote_src: yes + +- name: Set Matomo Directory Permissions + file: + path: "{{ matomo_path }}/matomo" + recurse: yes + owner: "{{ apache_user }}" # e.g. www-data + group: "{{ apache_user }}" + +- name: HTTP Get Welcome + uri: + url: "{{ matomo_full_url }}index.php?action=welcome" # e.g. http://box.lan/matomo + method: GET + status_code: 200 + register: matomo_welcome + +- debug: + var: matomo_welcome + +- name: Set a variable for the MATOMO_SESSID cookie + set_fact: + matomo_session_cookie: "MATOMO_SESSID={{ cookie.value }}" + when: cookie.key == "MATOMO_SESSID" + loop: "{{ matomo_welcome.cookies | dict2items }}" + loop_control: + loop_var: cookie + +- name: Get Matomo System Check + uri: + url: "{{ matomo_full_url }}index.php?action=systemCheck" + method: GET + headers: + Cookie: "{{ matomo_session_cookie }}" + return_content: true + timeout: 120 + status_code: 200 + register: matomo_system_check + +- debug: + var: matomo_system_check + +- name: Matomo Database Setup + uri: + url: "{{ matomo_full_url }}index.php?action=databaseSetup" + method: POST + headers: + Cookie: "{{ matomo_session_cookie }}" + body: + username: "{{ matomo_db_user }}" + password: "{{ matomo_db_pass }}" + dbname: "{{ matomo_db_name }}" + tables_prefix: "matomo_" + adapter: "PDO\\MYSQL" + body_format: form-urlencoded + status_code: 302 + #register: matomo_database_setup + +- name: Matomo Table Creation + uri: + url: "{{ matomo_full_url }}index.php?action=tablesCreation&module=Installation" + method: GET + status_code: 200 + register: matomo_table_creation + +- name: Set a variable for the MATOMO_SESSID cookie + set_fact: + matomo_session_cookie: "MATOMO_SESSID={{ cookie.value }}" + when: + - matomo_table_creation.cookies is defined + - matomo_table_creation.cookies | length > 0 + - cookie.key == "MATOMO_SESSID" + loop: "{{ matomo_table_creation.cookies | dict2items }}" + loop_control: + loop_var: cookie + +- debug: + var: matomo_table_creation + +- name: Matomo User Setup + uri: + url: "{{ matomo_full_url }}index.php?action=setupSuperUser&module=Installation" + method: POST + headers: + Cookie: "{{ matomo_session_cookie }}" + body: + login: "{{ matomo_db_user }}" + password: "{{ matomo_db_pass }}" + password_bis: "{{ matomo_db_pass }}" + email: "nobody@dev.null" + subscribe_newsletter_piwikorg: 0 + subscribe_newsletter_professionalservices: 0 + body_format: form-urlencoded + status_code: 302 + #register: matomo_setup_superuser + +- name: Configure Matomo to track IIAB + uri: + url: "{{ matomo_full_url }}index.php?action=firstWebsiteSetup&module=Installation" + method: POST + headers: + Cookie: "{{ matomo_session_cookie }}" + body: + siteName: "IIAB" + url: "{{ matomo_host_url }}" + ecommerce: 0 + body_format: form-urlencoded + status_code: [200, 302] + register: _result + +- name: Fallback Configure Matomo to track IIAB + uri: + url: "{{ matomo_full_url }}index.php?action=firstWebsiteSetup&module=Installation" + method: POST + headers: + Cookie: "{{ matomo_session_cookie }}" + body: + siteName: "IIAB" + url: "{{ matomo_host_url }}" + timezone: "Europe/London" + ecommerce: 0 + body_format: form-urlencoded + status_code: 302 + when: _result.status == 200 + +- name: Matomo Tracking Code + uri: + url: "{{ matomo_full_url }}index.php?action=trackingCode&module=Installation&site_idSite=1&site_name={{ matomo_host_url }}" + method: GET + headers: + Cookie: "{{ matomo_session_cookie }}" + return_content: true + status_code: 200 + #register: matomo_tracking_code + +- name: Finish Matomo Setup + uri: + url: "{{ matomo_full_url }}index.php?action=finished&module=Installation" + method: POST + headers: + Cookie: "{{ matomo_session_cookie }}" + body: + do_not_track: 1 + anonymise_ip: 1 + submit: "Continue to Matomo" + body_format: form-urlencoded + status_code: 302 + +- name: Start Collecting Matomo Data + cron: + name: "MatomoDataIngestionOnReboot" + special_time: reboot + job: "{{ matomo_cronjob }}" + user: root + cron_file: "matomo_reboot" + +- name: Run Daily Job Collecting Matomo Data + cron: + name: "DailyMatomoDataIngestion" + minute: "0" + hour: "0" + job: "{{ matomo_cronjob }}" + user: root + cron_file: "matomo_daily" + +- name: Set Permissions for token.php + copy: + content: "" + dest: "{{ matomo_path }}/matomo/tmp/cache/token.php" + group: "{{ apache_user }}" + owner: "{{ apache_user }}" + +- name: Set Permissions for tracker Directory + file: + path: "{{ matomo_path }}/matomo/tmp/cache/tracker" + state: directory + owner: "{{ apache_user }}" + group: "{{ apache_user }}" + +- name: Don't Check for Trusted Host + ini_file: + path: "{{ matomo_path }}/matomo/config/config.ini.php" + section: General + option: enable_trusted_host_check + value: 0 + + +# RECORD Matomo AS INSTALLED + +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'matomo_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: matomo + option: matomo_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + +- name: "Set 'matomo_installed: True'" + set_fact: + matomo_installed: True + +- name: "Add 'matomo_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^matomo_installed' + line: 'matomo_installed: True' diff --git a/roles/matomo/tasks/main.yml b/roles/matomo/tasks/main.yml new file mode 100644 index 000000000..b99de06e7 --- /dev/null +++ b/roles/matomo/tasks/main.yml @@ -0,0 +1,55 @@ +# "How do i fail a task in Ansible if the variable contains a boolean value? +# I want to perform input validation for Ansible playbooks" +# https://stackoverflow.com/questions/46664127/how-do-i-fail-a-task-in-ansible-if-the-variable-contains-a-boolean-value-i-want/46667499#46667499 + +# We assume 0-init/tasks/validate_vars.yml has DEFINITELY been run, so no need +# to re-check whether vars are defined here. As Ansible vars cannot be unset: +# https://serverfault.com/questions/856729/how-to-destroy-delete-unset-a-variable-value-in-ansible + +- name: Assert that "matomo_install is sameas true" (boolean not string etc) + assert: + that: matomo_install is sameas true + fail_msg: "PLEASE SET 'matomo_install: True' e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + +- name: Assert that "matomo_enabled | type_debug == 'bool'" (boolean not string etc) + assert: + that: matomo_enabled | type_debug == 'bool' + fail_msg: "PLEASE GIVE VARIABLE 'matomo_enabled' A PROPER (UNQUOTED) ANSIBLE BOOLEAN VALUE e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + + +- block: + + - name: Enable/Disable/Reload NGINX for Matomo + include_tasks: nginx.yml + + - name: Install Matomo if 'matomo_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: matomo_installed is undefined + + # LET'S ADD THIS "ON/OFF SWITCH" IF POSS! + # - include_tasks: enable-or-disable.yml + + - name: Add 'matomo' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: matomo + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Matomo + - option: description + value: '"Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership."' + - option: matomo_install + value: "{{ matomo_install }}" + - option: matomo_enabled + value: "{{ matomo_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/matomo/tasks/nginx.yml b/roles/matomo/tasks/nginx.yml new file mode 100644 index 000000000..46465dffb --- /dev/null +++ b/roles/matomo/tasks/nginx.yml @@ -0,0 +1,16 @@ +- name: Enable http://box/matomo via NGINX, by installing {{ nginx_conf_dir }}/matomo-nginx.conf from template + template: + src: matomo-nginx.conf.j2 + dest: "{{ nginx_conf_dir }}/matomo-nginx.conf" # /etc/nginx/conf.d + when: matomo_enabled + +- name: Disable http://box/matomo via NGINX, by removing {{ nginx_conf_dir }}/matomo-nginx.conf + file: + path: "{{ nginx_conf_dir }}/matomo-nginx.conf" # /etc/nginx/conf.d + state: absent + when: not matomo_enabled + +- name: Reload 'nginx' systemd service + systemd: + name: nginx + state: reloaded diff --git a/roles/matomo/templates/matomo-nginx.conf.j2 b/roles/matomo/templates/matomo-nginx.conf.j2 new file mode 100644 index 000000000..a5fdce030 --- /dev/null +++ b/roles/matomo/templates/matomo-nginx.conf.j2 @@ -0,0 +1,19 @@ +location ~ ^/matomo/(config|tmp|core|lang) { deny all; return 403; } + +location ~ ^/matomo(.*)\.php(.*)$ { + alias /library/www/matomo$1.php$2; # /library/www/matomo + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + fastcgi_pass php; + fastcgi_index index.html; + include fastcgi_params; + fastcgi_split_path_info ^(.+\.php)(.*)$; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_param PATH_INFO $2; +} + +location ~ ^/matomo(/)? { + root /library/www; +} diff --git a/roles/mediawiki/defaults/main.yml b/roles/mediawiki/defaults/main.yml index 93259de73..5c37610af 100644 --- a/roles/mediawiki/defaults/main.yml +++ b/roles/mediawiki/defaults/main.yml @@ -4,8 +4,8 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -mediawiki_major_version: 1.37 # "1.35" also works -mediawiki_minor_version: 1 +mediawiki_major_version: "1.43" # "1.40" quotes nec if trailing zero +mediawiki_minor_version: 0 mediawiki_version: "{{ mediawiki_major_version }}.{{ mediawiki_minor_version }}" mediawiki_download_base_url: "https://releases.wikimedia.org/mediawiki/{{ mediawiki_major_version }}" diff --git a/roles/mediawiki/tasks/install.yml b/roles/mediawiki/tasks/install.yml index 145c1dc3d..e89afdcd9 100644 --- a/roles/mediawiki/tasks/install.yml +++ b/roles/mediawiki/tasks/install.yml @@ -1,3 +1,23 @@ +- name: "Set 'mysql_install: True' and 'mysql_enabled: True'" + set_fact: + mysql_install: True + mysql_enabled: True + +- name: MYSQL - run 'mysql' role (attempt to install & enable MySQL / MariaDB) + include_role: + name: mysql + +- name: FAIL (STOP THE INSTALL) IF 'mysql_installed is undefined' + fail: + msg: "MediaWiki install cannot proceed, as MySQL / MariaDB is not installed." + when: mysql_installed is undefined + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # https://www.mediawiki.org/wiki/Manual:Installation_requirements#PHP - name: 'Install packages: php{{ php_version }}-intl, php{{ php_version }}-mbstring, php{{ php_version }}-xml' package: @@ -95,6 +115,17 @@ # RECORD MediaWiki AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'mediawiki_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mediawiki + option: mediawiki_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'mediawiki_installed: True'" set_fact: mediawiki_installed: True diff --git a/roles/mediawiki/tasks/main.yml b/roles/mediawiki/tasks/main.yml index 2318a886d..1a0318e06 100644 --- a/roles/mediawiki/tasks/main.yml +++ b/roles/mediawiki/tasks/main.yml @@ -19,39 +19,46 @@ quiet: yes -- name: Install MediaWiki {{ mediawiki_version }} if 'mediawiki_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: mediawiki_installed is undefined +- block: + - name: Install MediaWiki {{ mediawiki_version }} if 'mediawiki_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: mediawiki_installed is undefined -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + - name: Enable/Disable/Restart NGINX + include_tasks: nginx.yml + - name: Add 'mediawiki' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mediawiki + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: MediaWiki + - option: description + value: '"MediaWiki is a blog and web site management application, from the people who create Wikipedia."' + - option: mediawiki_install + value: "{{ mediawiki_install }}" + - option: mediawiki_enabled + value: "{{ mediawiki_enabled }}" + - option: mediawiki_src + value: "{{ mediawiki_src }}" + - option: mediawiki_abs_path + value: "{{ mediawiki_abs_path }}" + - option: mediawiki_db_name + value: "{{ mediawiki_db_name }}" + - option: mediawiki_db_user + value: "{{ mediawiki_db_user }}" + - option: mediawiki_url + value: "{{ mediawiki_url }}" + - option: mediawiki_full_url + value: "{{ mediawiki_full_url }}" -- name: Add 'mediawiki' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: mediawiki - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: MediaWiki - - option: description - value: '"MediaWiki is a blog and web site management application, from the people who create Wikipedia."' - - option: mediawiki_install - value: "{{ mediawiki_install }}" - - option: mediawiki_enabled - value: "{{ mediawiki_enabled }}" - - option: mediawiki_src - value: "{{ mediawiki_src }}" - - option: mediawiki_abs_path - value: "{{ mediawiki_abs_path }}" - - option: mediawiki_db_name - value: "{{ mediawiki_db_name }}" - - option: mediawiki_db_user - value: "{{ mediawiki_db_user }}" - - option: mediawiki_url - value: "{{ mediawiki_url }}" - - option: mediawiki_full_url - value: "{{ mediawiki_full_url }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/minetest/tasks/calc_vars.yml b/roles/minetest/NotUsed/calc_vars.yml similarity index 100% rename from roles/minetest/tasks/calc_vars.yml rename to roles/minetest/NotUsed/calc_vars.yml diff --git a/roles/minetest/tasks/rpi_minetest_install.yml b/roles/minetest/NotUsed/rpi_minetest_install.yml similarity index 100% rename from roles/minetest/tasks/rpi_minetest_install.yml rename to roles/minetest/NotUsed/rpi_minetest_install.yml diff --git a/roles/minetest/README.rst b/roles/minetest/README.rst index 38e04eef6..5d1afaba8 100644 --- a/roles/minetest/README.rst +++ b/roles/minetest/README.rst @@ -5,7 +5,7 @@ Minetest README `Minetest `_ is a `Minecraft `_-inspired creative/explorational building blocks game, written from scratch and licensed under the LGPL (version 2.1 or later). It supports both survival and creative modes along with multiplayer support, dynamic lighting, and an "infinite" map generator. -The Minetest multiplayer server can be installed as part of Internet-in-a-Box (IIAB) on Raspberry Pi (Raspbian), Ubuntu 18.04 and Debian 9 Stretch. +The Minetest multiplayer server can be installed as part of Internet-in-a-Box (IIAB) on Raspberry Pi OS, Ubuntu, or Debian. Please note that the initial configuration is for creative mode, and a number of mods are installed (see the list in `tasks/main.yml `_). @@ -23,14 +23,14 @@ No password is required. Configurable Parameters ----------------------- -If changes are necessary, please edit `/etc/iiab/local_vars.yml `_ (adding any variables that you need) prior to installation if possible: +If changes are necessary, please edit `/etc/iiab/local_vars.yml `_ (adding any variables that you need) prior to installation if possible: - ``minetest_install:`` set Minetest up to install; default is False - ``minetest_enabled:`` set Minetest up to be enabled; default is False - ``minetest_port:`` port on which client should connect; default is 30000 - ``minetest_server_admin:`` user with all permissions on minetest server; default is Admin -- ``minetest_default_game:`` only carbone-ng and minetest are supported; default is `carbone-ng `_ +- ``minetest_default_game:`` only the default minetest game is supported at present; in future the default will be DreamBuilder - ``minetest_flat_world:`` use a flat mapgen engine to lower computation on client; default is False After installation, you can monitor the 'minetest-server' service with command:: @@ -42,17 +42,6 @@ File Locations - The config file is ``/etc/minetest/minetest.conf`` - The world files are at ``/library/games/minetest/worlds/world`` - -File Locations on Raspberry Pi ------------------------------- - -- The server binary is ``/library/games/minetest/bin/minetestserver`` -- The working directory is ``/library/games/minetest`` -- mods are in ``/library/games/minetest/games//mods`` - -File Locations on Other Platforms ---------------------------------- - - The server binary is ``/usr/lib/minetest/minetestserver`` - The working directory is ``/usr/share/games/minetest`` - mods are in ``/usr/share/games/minetest/games//mods`` @@ -60,6 +49,6 @@ File Locations on Other Platforms To Do ----- -- Add more mods β€” currently only the default mods are there in carbone-ng +- Add more mods - Add more games - Minetest client software for Windows and Android, included onboard IIAB for offline communities (`#1465 `_) diff --git a/roles/minetest/defaults/main.yml b/roles/minetest/defaults/main.yml index 28f847046..052deed38 100644 --- a/roles/minetest/defaults/main.yml +++ b/roles/minetest/defaults/main.yml @@ -1,15 +1,13 @@ -# minetest_install: False -# minetest_enabled: False - -# minetest_port: 30000 -# minetest_server_admin: Admin - -# minetest_default_game: carbone-ng # only carbone-ng and minetest are supported -# minetest_flat_world: False - -# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml +# Other vars set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! # These should not be touched unless minetest packages change +minetest_server_bin: /usr/lib/minetest/minetestserver minetest_config_file: /etc/minetest/minetest.conf minetest_world_dir: /library/games/minetest/worlds/world + +minetest_runas_user: root +minetest_runas_group: root + +#minetest_runas_user: Debian-minetest +#minetest_runas_group: games diff --git a/roles/minetest/tasks/install.yml b/roles/minetest/tasks/install.yml new file mode 100644 index 000000000..9c00a10c2 --- /dev/null +++ b/roles/minetest/tasks/install.yml @@ -0,0 +1,62 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: Check for Minetest world file ({{ minetest_world_dir }}/world.mt) + stat: + path: "{{ minetest_world_dir }}/world.mt" + register: minetest_world + +- name: mkdir /library/games + file: + state: directory + path: /library/games + +- include_tasks: minetest_install.yml + when: not minetest_world.stat.exists + +# Install games +#- include_tasks: minetest_install_games.yml +# with_items: +# - name: carbone-ng +# url: https://github.com/Calinou/carbone-ng + +# Install mods +- include_tasks: minetest_install_mods.yml + with_items: + - name: basic_materials + url: https://content.minetest.net/packages/VanessaE/basic_materials/releases/14936/download/ + - name: mesecons + url: https://content.minetest.net/packages/Jeija/mesecons/releases/14247/download/ + - name: digilines + url: https://content.minetest.net/packages/Jeija/digilines/releases/13248/download/ + - name: pipeworks + url: https://content.minetest.net/packages/VanessaE/pipeworks/releases/7488/download/ + - name: Minetest-WorldEdit + url: https://content.minetest.net/packages/sfan5/worldedit/releases/13367/download/ + when: minetest_default_game == "minetest" + + +# RECORD Minetest AS INSTALLED + +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'minetest_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: minetest + option: minetest_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + +- name: "Set 'minetest_installed: True'" + set_fact: + minetest_installed: True + +- name: "Add 'minetest_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^minetest_installed' + line: 'minetest_installed: True' diff --git a/roles/minetest/tasks/main.yml b/roles/minetest/tasks/main.yml index a07d640c7..9955788d6 100644 --- a/roles/minetest/tasks/main.yml +++ b/roles/minetest/tasks/main.yml @@ -19,32 +19,39 @@ quiet: yes -- name: Install Minetest if 'minetest_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: provision.yml # i.e. install.yml in other roles - when: minetest_installed is undefined +- block: + - name: Install Minetest if 'minetest_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: minetest_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'minetest' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: minetest + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Minetest Server + - option: description + value: '"Minetest is an open source clone of the Minecraft building blocks game."' + - option: minetest_install + value: "{{ minetest_install }}" + - option: minetest_enabled + value: "{{ minetest_enabled }}" + - option: minetest_world_dir + value: "{{ minetest_world_dir }}" + - option: minetest_port + value: "{{ minetest_port }}" + - option: minetest_world_dir + value: "{{ minetest_world_dir }}" -- name: Add 'minetest' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: minetest - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Minetest Server - - option: description - value: '"Minetest is an open source clone of the Minecraft building blocks game."' - - option: minetest_install - value: "{{ minetest_install }}" - - option: minetest_enabled - value: "{{ minetest_enabled }}" - - option: minetest_world_dir - value: "{{ minetest_world_dir }}" - - option: minetest_port - value: "{{ minetest_port }}" - - option: minetest_world_dir - value: "{{ minetest_world_dir }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/minetest/tasks/minetest_install.yml b/roles/minetest/tasks/minetest_install.yml index 354907526..8cf943147 100644 --- a/roles/minetest/tasks/minetest_install.yml +++ b/roles/minetest/tasks/minetest_install.yml @@ -1,5 +1,3 @@ -# For non-rpi installs - - name: Install Minetest package package: name: minetest-server @@ -35,11 +33,3 @@ mode: 0755 with_items: - "{{ minetest_world_dir }}" - -- name: Change exec line in generated unit file - lineinfile: - path: /lib/systemd/system/minetest-server.service - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^ExecStart=/usr/lib/minetest/minetestserver', line: 'ExecStart=/usr/lib/minetest/minetestserver --config /etc/minetest/minetest.conf --logfile /var/log/minetest/minetest.log --world "{{ minetest_world_dir }}"' } diff --git a/roles/minetest/tasks/provision.yml b/roles/minetest/tasks/provision.yml deleted file mode 100644 index ac63b5329..000000000 --- a/roles/minetest/tasks/provision.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Calculate local variables -- include_tasks: calc_vars.yml - -- name: Check for Minetest world file ({{ minetest_world_dir }}/world.mt) - stat: - path: "{{ minetest_world_dir }}/world.mt" - register: minetest_world - -- name: mkdir /library/games - file: - state: directory - path: /library/games - # owner: root - # group: root - # mode: '0755' - -# rpi only -- include_tasks: rpi_minetest_install.yml - when: not minetest_world.stat.exists and is_raspbian - -# not rpi -- include_tasks: minetest_install.yml - when: not minetest_world.stat.exists and not is_raspbian - -- git: - repo: https://github.com/Calinou/carbone-ng.git - dest: "{{ minetest_game_dir }}" - depth: 1 - when: not minetest_world.stat.exists and minetest_default_game == "carbone-ng" - -- name: Give Minetest user ownership of carbone-ng - file: - state: directory - path: "{{ minetest_game_dir }}" - recurse: yes - owner: "{{ minetest_runas_user }}" - group: "{{ minetest_runas_group }}" - # mode: 0755 - when: minetest_default_game == "carbone-ng" - -# Install games -#- include_tasks: minetest_install_games.yml -# with_items: -# - name: carbone-ng -# url: https://github.com/Calinou/carbone-ng - -# Install mods -- include_tasks: minetest_install_mods.yml - with_items: - - name: moreblocks - url: https://github.com/minetest-mods/moreblocks/archive/master.zip - - name: moreores - url: https://github.com/Calinou/moreores/archive/master.zip - - name: basic_materials - url: https://gitlab.com/VanessaE/basic_materials/-/archive/master/basic_materials-master.zip - - name: mesecons - url: https://github.com/minetest-mods/mesecons/archive/master.zip - - name: digilines - url: https://github.com/minetest-mods/digilines/archive/master.zip - - name: pipeworks - url: https://github.com/minetest-mods/pipeworks/archive/master.zip - - name: Minetest-WorldEdit - url: https://github.com/Uberi/Minetest-WorldEdit/archive/master.zip - when: minetest_default_game == "minetest" - -- name: Remove mod from carbone-ng that prevents our Admin name - file: - state: absent - path: "{{ minetest_game_dir }}/mods/name_restrictions" - when: minetest_default_game == "carbone-ng" - - -# RECORD Minetest AS INSTALLED - -- name: "Set 'minetest_installed: True'" - set_fact: - minetest_installed: True - -- name: "Add 'minetest_installed: True' to {{ iiab_state_file }}" - lineinfile: - path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml - regexp: '^minetest_installed' - line: 'minetest_installed: True' diff --git a/roles/minetest/templates/minetest-server.service.j2 b/roles/minetest/templates/minetest-server.service.j2.unused similarity index 100% rename from roles/minetest/templates/minetest-server.service.j2 rename to roles/minetest/templates/minetest-server.service.j2.unused diff --git a/roles/minetest/templates/minetest.conf.j2 b/roles/minetest/templates/minetest.conf.j2.unused similarity index 100% rename from roles/minetest/templates/minetest.conf.j2 rename to roles/minetest/templates/minetest.conf.j2.unused diff --git a/roles/mongodb/defaults/main.yml b/roles/mongodb/defaults/main.yml index 1c54103e7..a5e2455d3 100644 --- a/roles/mongodb/defaults/main.yml +++ b/roles/mongodb/defaults/main.yml @@ -20,6 +20,27 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! +mongodb_arch_dict: + armv6l: unsupported # WAS: 3.0 + armv7l: unsupported # WAS: 3.0 + aarch64: 5.0 + i386: unsupported + x86_64: 6.0 + +mongodb_version: "{{ mongodb_arch_dict[ansible_machine] | default('unknown') }}" # A bit safer than ansible_architecture (see kiwix/defaults/main.yml) + +#mongodb_arm64_version: 5.0 # 2023-02-24: MongoDB 6.0.4 fails to install on +# # 64-bit RasPiOS 11, as it doesn't offer libssl3. +#mongodb_amd64_version: 6.0 # 2022-10-23: 4.4 fails on Debian 12 x86_64: +# "No package matching 'mongodb-org' is available". 5.0+ fail on "pre-2011" +# CPU's w/o AVX, and on RPi due to MongoDB compiling these for v8.2-A (RPi 4 is +# ARM v8-A). SO IIAB ALWAYS OVERLAYS andyfelong.com's 5.0.5 IF 5.0+ SPECIFIED. +# +# VERIFY both X.Y versions exist (+ work!) below: +# +# 1) https://www.mongodb.org/static/pgp/server-X.Y.asc ~= https://pgp.mongodb.com +# 2) http://repo.mongodb.org/apt/debian &/OR https://repo.mongodb.org/apt/ubuntu + mongodb_conf: /etc/mongod.conf mongodb_db_path: "{{ content_base }}/dbdata/mongodb" # /library/dbdata/mongodb mongodb_db_lock_file: "{{ mongodb_db_path }}/mongod.lock" diff --git a/roles/mongodb/tasks/enable-or-disable.yml b/roles/mongodb/tasks/enable-or-disable.yml index 68aaf9e84..851b4fb0e 100644 --- a/roles/mongodb/tasks/enable-or-disable.yml +++ b/roles/mongodb/tasks/enable-or-disable.yml @@ -1,6 +1,7 @@ - name: Enable & (Re)Start 'mongodb.service' if mongodb_enabled systemd: name: mongodb + daemon_reload: yes enabled: yes state: restarted when: mongodb_enabled diff --git a/roles/mongodb/tasks/install.yml b/roles/mongodb/tasks/install.yml index 061a27751..10c2f39f5 100644 --- a/roles/mongodb/tasks/install.yml +++ b/roles/mongodb/tasks/install.yml @@ -1,151 +1,366 @@ -# 1. INSTALL MongoDB PACKAGES OR BINARIES +# MongoDB Install Docs: +# https://www.mongodb.com/community/forums/t/installing-mongodb-over-ubuntu-22-04/159931/90 +# https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/ +# https://www.mongodb.com/docs/manual/installation/ + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# 1. INSTALL MongoDB PACKAGES AND/OR BINARIES # 2019-02-02: Sugarizer with Node.js 10.x requires MongoDB 2.6+ so # https://andyfelong.com/2017/08/mongodb-3-0-14-for-raspbian-stretch/ is # being used on Raspbian, all I found! (Raspbian's apt pkg is MongoDB 2.4.14) # # mongodb_stretch_3_0_14_core.zip (20M) & mongodb_stretch_3_0_14_tools.zip (15M) -# were backed up from andyfelong.com to http://download.iiab.io/packages/ +# were backed up from andyfelong.com to https://download.iiab.io/packages/ # # CLARIF: mongodb_stretch_3_0_14_core.zip IS IN FACT 3.0.14 (core) BUT... # mongodb_stretch_3_0_14_tools.zip IS REALLY 3.0.15 (tools) -- block: - - name: Create dir /tmp/mongodb-3.0.1x (aarch32) - file: - path: /tmp/mongodb-3.0.1x - state: directory +# - debug: +# msg: '9-STANZA BLOCK BELOW, RUNS *IF* 32-BIT -- i.e. not (ansible_architecture == "aarch64" or ansible_architecture == "x86_64") -- WILL LIKELY BE REMOVED SOON IN 2023, as MongoDB 3.0.1 is insufficient for Sugarizer Server 1.5.0''s new MongoDB 3.2+ REQUIREMENT: https://github.com/iiab/iiab/pull/3478#issuecomment-1444395170' - - name: Download & unzip 20MB http://download.iiab.io/packages/mongodb_stretch_3_0_14_core.zip to /tmp/mongodb-3.0.1x (aarch32) - unarchive: - remote_src: yes - src: "{{ iiab_download_url }}/mongodb_stretch_3_0_14_core.zip" # http://download.iiab.io/packages - dest: /tmp/mongodb-3.0.1x +# - block: +# - name: Create dir /tmp/mongodb-3.0.1x (aarch32) +# file: +# path: /tmp/mongodb-3.0.1x +# state: directory - - name: Install (move) its 3 CORE binaries from /tmp/mongodb-3.0.1x/core to /usr/bin (aarch32) - shell: mv /tmp/mongodb-3.0.1x/core/* /usr/bin +# - name: Download & unzip 20MB https://download.iiab.io/packages/mongodb_stretch_3_0_14_core.zip to /tmp/mongodb-3.0.1x (aarch32) +# unarchive: +# remote_src: yes +# src: "{{ iiab_download_url }}/mongodb_stretch_3_0_14_core.zip" # https://download.iiab.io/packages +# dest: /tmp/mongodb-3.0.1x - - name: Download & unzip 15MB http://download.iiab.io/packages/mongodb_stretch_3_0_14_tools.zip [IN FACT THIS ONE'S 3.0.15] to /tmp/mongodb-3.0.1x (aarch32) - unarchive: - remote_src: yes - src: "{{ iiab_download_url }}/mongodb_stretch_3_0_14_tools.zip" - dest: /tmp/mongodb-3.0.1x +# - name: Install (move) its 3 CORE binaries from /tmp/mongodb-3.0.1x/core to /usr/bin (aarch32) +# shell: mv /tmp/mongodb-3.0.1x/core/* /usr/bin - - name: Install (move) its 9 TOOLS binaries from /opt/iiab/downloads/mongodb-3.0.1x/tools to /usr/bin (aarch32) - shell: mv /tmp/mongodb-3.0.1x/tools/* /usr/bin +# - name: Download & unzip 15MB https://download.iiab.io/packages/mongodb_stretch_3_0_14_tools.zip [IN FACT THIS ONE'S 3.0.15] to /tmp/mongodb-3.0.1x (aarch32) +# unarchive: +# remote_src: yes +# src: "{{ iiab_download_url }}/mongodb_stretch_3_0_14_tools.zip" +# dest: /tmp/mongodb-3.0.1x - - name: Create Linux group mongodb (aarch32) - group: - name: mongodb - state: present +# - name: Install (move) its 9 TOOLS binaries from /opt/iiab/downloads/mongodb-3.0.1x/tools to /usr/bin (aarch32) +# shell: mv /tmp/mongodb-3.0.1x/tools/* /usr/bin - - name: Create Linux user mongodb (aarch32) - user: - name: mongodb - group: mongodb # primary group - groups: mongodb - home: /var/lib/mongodb - shell: /usr/sbin/nologin +# - name: Create Linux group mongodb (aarch32) +# group: +# name: mongodb +# state: present - - name: Install {{ mongodb_conf }} from template (aarch32) - template: - src: mongod.conf.j2 - dest: "{{ mongodb_conf }}" # /etc/mongod.conf - #owner: root - #group: root - #mode: 0644 +# - name: Create Linux user mongodb (aarch32) +# user: +# name: mongodb +# group: mongodb # primary group +# groups: mongodb +# home: /var/lib/mongodb +# shell: /usr/sbin/nologin - # end block - when: not (ansible_architecture == "x86_64" or ansible_architecture == "aarch64") +# - name: Install {{ mongodb_conf }} from template (aarch32) +# template: +# src: mongod.conf.j2 +# dest: "{{ mongodb_conf }}" # /etc/mongod.conf -# 32-bit OS's are handled above: this should handle aarch32 including 32-bit Ubuntu -# from https://ubuntu.com/download/raspberry-pi but Ubuntu 20.04 32-bit might fail -# untested, and 32-bit Intel might puke as this was orginally deployed for Raspbian. -# (Haven't seen bootable 32-bit Intel installers for a while now.) -# 64-bit OS's proceed below. +# - name: 'Create 2 dirs: /var/lib/mongodb, /var/log/mongodb (mongodb:mongodb)' +# file: +# state: directory +# path: "{{ item }}" +# owner: mongodb +# group: mongodb +# with_items: +# - /var/lib/mongodb +# - /var/log/mongodb + +# # end block +# when: not (ansible_architecture == "x86_64" or ansible_architecture == "aarch64") # ansible_machine is a bit safer than ansible_architecture (see kiwix/defaults/main.yml) + +# - debug: +# msg: 9-STANZA BLOCK ABOVE, RAN *IF* 32-BIT -- i.e. not (ansible_architecture == "aarch64" or ansible_architecture == "x86_64") + +# 32-bit OS's [WERE] handled above: this should handle aarch32 including 32-bit +# Ubuntu from https://ubuntu.com/download/raspberry-pi but Ubuntu 20.04+ and +# 22.04+ 32-bit might fail untested, and 32-bit Intel might puke as this was +# orginally deployed for Raspbian. (Haven't seen bootable 32-bit Intel +# installers for a while now.) 64-bit OS's proceed below. + + +# - debug: +# msg: 16-STANZA BLOCK BELOW, RUNS *IF* 64-BIT -- i.e. ansible_architecture == "aarch64" or ansible_architecture == "x86_64" + +# - block: +- name: Add mongodb.org signing key (only 64-bit available) for MongoDB version {{ mongodb_version }} + # https://www.mongodb.com/community/forums/t/installing-mongodb-over-ubuntu-22-04/159931/90 + shell: wget -qO - https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc | gpg --dearmor > /usr/share/keyrings/mongodb.gpg + #shell: wget -qO - https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc | apt-key add - + #shell: wget -qO - https://pgp.mongodb.com/server-{{ mongodb_version }}.asc | apt-key add - + #args: + # warn: no + # Ansible 2.14 ERROR: + # "Unsupported parameters for (ansible.legacy.command) module: warn. + # Supported parameters include: removes, strip_empty_ends, _raw_params, + # _uses_shell, stdin_add_newline, creates, chdir, executable, argv, stdin." + +# 2023-01-19: MongoDB only offers x86_64 for Debian, AND IN ANY CASE all their +# MongoDB 6.0's are ONLY COMPILED FOR ARM v8.2-A i.e. FAIL ON ARM v8-A RPi 4, +# LIKE THEIR MongoDB 5.0 tested 2022-06-07 ~137 lines below. Tested on Deb 11. +# -> DELETE THIS STANZA AFTER DEBIAN 12 IS SOLID -- USING UBUNTU REPO BELOW ? +- name: Install mongodb-org's Debian bullseye source/repo [ arch=amd64 ] for MongoDB version {{ mongodb_version }}, if x86_64 Debian < 12 + apt_repository: + # 2020-10-28 and 2022-06-09: https://repo.mongodb.org/apt/debian/dists/ + # supports only {Buster 10, Stretch 9, Jessie 8, Wheezy 7}. So Bullseye + # 11 and Bookworm 12 (testing branch) revert to buster for now: + # 2022-09-27: Changed from 'buster' to 'bullseye' (i.e. Debian 11) as + # this was recently added to https://repo.mongodb.org/apt/debian/dists/ + repo: deb [ arch=amd64 signed-by=/usr/share/keyrings/mongodb.gpg ] https://repo.mongodb.org/apt/debian bullseye/mongodb-org/{{ mongodb_version }} main + #repo: deb https://repo.mongodb.org/apt/debian bullseye/mongodb-org/{{ mongodb_version }} main + #repo: deb https://repo.mongodb.org/apt/debian {{ ansible_distribution_release }}/mongodb-org/4.4 main + #filename: mongodb-org + when: is_debian and os_ver is version('debian-12', '<') and ansible_architecture == "x86_64" + +- name: Install mongodb-org's Ubuntu jammy source/repo [ arch=amd64 ] for MongoDB version {{ mongodb_version }}, if other x86_64 OS + apt_repository: + repo: deb [ arch=amd64 signed-by=/usr/share/keyrings/mongodb.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/{{ mongodb_version }} multiverse + when: not (is_debian and os_ver is version('debian-12', '<')) and ansible_architecture == "x86_64" + +# 2023-01-19: Tested on x86_64 VM's with Ubuntu 22.04 & Debian 12. Based on +# MongoDB 6.0.3 (released 2022-11-15) instructions here: +# https://www.mongodb.com/community/forums/t/installing-mongodb-over-ubuntu-22-04/159931/90 +# WHEREAS 64-bit Raspberry Pi is likely NOT supported for now, as MongoDB 6.0 +# IS ONLY COMPILED FOR ARM v8.2-A i.e. FAIL ON ARM v8-A RPi 4 (JUST LIKE THEIR +# MongoDB 5.0, tested 2022-06-07 ~116 lines below). Though MongoDB 6.0.3+ on +# 64-bit Ubuntu on Raspberry Pi hardware (MIGHT) hypothetically be possible: +# https://www.mongodb.com/developer/products/mongodb/mongodb-on-raspberry-pi/ +# So IIAB overlays MongoDB 5.0.5 64-bit RPi binaries for now (~141 LINES BELOW!) +- name: Otherwise, install mongodb-org's Ubuntu focal source/repo [ arch=arm64 ] for MongoDB version {{ mongodb_version }} + apt_repository: + repo: deb [ arch=arm64 signed-by=/usr/share/keyrings/mongodb.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/{{ mongodb_version }} multiverse + #repo: deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/{{ mongodb_version }} multiverse + #repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/{{ mongodb_version }} multiverse + #filename: mongodb-org + when: not ansible_architecture == "x86_64" + #when: is_ubuntu or is_debian and os_ver is version('debian-12', '>=') + #when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') or is_linuxmint and os_ver is version('linuxmint-12', '>=') or is_debian and os_ver is version('debian-12', '>=') + #when: not (is_debian and ansible_architecture == "x86_64") + + +# 2022-10-23: Force-install MongoDB on Ubuntu 22.04+, Mint 21 & Debian 12; +# as each includes libssl3 not libssl1.1 (#3190). LATER REMOVE ALL 7 STANZAS +# BELOW, IF/WHEN MongoDB ONE DAY FINALLY SUPPORTS libssl3 ? (MongoDB 6.2 fix +# may be backported to 6.0, according to 2022-09-29 "official" gossip here...) +# https://www.mongodb.com/community/forums/t/installing-mongodb-over-ubuntu-22-04/159931/58 +# https://askubuntu.com/questions/1403619/mongodb-install-fails-on-ubuntu-22-04-depends-on-libssl1-1-but-it-is-not-insta/1403683#1403683 +# echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list +# sudo apt-get update +# sudo apt-get install libssl1.1 +# rm /etc/apt/sources.list.d/focal-security.list + +# 2023-02-25: RETROFITTING libssl1.1 STILL NEC on Ubuntu 22.04+ and Debian 12+ +# *IF* MongoDB < 6.0 (e.g. RPi, where MongoDB 6.0 is a complete non-starter!) +# +# Whereas libssl1.1 is thankfully NO LONGER NEC on x86_64, where MongoDB can +# finally use libssl3 instead, since 2022-11-15: +# https://www.mongodb.com/community/forums/t/installing-mongodb-over-ubuntu-22-04/159931/90 + +- debug: + msg: 5-STANZA BLOCK FOLLOWS, TO FORCE INSTALL libssl1.1 -- runs *IF* mandated mongodb_version ({{ mongodb_version }}) < 6.0 (i.e. for aarch64/arm64) on Ubuntu 22.04+ or Debian 12+ -- whereas Linux Mint should never need libssl1.1 - block: - - name: Add mongodb.org signing key (only 64-bit support available) - shell: wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add - - args: - warn: false - - name: Use mongodb-org's Debian repo for Debian (only amd64 support available) + - name: Install OLD source/repo "deb http://ports.ubuntu.com/ubuntu-ports focal-security main" at /etc/apt/sources.list.d/ports_ubuntu_com_ubuntu_ports.list if Ubuntu apt_repository: - # 2020-10-28: http://repo.mongodb.org/apt/debian/dists/ supports only - # {buster 10, stretch 9, jessie 8, wheezy 7} - # so Debian 11 "Bullseye" (testing branch) can revert to buster for now: - repo: deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.4 main - #repo: deb http://repo.mongodb.org/apt/debian {{ ansible_distribution_release }}/mongodb-org/4.4 main - state: present - filename: mongodb-org - when: is_debian and (ansible_architecture == "x86_64") + repo: deb http://ports.ubuntu.com/ubuntu-ports focal-security main + when: is_ubuntu - # Debian 10 aarch64 might work below but is blocked in main.yml - - name: Use mongodb-org's Ubuntu focal repo for RasPiOS-aarch64 + - name: Install OLD source/repo "deb http://security.debian.org/debian-security bullseye-security main" at /etc/apt/sources.list.d/security_debian_org_debian_security.list if Debian apt_repository: - repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse - state: present - filename: mongodb-org - when: is_raspbian and (ansible_architecture == "aarch64") + repo: deb http://security.debian.org/debian-security bullseye-security main + #repo: deb https://deb.debian.org/debian-security bullseye-security main # New way, likely equivalent + when: is_debian - - name: Use mongodb-org's Ubuntu focal repo for Linux Mint - 64bit only - apt_repository: - repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse - state: present - filename: mongodb-org - when: is_linuxmint - - - name: Use mongodb-org's Ubuntu repo for all non-Mint Ubuntu - 64bit only - apt_repository: - # 2020-10-27: https://repo.mongodb.org/apt/ubuntu/dists/ supports only - # {focal 20.04, bionic 18.04, xenial 16.04, trusty 14.04, precise 12.04} - # so other Ubuntu's like groovy 20.10 need to revert to recent LTS repo: - repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse - #repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release }}/mongodb-org/4.4 multiverse - state: present - filename: mongodb-org - when: is_ubuntu and not is_linuxmint - - - name: "Install packages: mongodb-org, mongodb-org-server" + - name: Force install libssl1.1 package: - name: - - mongodb-org - - mongodb-org-server + name: libssl1.1 state: present - - name: Establish {{ mongodb_conf }} port {{ mongodb_port }} (mongodb_conf) -- takes effect on next (re)start of the service -- via enable-or-disable.yml or via sugarizer.service auto-starting MongoDB on demand - lineinfile: - path: "{{ mongodb_conf }}" - regexp: '^\s*port:' # \s = any whitespace char. stackoverflow.com/a/38491899 - #backrefs: yes - line: " port: {{ mongodb_port }}" # 27017 + - name: Remove OLD source/repo "deb http://security.debian.org/debian-security bullseye-security main" at /etc/apt/sources.list.d/security_debian_org_debian_security.list if Debian + apt_repository: + repo: deb http://security.debian.org/debian-security bullseye-security main + #repo: deb https://deb.debian.org/debian-security bullseye-security main # New way, likely equivalent + state: absent + when: is_debian - # end block - when: (ansible_architecture == "aarch64") or (ansible_architecture == "x86_64") + - name: Remove OLD source/repo "deb http://ports.ubuntu.com/ubuntu-ports focal-security main" at /etc/apt/sources.list.d/ports_ubuntu_com_ubuntu_ports.list if Ubuntu + apt_repository: + repo: deb http://ports.ubuntu.com/ubuntu-ports focal-security main + state: absent + when: is_ubuntu + + when: mongodb_version is version('6.0', '<') and (is_ubuntu and os_ver is version('ubuntu-2204', '>=') or is_debian and os_ver is version('debian-12', '>=')) + +- debug: + msg: 5-STANZA BLOCK ABOVE, RAN *IF* FORCED INSTALL OF libssl1.1 WAS NEEDED + +# - name: Install source/repo "deb http://security.ubuntu.com/ubuntu focal-security main" at /etc/apt/sources.list.d/security_ubuntu_com_ubuntu.list if Ubuntu 22.04+ x86_64 or Mint 21 +# apt_repository: +# repo: deb http://security.ubuntu.com/ubuntu focal-security main +# #filename: focal-security # If filename focal-security.list is preferred +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') and ansible_architecture == "x86_64" or is_linuxmint_21 + +# - name: Install source/repo "deb http://ports.ubuntu.com/ubuntu-ports focal-security main" at /etc/apt/sources.list.d/ports_ubuntu_com_ubuntu_ports.list if ubuntu 22.04+ aarch64 +# apt_repository: +# repo: deb http://ports.ubuntu.com/ubuntu-ports focal-security main +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') and ansible_architecture == "aarch64" + +# - name: Install source/repo "deb http://security.debian.org/debian-security bullseye-security main" at /etc/apt/sources.list.d/security_debian_org_debian_security.list if Debian 12 +# apt_repository: +# repo: deb http://security.debian.org/debian-security bullseye-security main +# #repo: deb https://deb.debian.org/debian-security bullseye-security main # New way, likely equivalent +# when: is_debian_12 + +# - name: Install libssl1.1 if Ubuntu 22.04+ or Mint 21 or Debian 12 (required by MongoDB below) +# package: +# name: libssl1.1 +# state: present +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') or is_linuxmint_21 or is_debian_12 + +# - name: Remove source/repo "deb http://security.debian.org/debian-security bullseye-security main" at /etc/apt/sources.list.d/security_debian_org_debian_security.list if Debian 12 +# apt_repository: +# repo: deb http://security.debian.org/debian-security bullseye-security main +# #repo: deb https://deb.debian.org/debian-security bullseye-security main # New way, likely equivalent +# state: absent +# when: is_debian_12 + +# - name: Remove source/repo "deb http://ports.ubuntu.com/ubuntu-ports focal-security main" at /etc/apt/sources.list.d/ports_ubuntu_com_ubuntu_ports.list if ubuntu 22.04+ aarch64 +# apt_repository: +# repo: deb http://ports.ubuntu.com/ubuntu-ports focal-security main +# state: absent +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') and ansible_architecture == "aarch64" + +# - name: Remove source/repo "deb http://security.ubuntu.com/ubuntu focal-security main" at /etc/apt/sources.list.d/security_ubuntu_com_ubuntu.list if Ubuntu 22.04+ x86_64 or Mint 21 +# apt_repository: +# repo: deb http://security.ubuntu.com/ubuntu focal-security main +# state: absent +# #filename: focal-security # 100% IGNORED during repo deletion +# when: is_ubuntu and os_ver is version('ubuntu-2204', '>=') and ansible_architecture == "x86_64" or is_linuxmint_21 + + +# # Debian 10 aarch64 might work below but is blocked in main.yml +# - name: Use mongodb-org's Ubuntu focal repo for RasPiOS-aarch64 +# apt_repository: +# repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse +# filename: mongodb-org +# when: is_raspbian and ansible_architecture == "aarch64" + +# - name: Use mongodb-org's Ubuntu focal repo for Linux Mint - 64bit only +# apt_repository: +# repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse +# filename: mongodb-org +# when: is_linuxmint + +# - name: Use mongodb-org's Ubuntu repo for all non-Mint Ubuntu - 64bit only +# apt_repository: +# # 2020-10-27: https://repo.mongodb.org/apt/ubuntu/dists/ supports only +# # {focal 20.04, bionic 18.04, xenial 16.04, trusty 14.04, precise 12.04} +# # so other Ubuntu's like groovy 20.10 need to revert to recent LTS repo: +# repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse +# #repo: deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release }}/mongodb-org/4.4 multiverse +# filename: mongodb-org +# when: is_ubuntu and not is_linuxmint + + +- name: "Install packages: mongodb-org, mongodb-org-server" + package: + name: + - mongodb-org # Meta-package that's auto-installed anyway (SO PROB UNNEC HERE?) + - mongodb-org-server + state: present + +- name: Establish {{ mongodb_conf }} dbPath {{ mongodb_db_path }} -- instead of /var/lib/mongodb default -- takes effect on next (re)start of mongodb.service -- via enable-or-disable.yml or via sugarizer.service auto-starting MongoDB on demand + lineinfile: + path: "{{ mongodb_conf }}" # /etc/mongod.conf + regexp: '^\s*dbPath:' # \s = any whitespace char. stackoverflow.com/a/38491899 + line: " dbPath: {{ mongodb_db_path }}" # /library/dbdata/mongodb + +# GRATUITOUS (port 27017 is already the default) +- name: Establish {{ mongodb_conf }} port {{ mongodb_port }} -- takes effect on next (re)start of mongodb.service -- via enable-or-disable.yml or via sugarizer.service auto-starting MongoDB on demand + lineinfile: + path: "{{ mongodb_conf }}" + regexp: '^\s*port:' + line: " port: {{ mongodb_port }}" # 27017 + + +# 2022-06-07 #3236 MongoDB 5.0.9 "Illegal instruction" on RPi 4... +# https://www.mongodb.com/community/forums/t/core-dump-on-mongodb-5-0-on-rpi-4/115291/14 +# ...as ARM v8-A < ARM v8.2-A ...also reveals: +# +# (1) For Intel x86_64, MongoDB 5.x requires Sandy Bridge or later. +# For AMD x86_64, MongoDB 5.x requires Bulldozer or later. +# Roughly speaking, this means post-2011 CPUs with AVX instructions: +# https://github.com/docker-library/mongo/issues/485#issuecomment-891991814 +# (2) dbPath needed fixing in /etc/mongod.conf (~16 lines above) from +# /var/lib/mongodb to /library/dbdata/mongodb +# (3) mongod.lock is effectively NO LONGER A LOCK FILE -- but rather a PID +# file (it may be zero bytes, but never goes away) as confirmed with +# MongoDB 4.4.14 on RPi 4 and 5.0.9 Ubuntu 22.04 on x86_64. And now +# 'mongod --repair --dbpath /library/dbdata/mongodb/' IGNORES mongod.lock +# (4) mongodb.service needed a more graceful way to shut down than +# 'killall mongod' (MongoDB 5+ shuts down w/ 15sec quiesce period). +# (5) MongoDB 6.0 is likely imminent; meantime a 2022-01-12 option (~12 +# lines below) is MongoDB 5.0.5 compiled for 64-bit RPi 4 and RPi 400: +# https://andyfelong.com/downloads/raspbian_mongodb_5.0.5.gz +# https://andyfelong.com/2021/08/mongodb-4-4-under-raspberry-pi-os-64-bit-raspbian64/ + +- name: If hardware is Raspberry Pi and mongodb_version >= 5.0, run 'apt-mark hold mongodb-org mongodb-org-server' -- so MongoDB 5.0.5 binaries {mongo, mongod, mongos} can be installed without apt interfering in future + command: apt-mark hold mongodb-org mongodb-org-server + when: rpi_model != "none" and mongodb_version is version('5.0', '>=') + +- name: If hardware is Raspberry Pi and mongodb_version >= 5.0, unarchive 76MB {{ iiab_download_url }}//packages/raspbian_mongodb_5.0.5.gz OVERWRITING 5.0.9+ {mongo, mongod, mongos} in /usr/bin + unarchive: + remote_src: yes + src: "{{ iiab_download_url }}/raspbian_mongodb_5.0.5.gz" + dest: /usr/bin + when: rpi_model != "none" and mongodb_version is version('5.0', '>=') + +# # end block +# when: ansible_architecture == "aarch64" or ansible_architecture == "x86_64" + +# - debug: +# msg: 16-STANZA BLOCK ABOVE, RAN *IF* 64-BIT -- i.e. ansible_architecture == "aarch64" or ansible_architecture == "x86_64" # ansible_machine is a bit safer than ansible_architecture (see kiwix/defaults/main.yml) # 2. CONFIGURE MongoDB FOR IIAB -- name: 'Create 3 dirs for MongoDB: /var/lib/mongodb, /var/log/mongodb, {{ mongodb_db_path }}' +# - name: 'Create 3 dirs for MongoDB: /var/lib/mongodb, /var/log/mongodb, {{ mongodb_db_path }}' +# file: +# state: directory +# path: "{{ item }}" +# owner: mongodb +# group: mongodb +# with_items: +# #- { path: '/var/run/mongodb' } +# - /var/lib/mongodb +# - /var/log/mongodb +# - "{{ mongodb_db_path }}" # /library/dbdata/mongodb + +- name: 'Create dir {{ mongodb_db_path }} (mongodb:mongodb)' file: state: directory - path: "{{ item }}" + path: "{{ mongodb_db_path }}" # /library/dbdata/mongodb owner: mongodb group: mongodb - with_items: - #- { path: '/var/run/mongodb' } - - /var/lib/mongodb - - /var/log/mongodb - - "{{ mongodb_db_path }}" # /library/dbdata/mongodb - name: Install mongodb.service, /usr/bin/iiab-mongodb-repair-if-no-lock from templates template: src: "{{ item.src }}" dest: "{{ item.dest }}" - owner: root - group: root mode: "{{ item.mode }}" + #owner: root + #group: root with_items: - { src: 'mongodb.service.j2', dest: '/etc/systemd/system/mongodb.service', mode: '0644' } - { src: 'iiab-mongodb-repair-if-no-lock.j2', dest: '/usr/bin/iiab-mongodb-repair-if-no-lock', mode: '0755' } @@ -157,6 +372,17 @@ # 3. RECORD MongoDB AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'mongodb_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mongodb + option: mongodb_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'mongodb_installed: True'" set_fact: mongodb_installed: True diff --git a/roles/mongodb/tasks/main.yml b/roles/mongodb/tasks/main.yml index e5e2f20ba..1dc712a0a 100644 --- a/roles/mongodb/tasks/main.yml +++ b/roles/mongodb/tasks/main.yml @@ -29,43 +29,57 @@ - debug: var: rpi_model # 0-init sets it from ansible_local.local_facts.rpi_model - debug: - var: ansible_local.local_facts.os_ver # Like OS_VER in /etc/iiab/iiab.env + var: os_ver # Equivalent to ansible_local.local_facts.os_ver and OS_VER in /etc/iiab/iiab.env - debug: var: is_debian - debug: var: is_raspbian +- debug: + var: mongodb_version -# might be able to lift this once we know using bionic would work -- name: EXIT 'mongodb' ROLE & CONTINUE, IF 'is_debian_10 and aarch64 and not is_raspbian' i.e. TRUE DEBIAN with arch64 - fail: # FORCE IT RED THIS ONCE! - msg: ATTEMPTED MongoDB INSTALLATION WITH (TRUE) DEBIAN aarch64, which is not supported upstream. Nevertheless IIAB will continue (consider this a warning!) - when: (ansible_architecture == "aarch64") and is_debian_10 and not is_raspbian - ignore_errors: yes +# WARNING: Since March 2023, 32-bit RasPiOS can act as 64-bit on RPi 4 and +# RPi 400 (unlike RPi 3!) SEE: https://github.com/iiab/iiab/pull/3422 and #3516 +- name: Run command 'dpkg --print-architecture' to identify OS architecture (CPU arch as revealed by ansible_architecture ~= ansible_machine is NO LONGER enough!) + command: dpkg --print-architecture + register: dpkg_arch +- debug: + msg: "'dpkg --print-architecture' output: {{ dpkg_arch.stdout }}" -# ELSE... +- block: -- name: Install MongoDB if 'mongodb_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: mongodb_installed is undefined and not (ansible_architecture == "aarch64" and is_debian_10 and not is_raspbian) + - name: EXIT 'mongodb' ROLE, if 'dpkg --print-architecture' appears to be 32-bit (i.e. does not contain "64") or mongodb_version == "unsupported" or ansible_machine not found + fail: # FORCE IT RED THIS ONCE! + msg: MongoDB 3.2+ (as needed by Sugarizer Server 1.5.0) is NO LONGER SUPPORTED on 32-bit Raspberry Pi OS. + when: not dpkg_arch.stdout is search("64") or mongodb_version == "unsupported" or mongodb_version == "unknown" + #when: dpkg_arch.stdout == "armhf" or mongodb_version == "unsupported" or mongodb_version == "unknown" + - name: Install MongoDB if 'mongodb_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: mongodb_installed is undefined + # when: mongodb_installed is undefined and not (ansible_architecture == "aarch64" and is_debian_10 and not is_raspbian) -- name: Enable or Disable MongoDB, if mongodb_installed is defined (sugarizer.service auto-starts MongoDB as nec, so doesn't need this or care what happens here!) - include_tasks: enable-or-disable.yml - when: mongodb_installed is defined + - name: Enable or Disable MongoDB (FYI sugarizer.service auto-starts MongoDB as nec, so doesn't need this or care what happens here!) + include_tasks: enable-or-disable.yml + - name: Add 'mongodb' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mongodb + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: MongoDB + - option: description + value: '"MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling."' + - option: mongodb_install + value: "{{ mongodb_install }}" + - option: mongodb_enabled + value: "{{ mongodb_enabled }}" -- name: Add 'mongodb' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: mongodb - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: MongoDB - - option: description - value: '"MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling."' - - option: mongodb_install - value: "{{ mongodb_install }}" - - option: mongodb_enabled - value: "{{ mongodb_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/mongodb/templates/iiab-mongodb-repair-if-no-lock.j2 b/roles/mongodb/templates/iiab-mongodb-repair-if-no-lock.j2 index 790748103..433b98c5d 100644 --- a/roles/mongodb/templates/iiab-mongodb-repair-if-no-lock.j2 +++ b/roles/mongodb/templates/iiab-mongodb-repair-if-no-lock.j2 @@ -1,5 +1,7 @@ #!/bin/bash +# 2022-06-07: 100% BOGUS+USELESS with MongoDB 4+ -- SEE mongodb.service & #3236 + if [ -f {{ mongodb_db_lock_file }} ]; then echo '"mongod --repair" cannot run when {{ mongodb_db_lock_file }} present.' >&2 # Output to STDERR but keep going, so /etc/systems/system/mongodb.service continues else diff --git a/roles/mongodb/templates/mongodb.service.j2 b/roles/mongodb/templates/mongodb.service.j2 index 1ae050ae8..6e371da7d 100644 --- a/roles/mongodb/templates/mongodb.service.j2 +++ b/roles/mongodb/templates/mongodb.service.j2 @@ -1,3 +1,40 @@ +# 2022-06-07: IS MongoDB's OFFICIAL /lib/systemd/system/mongod.service USEFUL? + +# [Unit] +# Description=MongoDB Database Server +# Documentation=https://docs.mongodb.org/manual +# After=network-online.target +# Wants=network-online.target + +# [Service] +# User=mongodb +# Group=mongodb +# EnvironmentFile=-/etc/default/mongod +# ExecStart=/usr/bin/mongod --config /etc/mongod.conf +# PIDFile=/var/run/mongodb/mongod.pid +# # file size +# LimitFSIZE=infinity +# # cpu time +# LimitCPU=infinity +# # virtual memory size +# LimitAS=infinity +# # open files +# LimitNOFILE=64000 +# # processes/threads +# LimitNPROC=64000 +# # locked memory +# LimitMEMLOCK=infinity +# # total threads (user+kernel) +# TasksMax=infinity +# TasksAccounting=false + +# # Recommended limits for mongod as specified in +# # https://docs.mongodb.com/manual/reference/ulimit/#recommended-ulimit-settings + +# [Install] +# WantedBy=multi-user.target + + [Unit] Description=High-performance, schema-free document-oriented database After=syslog.target network.target @@ -6,15 +43,22 @@ After=syslog.target network.target Type=simple User=mongodb Group=mongodb -# FAILS (after power failures, etc) as --repair cannot run when lock file exists: (https://github.com/iiab/iiab/issues/942) +{% if not (ansible_architecture == "x86_64" or ansible_architecture == "aarch64") %} +# USED TO FAIL (after power failures, etc) as --repair cannot run when lock file exists: (https://github.com/iiab/iiab/issues/942) #ExecStartPre=/usr/bin/mongod --repair --dbpath /library/dbdata/mongodb # FAILS as systemd cannot run bash here: #ExecStartPre=if [ ! -f /library/dbdata/mongodb/mongod.lock ]; then /usr/bin/mongod --repair --dbpath {{ mongodb_db_path }}; fi +# 2022-06-07: MIGHT STILL BE USEFUL for MongoDB 3.x (i.e. on 32-bit RasPiOS) ExecStartPre=/usr/bin/iiab-mongodb-repair-if-no-lock +{% endif %} ExecStart=/usr/bin/mongod -f {{ mongodb_conf }} -ExecStop=/usr/bin/killall mongod -# killall's SIGTERM (15) seems fine, to induce a graceful stop. This would work too: -#ExecStop=mongod --dbpath {{ mongodb_db_path }} --shutdown +#ExecStop=/usr/bin/killall mongod +# killall's SIGTERM (15) above no longer induces a graceful stop w/ MongoDB 5+ +# https://www.mongodb.com/docs/manual/reference/method/db.shutdownServer/ +# https://www.mongodb.com/docs/v5.0/reference/command/shutdown/ +# https://www.mongodb.com/docs/v6.0/reference/command/shutdown/ +ExecStop=/usr/bin/mongod -f {{ mongodb_conf }} --shutdown +#ExecStop=/usr/bin/mongod --dbpath {{ mongodb_db_path }} --shutdown [Install] WantedBy=multi-user.target diff --git a/roles/monit/tasks/install.yml b/roles/monit/tasks/install.yml index bc6173468..8d523c653 100644 --- a/roles/monit/tasks/install.yml +++ b/roles/monit/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Install 'monit' package package: name: monit @@ -35,6 +40,17 @@ # RECORD Monit AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'monit_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: monit + option: monit_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'monit_installed: True'" set_fact: monit_installed: True diff --git a/roles/monit/tasks/main.yml b/roles/monit/tasks/main.yml index 23340644d..7cc7335f7 100644 --- a/roles/monit/tasks/main.yml +++ b/roles/monit/tasks/main.yml @@ -19,43 +19,53 @@ quiet: yes -# 2019-07-06: The 'monit' package was suddenly removed from Debian 10.0.0 -# "Buster" during the very final days prior to release, as confirmed by the -# sudden disappearance of these 2 pages: -# -# https://packages.debian.org/buster/monit -# https://packages.debian.org/source/buster/monit -# -# And yet Raspbian Buster (is_raspbian_10, which confusingly IIAB declares to -# be is_debian_10 in vars/raspbian-10.yml for now!) still provides 'monit' via -# apt -- so eliminating "Debian 10+" requires this funky conditional: +- block: -# 2020-09-21: The 'monit' package appears to be returning to Debian 11, per: -# -# https://packages.debian.org/bullseye/monit -# https://packages.debian.org/source/bullseye/monit -# -# SEE iiab/iiab#1849 re: "Debian 10 Buster no longer includes Monit" etc. + # 2019-07-06: The 'monit' package was suddenly removed from Debian 10.0.0 + # "Buster" during the very final days prior to release, as confirmed by the + # sudden disappearance of these 2 pages: + # + # https://packages.debian.org/buster/monit + # https://packages.debian.org/source/buster/monit + # + # And yet Raspbian Buster (is_raspbian_10, which confusingly IIAB declares to + # be is_debian_10 in vars/raspbian-10.yml for now!) still provides 'monit' via + # apt -- so eliminating "Debian 10+" requires this funky conditional: -- name: Install Monit if 'monit_installed' not defined, e.g. in {{ iiab_state_file }} AND not Debian 10 # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: monit_installed is undefined and not (is_debian_10 and not is_raspbian) - #when: monit_installed is undefined and not ((is_debian and not is_raspbian) and (not is_debian_8) and (not is_debian_9)) + # 2020-09-21: The 'monit' package appears to be returning to Debian 11, per: + # + # https://packages.debian.org/bullseye/monit + # https://packages.debian.org/source/bullseye/monit + # + # SEE iiab/iiab#1849 re: "Debian 10 Buster no longer includes Monit" etc. + + - name: Install Monit if 'monit_installed' not defined, e.g. in {{ iiab_state_file }} AND not Debian 10 # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: monit_installed is undefined + #when: monit_installed is undefined and not (is_debian_10 and not is_raspbian) + #when: monit_installed is undefined and not ((is_debian and not is_raspbian) and (not is_debian_8) and (not is_debian_9)) -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml -- name: Add 'monit' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: monit - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Monit - - option: description - value: '"Monit is a background service monitor which can correct problems, send email, restart services."' - - option: enabled - value: "{{ monit_enabled }}" + - name: Add 'monit' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: monit + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Monit + - option: description + value: '"Monit is a background service monitor which can correct problems, send email, restart services."' + - option: enabled + value: "{{ monit_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/monit/templates/monitrc.unused b/roles/monit/templates/monitrc.unused index e66b3055c..a269d30d3 100644 --- a/roles/monit/templates/monitrc.unused +++ b/roles/monit/templates/monitrc.unused @@ -65,7 +65,7 @@ set daemon 300 # check services at 5-minute intervals # # ## Send status and events to M/Monit (for more informations about M/Monit -## see http://mmonit.com/). By default Monit registers credentials with +## see https://mmonit.com/). By default Monit registers credentials with ## M/Monit so M/Monit can smoothly communicate back to Monit and you don't ## have to register Monit credentials manually in M/Monit. It is possible to ## disable credential registration using the commented out option below. diff --git a/roles/moodle/defaults/main.yml b/roles/moodle/defaults/main.yml index 23be708e0..a687dc4b4 100644 --- a/roles/moodle/defaults/main.yml +++ b/roles/moodle/defaults/main.yml @@ -7,11 +7,16 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -moodle_version: 311 + +# October 2024: Currently testing Moodle's main branch is mandatory if your +# OS PHP >= 8.4, see moodle/tasks/install.yml for detail! OR, *IF* your +# OS PHP < 8.4, then {{ moodle_version }} will be attempted: +moodle_version: MOODLE_405_STABLE # Moodle 4.5 +#moodle_version: main # e.g. to try Moodle's "weekly" 5.0dev pre-release *EVEN IF* OS PHP < 8.4 moodle_repo_url: https://github.com/moodle/moodle #moodle_repo_url: git://git.moodle.org/moodle.git # 2020-10-16: VERY Slow! -moodle_base: "{{ iiab_base }}/moodle" # /opt/iiab +moodle_base: "{{ iiab_base }}/moodle" # /opt/iiab moodle_data: "{{ content_base }}/moodle" # /library moodle_db_name: moodle diff --git a/roles/moodle/tasks/nginx.yml b/roles/moodle/tasks/enable-or-disable.yml similarity index 53% rename from roles/moodle/tasks/nginx.yml rename to roles/moodle/tasks/enable-or-disable.yml index 65a8eef08..687d6db1e 100644 --- a/roles/moodle/tasks/nginx.yml +++ b/roles/moodle/tasks/enable-or-disable.yml @@ -1,3 +1,18 @@ +- name: "Set 'postgresql_install: True' and 'postgresql_enabled: True'" + set_fact: + postgresql_install: True + postgresql_enabled: True # Revert just below if... + +- name: "Set 'postgresql_enabled: False' if not moodle_enabled" + set_fact: + postgresql_enabled: False + when: not moodle_enabled # and not (pathagar_enabled is defined and pathagar_enabled) + +- name: POSTGRESQL - run 'postgresql' role (Enable&Start or Disable&Stop PostgreSQL) + include_role: + name: postgresql + + - name: Enable http://box/moodle via NGINX, by installing {{ nginx_conf_dir }}/moodle-nginx.conf from template template: src: moodle-nginx.conf.j2 diff --git a/roles/moodle/tasks/install.yml b/roles/moodle/tasks/install.yml index b90c55017..00cf13066 100644 --- a/roles/moodle/tasks/install.yml +++ b/roles/moodle/tasks/install.yml @@ -6,6 +6,20 @@ # 2021-06-28: This ALSO now happens in /etc/php/{{ php_version }}/cli/php.ini # (as required by Moodle's CLI installer, DESPITE it using fpm/php.ini later!) +# 2023-12-17: Upgrade instructions via CLI +# https://docs.moodle.org/en/Administration_via_command_line +# +# EXAMPLE: +# cd /opt/iiab/moodle +# sudo -u www-data /usr/bin/php admin/cli/maintenance.php --enable +# cd /opt/iiab +# mv moodle moodle.bkp +# git clone https://github.com/moodle/moodle -b MOODLE_403_STABLE --depth 1 # As a regular 'git pull' will likely fail, due to original clone's '--depth 1' -- but no worries: total clone download is just ~100 MB, which expands to ~400 MB +# cp moodle.bkp/config.php moodle/ +# cd moodle +# sudo -u www-data /usr/bin/php admin/cli/upgrade.php # Or later log in to Moodle, to complete the upgrade (i.e. click "Continue" 4-5 times) +# sudo -u www-data /usr/bin/php admin/cli/maintenance.php --disable + - name: "Set 'postgresql_install: True' and 'postgresql_enabled: True'" set_fact: @@ -17,6 +31,11 @@ name: postgresql +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 2021-07-02: Let's monitor & learn from these 2 pages year-by-year: # https://docs.moodle.org/19/en/PHP_settings_by_Moodle_version#PHP_Extensions_and_libraries # https://github.com/moodlebox/moodlebox/blob/master/roles/packages/vars/main.yml @@ -30,6 +49,7 @@ #- php{{ php_version }}-common # 2021-06-27: Auto-installed as an apt dependency. REGARDLESS: php{{ php_version }}-common superset php{{ php_version }}-cli is auto-installed by php{{ php_version }}-fpm in nginx/tasks/install.yml #- php{{ php_version }}-cli # 2021-06-27: Compare to php{{ php_version }}-common just above! 2020-06-15: In the past this included (below) mbstring? However this is not true on Ubuntu Server 20.04 LTS. - php{{ php_version }}-curl # 2021-06-27: Likewise installed in nextcloud/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml, wordpress/tasks/install.yml + #- php{{ php_version }}-exif # 2022-11-27: Recommended by Moodle 4.1, possibly required by Moodle 4.2 (for image metadata, rotation, etc?) apt package(s) NOT REQUIRED as it's somehow already installed with PHP's core, as confirmed by 'php -m' & 'php -i' on Ubuntu 22.04 and RasPiOS. - php{{ php_version }}-gd # 2021-06-27: Likewise installed in nextcloud/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml - php{{ php_version }}-intl # 2020-12-03: Required by Moodle 3.10+ -- Likewise installed in mediawiki/tasks/install.yml, nextcloud/tasks/install.yml, wordpress/tasks/install.yml - php{{ php_version }}-mbstring # 2020-06-15: Required by Moodle 3.9+ -- Likewise installed in mediawiki/tasks/install.yml, nextcloud/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml, wordpress/tasks/install.yml @@ -43,14 +63,54 @@ - php{{ php_version }}-zip # 2021-06-27: Likewise installed in nextcloud/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml, wordpress/tasks/install.yml state: present -- name: Download (clone) {{ moodle_repo_url }} to {{ moodle_base }} (~356 MB initially, ~376 MB later) +- name: "Run roles/www_options/tasks/php-settings.yml with 'nginx_high_php_limits: True' by default" + include_tasks: roles/www_options/tasks/php-settings.yml + when: php_settings_done is undefined + + +- name: Does /opt/iiab/moodle exist? + stat: + path: /opt/iiab/moodle + register: opt_iiab_moodle + +# 2023-04-30: Allows re-running (e.g. 'sudo iiab') if git clone was already +# begun, avoiding this error: (arises from 'www-data' ownership) +# "Failed to set a new url https://github.com/moodle/moodle for origin: +# fatal: detected dubious ownership in repository at '/opt/iiab/moodle' +# To add an exception for this directory, call: +# git config --global --add safe.directory /opt/iiab/moodle" + +- name: If /opt/iiab/moodle exists, move it to /tmp/opt-iiab-moodle.old (TO BE DELETED ON NEXT BOOT) -- allows re-running if git clone (below) was already begun + shell: rm -rf /tmp/opt-iiab-moodle.old && mv /opt/iiab/moodle /tmp/opt-iiab-moodle.old + when: opt_iiab_moodle.stat.exists + + +# WARNING: Since March 2023, 32-bit RasPiOS can act as 64-bit on RPi 4 and +# RPi 400 (unlike RPi 3!) SEE: https://github.com/iiab/iiab/pull/3516 +- name: Run command 'dpkg --print-architecture' to identify OS architecture (CPU arch as revealed by ansible_architecture ~= ansible_machine is NO LONGER enough!) + command: dpkg --print-architecture + register: dpkg_arch + +- name: "2023-04-30: MOODLE 4.2+ REQUIRES PHP 8 AND *FULL* 64-BIT OPERATION -- SO WE REVERT TO TRYING THE OLDER MOODLE 4.1 LTS WHEN NECESSARY -- NOTE PHP 7.x END-OF-LIFE WAS NOVEMBER 2022" + set_fact: + moodle_version: MOODLE_401_STABLE # i.e. Moodle 4.1 LTS + when: php_version is version('8.0', '<') or not dpkg_arch.stdout is search("64") + +- name: Download (clone) {{ moodle_repo_url }} branch '{{ moodle_version }}' to {{ moodle_base }} (~476 MB initially, ~504 MB later) if OS PHP {{ php_version }} < 8.4 git: repo: "{{ moodle_repo_url }}" # https://github.com/moodle/moodle dest: "{{ moodle_base }}" # /opt/iiab/moodle depth: 1 - version: "MOODLE_{{ moodle_version }}_STABLE" - #version: master # TEMPORARY DURING MAY 2018 TESTING, installed 3.5beta+ = https://download.moodle.org/releases/development/ - #ignore_errors: yes + version: "{{ moodle_version }}" # e.g. MOODLE_404_STABLE (Moodle 4.4) + when: php_version is version('8.4', '<') + +- name: "MOODLE PRE-RELEASE TESTING: Download (clone) {{ moodle_repo_url }} branch 'main' to {{ moodle_base }} (~476 MB initially, ~504 MB later) if OS PHP {{ php_version }} >= 8.4" + git: + repo: "{{ moodle_repo_url }}" + dest: "{{ moodle_base }}" + depth: 1 + version: main # For "weekly" Moodle pre-releases: https://download.moodle.org/releases/development/ (e.g. 3.5beta+ in May 2018, 4.1dev in Sept 2022, 4.2dev in Dec 2022, 4.3dev in May 2023, 4.4dev in Oct 2023, 4.5dev in Apr 2024, 5.0dev in Oct 2024) + when: php_version is version('8.4', '>=') - name: chown -R {{ apache_user }}:{{ apache_user }} {{ moodle_base }} (by default dirs 755 & files 644) file: @@ -128,7 +188,7 @@ # 2021-11-19: Resolves Moodle error https://github.com/iiab/iiab/issues/3024 - name: Set cron job to run /opt/iiab/moodle/admin/cli/cron.php every minute (* * * * *) in /var/spool/cron/crontabs/www-data -- per https://docs.moodle.org/310/en/Cron cron: - name: https://docs.moodle.org/310/en/Cron + name: https://docs.moodle.org/en/Cron user: www-data job: "/usr/bin/php /opt/iiab/moodle/admin/cli/cron.php >/dev/null" @@ -154,6 +214,17 @@ # RECORD Moodle AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'moodle_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: moodle + option: moodle_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'moodle_installed: True'" set_fact: moodle_installed: True diff --git a/roles/moodle/tasks/main.yml b/roles/moodle/tasks/main.yml index 5c4e6bf73..aeb40556f 100644 --- a/roles/moodle/tasks/main.yml +++ b/roles/moodle/tasks/main.yml @@ -19,44 +19,35 @@ quiet: yes -- name: Install Moodle if 'moodle_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: moodle_installed is undefined +- block: + - name: Install Moodle if 'moodle_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: moodle_installed is undefined -- name: "Set 'postgresql_install: True' and 'postgresql_enabled: True'" - set_fact: - postgresql_install: True - postgresql_enabled: True # Revert just below if... + - include_tasks: enable-or-disable.yml -- name: "Set 'postgresql_enabled: False' if not moodle_enabled" - set_fact: - postgresql_enabled: False - when: not moodle_enabled # and not (pathagar_enabled is defined and pathagar_enabled) + - name: Add 'moodle' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: moodle + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Moodle + - option: description + value: '"Access the Moodle learning management system."' + - option: moodle_install + value: "{{ moodle_install }}" + - option: moodle_enabled + value: "{{ moodle_enabled }}" + - option: moodle_base + value: "{{ moodle_base }}" -- name: POSTGRESQL - run 'postgresql' role (Enable&Start or Disable&Stop PostgreSQL) - include_role: - name: postgresql + rescue: - -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml - - -- name: Add 'moodle' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: moodle - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Moodle - - option: description - value: '"Access the Moodle learning management system."' - - option: moodle_install - value: "{{ moodle_install }}" - - option: moodle_enabled - value: "{{ moodle_enabled }}" - - option: moodle_base - value: "{{ moodle_base }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/moodle/templates/moodle-nginx.conf.j2 b/roles/moodle/templates/moodle-nginx.conf.j2 index 135096c5b..f6077f50c 100644 --- a/roles/moodle/templates/moodle-nginx.conf.j2 +++ b/roles/moodle/templates/moodle-nginx.conf.j2 @@ -29,7 +29,7 @@ location ~ ^/moodle(.*)\.php(.*)$ { # Uncomment to override /etc/php//fpm/php.ini -- FYI Stage 4's # roles/www_options/tasks/main.yml FORCES these same settings and more # (equivalent to 'nginx_high_php_limits: True') when 'moodle_install: True' - #fastcgi_param PHP_VALUE "max_execution_time=300\n upload_max_filesize=500M\n post_max_size=500M\n max_input_vars=5000"; + #fastcgi_param PHP_VALUE "max_execution_time=300\n upload_max_filesize=10000M\n post_max_size=10000M\n max_input_vars=5000"; } location ~ ^/moodle { diff --git a/roles/mosquitto/README.rst b/roles/mosquitto/README.rst index 098ff2831..7ccb29f97 100644 --- a/roles/mosquitto/README.rst +++ b/roles/mosquitto/README.rst @@ -9,7 +9,7 @@ Roughly follows this guide: https://www.digitalocean.com/community/tutorials/how Using It -------- -Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: +Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: mosquitto_install: True mosquitto_enabled: True diff --git a/roles/mosquitto/tasks/install.yml b/roles/mosquitto/tasks/install.yml index 6ba7fd0d0..d4b7271a0 100644 --- a/roles/mosquitto/tasks/install.yml +++ b/roles/mosquitto/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Install packages: mosquitto, mosquitto-clients" package: name: "{{ item }}" @@ -32,6 +37,17 @@ # RECORD Mosquitto AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'mosquitto_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mosquitto + option: mosquitto_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'mosquitto_installed: True'" set_fact: mosquitto_installed: True diff --git a/roles/mosquitto/tasks/main.yml b/roles/mosquitto/tasks/main.yml index dd953d37a..1d38ab229 100644 --- a/roles/mosquitto/tasks/main.yml +++ b/roles/mosquitto/tasks/main.yml @@ -19,26 +19,33 @@ quiet: yes -- name: Install Mosquitto if 'mosquitto_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: mosquitto_installed is undefined +- block: + - name: Install Mosquitto if 'mosquitto_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: mosquitto_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'mosquitto' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mosquitto + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Mosquitto service + - option: description + value: '"Mosquitto (uses the MQTT protocol) is a pub-sub broker for electronics projects and educational Internet of Things (IoT) experiments. It''s designed for TCP/IP with remote locations where a ''small code footprint'' is required or bandwidth is limited. See also: Node-RED"' + - option: mosquitto_install + value: "{{ mosquitto_install }}" + - option: mosquitto_enabled + value: "{{ mosquitto_enabled }}" -- name: Add 'mosquitto' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: mosquitto - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Mosquitto service - - option: description - value: '"Mosquitto (uses the MQTT protocol) is a pub-sub broker for electronics projects and educational Internet of Things (IoT) experiments. It''s designed for TCP/IP with remote locations where a ''small code footprint'' is required or bandwidth is limited. See also: Node-RED"' - - option: mosquitto_install - value: "{{ mosquitto_install }}" - - option: mosquitto_enabled - value: "{{ mosquitto_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/munin/tasks/enable-or-disable.yml b/roles/munin/tasks/enable-or-disable.yml new file mode 100644 index 000000000..fce74cae5 --- /dev/null +++ b/roles/munin/tasks/enable-or-disable.yml @@ -0,0 +1,44 @@ +# SEE ALSO roles/network/tasks/install.yml +- name: TEMPORARILY REVERT net.ipv6.conf.all.disable_ipv6 to 0 in /etc/sysctl.conf for #3434 + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: 0 + +- name: Enable & Start 'munin-node' systemd service + systemd: + name: munin-node + daemon_reload: yes + enabled: yes + state: started + when: munin_enabled + +# SEE ALSO roles/network/tasks/install.yml +- name: RESTORE net.ipv6.conf.all.disable_ipv6 to 1 in /etc/sysctl.conf for #3434 + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: 1 + +- name: Disable & Stop 'munin-node' systemd service + systemd: + name: munin-node + enabled: no + state: stopped + when: not munin_enabled + + +- name: Enable http://box/munin via NGINX, by installing {{ nginx_conf_dir }}/munin24-nginx.conf from template + template: + src: munin24-nginx.conf.j2 + dest: "{{ nginx_conf_dir }}/munin24-nginx.conf" # /etc/nginx/conf.d + when: munin_enabled + +- name: Disable http://box/munin via NGINX, by installing {{ nginx_conf_dir }}/munin24-nginx.conf + file: + path: "{{ nginx_conf_dir }}/munin24-nginx.conf" # /etc/nginx/conf.d + state: absent + when: not munin_enabled + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/munin/tasks/install.yml b/roles/munin/tasks/install.yml index 7d439ff5a..89fe254cf 100644 --- a/roles/munin/tasks/install.yml +++ b/roles/munin/tasks/install.yml @@ -1,4 +1,15 @@ -- name: "Install 5 packages: libcgi-fast-perl, munin, munin-node, munin-plugins-extra, python3-passlib" +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# SEE ALSO roles/network/tasks/install.yml +- name: "TEMPORARILY REVERT net.ipv6.conf.all.disable_ipv6 to 0 in /etc/sysctl.conf for #3434" + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: 0 + +- name: "Install 4 packages: libcgi-fast-perl, munin, munin-node, munin-plugins-extra" package: name: #- libapache2-mod-fcgid @@ -6,16 +17,28 @@ - munin - munin-node - munin-plugins-extra - - python3-passlib # For Ansible module 'htpasswd' in Ansible collection community.general -- used just below + #- python3-passlib # For Ansible module 'htpasswd' in Ansible collection community.general -- used just below state: present +- name: pip install 'passlib' into venv /usr/local/ansible -- for Ansible module 'htpasswd' in Ansible collection community.general -- used just below + pip: + name: passlib + virtualenv: /usr/local/ansible + extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560 + +# SEE ALSO roles/network/tasks/install.yml +- name: RESTORE net.ipv6.conf.all.disable_ipv6 to 1 in /etc/sysctl.conf for #3434 + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: 1 + - name: Establish username/password Admin/changeme in /etc/munin/munin-htpasswd htpasswd: path: /etc/munin/munin-htpasswd name: "{{ munin_username}}" # Admin password: "{{ munin_password }}" # changeme -- name: If MySQL is enabled, let Munin monitor it +- name: If MySQL is installed, let Munin monitor it copy: src: "{{ item }}" dest: /etc/munin/plugins/ @@ -27,11 +50,23 @@ - /usr/share/munin/plugins/mysql_queries - /usr/share/munin/plugins/mysql_slowqueries - /usr/share/munin/plugins/mysql_threads - when: mysql_enabled + when: mysql_installed + #when: mysql_enabled # RECORD Munin AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'munin_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: munin + option: munin_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'munin_installed: True'" set_fact: munin_installed: True diff --git a/roles/munin/tasks/main.yml b/roles/munin/tasks/main.yml index 22a07119a..0ff168fa5 100644 --- a/roles/munin/tasks/main.yml +++ b/roles/munin/tasks/main.yml @@ -19,42 +19,33 @@ quiet: yes -- name: Install Munin if 'munin_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: munin_installed is undefined +- block: + - name: Install Munin if 'munin_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: munin_installed is undefined -- name: Enable & Start 'munin-node' systemd service - systemd: - name: munin-node - daemon_reload: yes - enabled: yes - state: started - when: munin_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'munin-node' systemd service - systemd: - name: munin-node - enabled: no - state: stopped - when: not munin_enabled + - name: Add 'munin' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: munin + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Munin + - option: description + value: '"Munin is a networked resource monitoring tool that can help analyze resource trends and ''what just happened to kill our performance?'' problems."' + - option: munin_install + value: "{{ munin_install }}" + - option: munin_enabled + value: "{{ munin_enabled }}" -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + rescue: - -- name: Add 'munin' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: munin - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Munin - - option: description - value: '"Munin is a networked resource monitoring tool that can help analyze resource trends and ''what just happened to kill our performance?'' problems."' - - option: munin_install - value: "{{ munin_install }}" - - option: munin_enabled - value: "{{ munin_enabled }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/munin/tasks/nginx.yml b/roles/munin/tasks/nginx.yml deleted file mode 100644 index cd1094451..000000000 --- a/roles/munin/tasks/nginx.yml +++ /dev/null @@ -1,16 +0,0 @@ -- name: Enable http://box/munin via NGINX, by installing {{ nginx_conf_dir }}/munin24-nginx.conf from template - template: - src: munin24-nginx.conf.j2 - dest: "{{ nginx_conf_dir }}/munin24-nginx.conf" # /etc/nginx/conf.d - when: munin_enabled - -- name: Disable http://box/munin via NGINX, by installing {{ nginx_conf_dir }}/munin24-nginx.conf - file: - path: "{{ nginx_conf_dir }}/munin24-nginx.conf" # /etc/nginx/conf.d - state: absent - when: not munin_enabled - -- name: Restart 'nginx' systemd service - systemd: - name: nginx - state: restarted diff --git a/roles/mysql/tasks/enable-or-disable.yml b/roles/mysql/tasks/enable-or-disable.yml new file mode 100644 index 000000000..ac06c0c8c --- /dev/null +++ b/roles/mysql/tasks/enable-or-disable.yml @@ -0,0 +1,15 @@ +- name: Enable & Start MySQL ({{ mysql_service }}) systemd service, if mysql_enabled + systemd: + name: "{{ mysql_service }}" + daemon_reload: yes + state: started + enabled: yes + when: mysql_enabled + +# We had to start MySQL in order to configure it, now turn if off if not enabled +- name: Disable & Stop MySQL ({{ mysql_service }}) systemd service, if not mysql_enabled + systemd: + name: "{{ mysql_service }}" + enabled: no + state: stopped + when: not mysql_enabled diff --git a/roles/mysql/tasks/install.yml b/roles/mysql/tasks/install.yml index ceff65c66..1b8a04388 100644 --- a/roles/mysql/tasks/install.yml +++ b/roles/mysql/tasks/install.yml @@ -1,13 +1,24 @@ -- name: 'Install MySQL packages: mariadb-server, mariadb-client, php{{ php_version }}-mysql, python3-pymysql' +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: 'Install MySQL packages: mariadb-server, mariadb-client, php{{ php_version }}-mysql' package: name: - mariadb-server - mariadb-client #- php{{ php_version }}-common # Auto-installed as an apt dependency. REGARDLESS: php{{ php_version }}-common superset php{{ php_version }}-cli is auto-installed by php{{ php_version }}-fpm in nginx/tasks/install.yml - php{{ php_version }}-mysql # Likewise installed in nextcloud/tasks/install.yml, pbx/tasks/freepbx.yml, wordpress/tasks/install.yml - - python3-pymysql # For Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in MySQL roles {mediawiki, nextcloud, wordpress} and possibly {elgg, pbx} + #- python3-pymysql # For Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in MySQL roles {mediawiki, nextcloud, wordpress} and possibly {elgg, pbx} state: present +- name: pip install 'PyMySQL' into venv /usr/local/ansible -- for Ansible modules {mysql_db, mysql_user} in Ansible collection community.mysql -- used in roles {mediawiki, nextcloud, wordpress, matomo, pbx} + pip: + name: PyMySQL + virtualenv: /usr/local/ansible + extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560 + # 2020-07-11: 10 PHP package installs moved to roles/www_base/tasks/main.yml # php{{ php_version }}-sqlite3 install moved to roles/osm-vector-maps/tasks/install.yml @@ -61,6 +72,17 @@ # RECORD MySQL AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'mysql_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mysql + option: mysql_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'mysql_installed: True'" set_fact: mysql_installed: True diff --git a/roles/mysql/tasks/main.yml b/roles/mysql/tasks/main.yml index 789d406c1..d91bbce14 100644 --- a/roles/mysql/tasks/main.yml +++ b/roles/mysql/tasks/main.yml @@ -26,40 +26,33 @@ var: mysql_installed -- name: Install MySQL if 'mysql_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: mysql_installed is undefined +- block: + - name: Install MySQL if 'mysql_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: mysql_installed is undefined -- name: Enable & Start MySQL ({{ mysql_service }}) systemd service, if mysql_enabled - systemd: - name: "{{ mysql_service }}" - daemon_reload: yes - state: started - enabled: yes - when: mysql_enabled + - include_tasks: enable-or-disable.yml -# We had to start MySQL in order to configure it, now turn if off if not enabled -- name: Disable & Stop MySQL ({{ mysql_service }}) systemd service, if not mysql_enabled - systemd: - name: "{{ mysql_service }}" - enabled: no - state: stopped - when: not mysql_enabled + - name: Add 'mysql' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: mysql + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: MySQL + - option: description + value: '"MySQL is a widely used free and open source (GPLv2) database, offered by most web hosting services, on a diversity of platforms."' + - option: mysql_install + value: "{{ mysql_install }}" + - option: mysql_enabled + value: "{{ mysql_enabled }}" + rescue: -- name: Add 'mysql' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: mysql - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: MySQL - - option: description - value: '"MySQL is a widely used free and open source (GPLv2) database, offered by most web hosting services, on a diversity of platforms."' - - option: mysql_install - value: "{{ mysql_install }}" - - option: mysql_enabled - value: "{{ mysql_enabled }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/network/README.rst b/roles/network/README.rst index cbe01f450..a95e247ff 100644 --- a/roles/network/README.rst +++ b/roles/network/README.rst @@ -2,13 +2,15 @@ Network README ============== -This is run by `Ansible `_ after it has installed the core (`Stages 0-to-9 `_) of `Internet-in-a-Box (IIAB) `_ and its apps/services. +This is run by `Ansible `_ after it has installed the core (`Stages 0-to-9 `_) of `Internet-in-a-Box (IIAB) `_ and its apps/services. Specifically, this 'network' role is run... - ...automatically during IIAB installation, after `/opt/iiab/iiab/iiab-install <../../iiab-install>`_ has run `Stages 0-to-9 <..>`_ (thanks to `iiab-stages.yml <../../iiab-stages.yml>`_). - ...automatically by IIAB's **Admin Console** (http://box/admin) if you click **Configure** -> **Install Configured Options** β€” this is similar to the above, but only runs Stage 0, then Stage 4-to-9, and then finally this 'network' role/stage (thanks to `iiab-from-console.yml <../../iiab-from-console.yml>`_). -- ...or manually, if you run ``cd /opt/iiab/iiab`` then `sudo ./iiab-network <../../iiab-network>`_ (which is much the same as running ``sudo ./runrole network``). +- ...or manually, if you run `sudo iiab-network <../../scripts/iiab-network>`_ + - A stronger version is also available if necessary: ``cd /opt/iiab/iiab`` then ``sudo ./runrole --reinstall network`` + - If your IIAB was installed prior to August 2022, instead run: ``cd /opt/iiab/iiab`` then `sudo ./iiab-network <../../iiab-network>`_ (which is much the same as running ``sudo ./runrole network``). Many IIAB networking questions can be answered in these 2 documents: diff --git a/roles/network/defaults/main.yml b/roles/network/defaults/main.yml index f647af6ec..593f14922 100644 --- a/roles/network/defaults/main.yml +++ b/roles/network/defaults/main.yml @@ -27,6 +27,7 @@ # hostapd_enabled: True # Above set in /opt/iiab/iiab/vars/default_vars.yml + hostapd_wait: 10 host_wireless_n: False driver_name: nl80211 @@ -54,20 +55,24 @@ strict_networking: False iiab_demo_mode: False gui_static_wan: False wan_cidr: "" -virtual_network_devices: "-e ap0 -e lo -e br0 -e tun -e br- -e docker -e bridge0 -e veth" +virtual_network_devices: "-e wwlan -e ppp -e ap0 -e lo -e br0 -e tun -e br- -e docker -e bridge0 -e veth -e tailscale0" # Set defaults for discovery process as strings wifi1: "not found-1" wifi2: "not found-2" +can_be_ap: False exclude_devices: none device_gw: none prior_gw_device: unset - +# 2022-06-29: Legacy vars no longer used by roles/0-init +discovered_wan_iface: none # 2021-07-30: Very broadly used! iiab_wan_iface: none iiab_lan_iface: none discovered_lan_iface: none discovered_wired_iface: none discovered_wireless_iface: none +# use the same case as what `iw reg get` would return with 00 present +host_country_code_found: UNSET # Red Hat #iiab_wired_lan_iface: "none" diff --git a/roles/network/tasks/NM-debian.yml b/roles/network/tasks/NM-debian.yml index 8cf977c8a..a0af7adcc 100644 --- a/roles/network/tasks/NM-debian.yml +++ b/roles/network/tasks/NM-debian.yml @@ -1,6 +1,6 @@ # NM-debian.yml -- name: Stopping services - include_tasks: down-debian.yml +#- name: Stopping services +# include_tasks: down-debian.yml # provide keyfile layout like the XO's used way back. #- name: Create uuid for NM's keyfile store @@ -22,7 +22,7 @@ dest: /etc/NetworkManager/conf.d/ap0-manage.conf src: network/ap0-manage.conf mode: 0644 - when: wifi_up_down + when: discovered_wireless_iface != "none" and wifi_up_down - name: Copy manage.conf for NetworkManager when wifi_up_down False template: @@ -71,13 +71,14 @@ when: wan_ip != "dhcp" - name: Use systemd-networkd to handle br0 - include_tasks: sysd-netd-debian.yml - when: iiab_lan_iface == "br0" and not systemd_networkd_active + set_fact: + systemd_networkd_active: True + when: iiab_lan_iface == "br0" - name: Reload systemd systemd: daemon_reload: yes - when: not iiab_lan_iface == "br0" + when: not no_net_restart or not iiab_lan_iface == "br0" - name: Restart the NetworkManager service systemd: diff --git a/roles/network/tasks/avahi.yml b/roles/network/tasks/avahi.yml index 15a62de8e..cfa382d72 100644 --- a/roles/network/tasks/avahi.yml +++ b/roles/network/tasks/avahi.yml @@ -1,13 +1,13 @@ -- name: Create a user for avahi (debuntu) +- name: Create user 'avahi' user: name: avahi createhome: no shell: /bin/false - when: is_debuntu + #when: is_debuntu - name: Install avahi announce config file /etc/avahi/services/schoolserver.service template: - src: avahi/schoolserver.service + src: roles/network/templates/avahi/schoolserver.service # Invoked by 1-prep (so full path needed) dest: /etc/avahi/services/schoolserver.service owner: avahi group: avahi @@ -20,24 +20,24 @@ # IF >= 2, Admin Console $gui_port from 0-init determines which port (http-or-https) is opened here: # https://github.com/iiab/iiab/blob/master/roles/network/templates/gateway/iiab-gen-iptables#L133-L138 -- name: Find avahi_ver for clean copy of ssh.service (not debuntu) - shell: "ls /usr/share/doc/ | grep avahi | head -n1" - register: avahi_ver - ignore_errors: True - changed_when: False - # when: not is_debuntu # would cause failures 6 lines below +# - name: Find avahi_ver for clean copy of ssh.service (not debuntu) +# shell: "ls /usr/share/doc/ | grep avahi | head -n1" +# register: avahi_ver +# ignore_errors: True +# changed_when: False +# # when: not is_debuntu # would cause failures 6 lines below -- name: Grab a clean copy of ssh.service (not debuntu) - copy: - src: '/usr/share/doc/{{ avahi_ver.stdout }}/ssh.service' - dest: /etc/avahi/services/ - when: avahi_ver.stdout != "" and not is_debuntu +# - name: Grab a clean copy of ssh.service (not debuntu) +# copy: +# src: '/usr/share/doc/{{ avahi_ver.stdout }}/ssh.service' +# dest: /etc/avahi/services/ +# when: avahi_ver.stdout != "" and not is_debuntu -- name: Grab a clean copy of ssh.service (debuntu) +- name: Grab a clean copy of ssh.service copy: src: /usr/share/doc/avahi-daemon/examples/ssh.service dest: /etc/avahi/services/ - when: is_debuntu + #when: is_debuntu - name: Set ssh port for avahi lineinfile: diff --git a/roles/network/tasks/computed_network.yml b/roles/network/tasks/computed_network.yml index 730274380..8c7ac5515 100644 --- a/roles/network/tasks/computed_network.yml +++ b/roles/network/tasks/computed_network.yml @@ -158,17 +158,19 @@ option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: - - option: iiab_wan_enabled - value: "{{ iiab_wan_enabled }}" - - option: user_wan_iface - value: "{{ user_wan_iface }}" - - option: iiab_wan_iface - value: "{{ iiab_wan_iface }}" - - option: iiab_lan_enabled - value: "{{ iiab_lan_enabled }}" - - option: user_lan_iface - value: "{{ user_lan_iface }}" - - option: iiab_lan_iface - value: "{{ iiab_lan_iface }}" - - option: iiab_network_mode - value: "{{ iiab_network_mode }}" + - option: iiab_wan_enabled + value: "{{ iiab_wan_enabled }}" + - option: user_wan_iface + value: "{{ user_wan_iface }}" + - option: iiab_wan_iface + value: "{{ iiab_wan_iface }}" + - option: iiab_lan_enabled + value: "{{ iiab_lan_enabled }}" + - option: user_lan_iface + value: "{{ user_lan_iface }}" + - option: iiab_lan_iface + value: "{{ iiab_lan_iface }}" + - option: iiab_network_mode + value: "{{ iiab_network_mode }}" + - option: network_enabled + value: "{{ network_enabled }}" diff --git a/roles/network/tasks/computed_services.yml b/roles/network/tasks/computed_services.yml index 47c3cd7cc..2a113ce15 100644 --- a/roles/network/tasks/computed_services.yml +++ b/roles/network/tasks/computed_services.yml @@ -20,35 +20,35 @@ iiab_network_mode: "Gateway" when: iiab_lan_iface != "none" and iiab_wan_iface != "none" -- name: No LAN configured - non-dnsmasq - set_fact: - named_enabled: True - dhcpd_enabled: False - dhcp_service2: "dhcpd disabled" - when: not dnsmasq_enabled and iiab_network_mode == "Appliance" +#- name: No LAN configured - non-dnsmasq +# set_fact: +# named_enabled: True +# dhcpd_enabled: False +# dhcp_service2: "dhcpd disabled" +# when: not dnsmasq_enabled and iiab_network_mode == "Appliance" -- name: LAN configured - non-dnsmasq - set_fact: - named_enabled: True - dhcpd_enabled: True - dhcp_service2: "dhcpd" - when: not dnsmasq_enabled and iiab_network_mode != "Appliance" +#- name: LAN configured - non-dnsmasq +# set_fact: +# named_enabled: True +# dhcpd_enabled: True +# dhcp_service2: "dhcpd" +# when: not dnsmasq_enabled and iiab_network_mode != "Appliance" -- name: LAN configured - dnsmasq - set_fact: - named_enabled: False - dhcpd_enabled: False - dnsmasq_enabled: True - dhcp_service2: "dnsmasq" - when: dnsmasq_install and iiab_network_mode != "Appliance" +#- name: LAN configured - dnsmasq +# set_fact: +# named_enabled: False +# dhcpd_enabled: False +# dnsmasq_enabled: True +# dhcp_service2: "dnsmasq" +# when: dnsmasq_install and iiab_network_mode != "Appliance" -- name: LAN not configured - dnsmasq - set_fact: - named_enabled: False - dhcpd_enabled: False - dnsmasq_enabled: True - dhcp_service2: "dnsmasq" - when: dnsmasq_install and iiab_network_mode == "Appliance" +#- name: LAN not configured - dnsmasq +# set_fact: +# named_enabled: False +# dhcpd_enabled: False +# dnsmasq_enabled: True +# dhcp_service2: "dnsmasq" +# when: dnsmasq_install and iiab_network_mode == "Appliance" - name: Add 'network' variable values (from computed_services.yml) to {{ iiab_ini_file }} ini_file: @@ -71,32 +71,13 @@ # value: "{{ wondershaper_enabled }}" - option: iiab_network_mode_applied value: "{{ iiab_network_mode }}" - - option: dhcpd_enabled - value: "{{ dhcpd_enabled }}" - - option: dhcp_service2 - value: "{{ dhcp_service2 }}" - - option: named_enabled - value: "{{ named_enabled }}" +# - option: dhcpd_enabled +# value: "{{ dhcpd_enabled }}" +# - option: dhcp_service2 +# value: "{{ dhcp_service2 }}" +# - option: named_enabled +# value: "{{ named_enabled }}" - option: dnsmasq_enabled value: "{{ dnsmasq_enabled }}" - option: no_net_restart value: "{{ no_net_restart }}" - - option: hostapd_enabled - value: "{{ hostapd_enabled }}" - - option: host_ssid - value: "{{ host_ssid }}" - - option: host_wifi_mode - value: "{{ host_wifi_mode }}" - - option: host_channel - value: "{{ host_channel }}" - -- name: Add 'network' variable 'current_client_channel' value if defined, to {{ iiab_ini_file }} - ini_file: - dest: "{{ iiab_ini_file }}" - section: network - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: client_wifi_channel - value: "{{ current_client_channel.stdout }}" - when: current_client_channel.stdout is defined diff --git a/roles/network/tasks/debian.yml b/roles/network/tasks/debian.yml index 74ca452c7..3cc21d7ee 100644 --- a/roles/network/tasks/debian.yml +++ b/roles/network/tasks/debian.yml @@ -53,16 +53,18 @@ template: dest: /etc/network/interfaces.d/patch_auto src: network/debian-auto.j2 - when: iiab_wan_iface != "none" and is_debian and not is_debian_8 + when: iiab_wan_iface != "none" and is_debian + #when: iiab_wan_iface != "none" and is_debian and not is_debian_8 - name: Clearing out /etc/network/interfaces for static addresses (debian-9+) lineinfile: state: absent path: /etc/network/interfaces regexp: "{{ iiab_wan_iface }}" - when: wan_ip != "dhcp" and iiab_wan_iface != "none" and is_debian and not is_debian_8 + when: wan_ip != "dhcp" and iiab_wan_iface != "none" and is_debian + #when: wan_ip != "dhcp" and iiab_wan_iface != "none" and is_debian and not is_debian_8 -- include_tasks: down-debian.yml +#- include_tasks: down-debian.yml - name: Reload systemd systemd: diff --git a/roles/network/tasks/detected_network.yml b/roles/network/tasks/detected_network.yml index fec38c805..c72028d53 100644 --- a/roles/network/tasks/detected_network.yml +++ b/roles/network/tasks/detected_network.yml @@ -1,3 +1,13 @@ +# Similar code block in roles/vnstat/tasks/install.yml +- name: Do we have a gateway? If 'ip route' specifies a default route, Ansible parses details here... + debug: + var: ansible_default_ipv4 + +- name: "If above ansible_default_ipv4.gateway is defined, set WAN candidate 'discovered_wan_iface: {{ ansible_default_ipv4.alias }}' -- using ansible_default_ipv4.alias" + set_fact: + discovered_wan_iface: "{{ ansible_default_ipv4.alias }}" + when: ansible_default_ipv4.gateway is defined + # so this works - name: Interface count shell: ls /sys/class/net | grep -v {{ virtual_network_devices }} | wc | awk '{print $1}' @@ -26,25 +36,22 @@ device_gw: "{{ discovered_wan_iface }}" when: ansible_default_ipv4.gateway is defined -- name: Figure out netplan file name - shell: ls /etc/netplan - register: netplan - ignore_errors: True # pre 17.10 doesn't use netplan - when: is_ubuntu +# 2022-07-22: Moved to netplan.yml AND restart.yml (REMOVE DUPLICATE CODE LATER?!) +# - name: Figure out netplan file name +# shell: ls /etc/netplan +# register: netplan +# ignore_errors: True # pre 17.10 doesn't use netplan +# when: is_ubuntu - name: Setting dhcpcd_test results set_fact: dhcpcd_result: "{{ ansible_local.local_facts.dhcpcd }}" -- name: Setting systemd_networkd results +# 2022-07-22: Copied to netplan.yml (REMOVE DUPLICATE CODE LATER?!) +- name: "Set 'systemd_networkd_active: True' if local_facts.systemd_networkd confirms" set_fact: systemd_networkd_active: True - when: 'ansible_local.local_facts.systemd_networkd == "enabled"' - -- name: Setting systemd_networkd-2 results - set_fact: - systemd_networkd_active: True - when: 'ansible_local.local_facts.systemd_networkd == "enabled-runtime"' + when: ansible_local.local_facts.systemd_networkd == "enabled" or ansible_local.local_facts.systemd_networkd == "enabled-runtime" - name: Setting network_manager results set_fact: @@ -53,13 +60,14 @@ - name: Check /etc/network/interfaces for gateway shell: grep {{ device_gw }} /etc/network/interfaces | wc -l - when: is_debuntu + #when: is_debuntu register: wan_file - name: Setting wan_in_interfaces set_fact: wan_in_interfaces: True - when: is_debuntu and (wan_file.stdout|int > 0) + when: wan_file.stdout|int > 0 + #when: is_debuntu and (wan_file.stdout|int > 0) # WIRELESS -- if any wireless is detected as gateway, it becomes WAN - name: Look for any wireless interfaces @@ -101,12 +109,31 @@ set_fact: num_wifi_interfaces: "{{ count_wifi_interfaces.stdout|int }}" +- block: + - name: Run 'iw list' to check for Access Point capability -- if discovered_wireless_iface ({{ discovered_wireless_iface }}) != "none" + # shell: iw list | grep -v AP: | grep AP | wc -l # False positives 'EAP' etc + shell: iw list | grep '^[[:space:]]*\* AP$' # If grep doesn't find the regex, it returns 1 (hence 'ignore_errors: yes' 9 lines below) + register: look_for_ap + when: discovered_wireless_iface != "none" # Line not nec (but can't hurt?) + # failed_when: False # Hides red errors and is too strong (renders useless the look_for_ap.failed test below!) + + rescue: # Force another red error msg (to explain) then proceed + - name: WiFi chipset/firmware NOT CAPABLE of AP Mode (details above) + fail: + msg: WiFi chipset/firmware NOT CAPABLE of AP Mode (details above) + ignore_errors: yes + +- name: "Set 'can_be_ap: True' if 'iw list' output contains suitable '* AP'" + set_fact: + can_be_ap: True + when: look_for_ap.failed is defined and not look_for_ap.failed + - name: Detect wifi gateway active shell: ip r | grep default | grep {{ discovered_wireless_iface }} | wc -l register: wifi_gateway_found when: discovered_wireless_iface != "none" -- name: Set has_wifi_gateway if WiFi has default gateway detected for {{ discovered_wireless_iface }} +- name: "Set 'has_wifi_gateway: True' if WiFi has default gateway detected for discovered_wireless_iface ({{ discovered_wireless_iface }}) -- otherwise leave it undefined" set_fact: has_wifi_gateway: True when: discovered_wireless_iface != "none" and (wifi_gateway_found.stdout|int > 0) @@ -116,6 +143,11 @@ register: second_gateway_found changed_when: False +- name: If multiple secondary gateways are detected, fail intentionally and explain + fail: + msg: "IIAB currently DOES NOT SUPPORT multiple secondary gateways: {{ second_gateway_found.stdout }}" + when: second_gateway_found.stdout_lines is defined and second_gateway_found.stdout_lines | length > 1 + - name: Set exclude_devices if default gateway has been detected for {{ second_gateway_found.stdout }} set_fact: exclude_devices: "{{ second_gateway_found.stdout }}" @@ -135,7 +167,7 @@ when: reserved_device is defined - name: Count LAN ifaces - shell: ls /sys/class/net | grep -v {{ virtual_network_devices }} -e wwlan -e ppp -e {{ device_gw }} -e {{ exclude_devices }} | wc -l + shell: ls /sys/class/net | grep -v {{ virtual_network_devices }} -e {{ discovered_wireless_iface }} -e {{ device_gw }} -e {{ exclude_devices }} | wc -l register: num_lan_interfaces_result - name: Calculate number of LAN interfaces including WiFi @@ -144,7 +176,7 @@ # LAN - pick non WAN's - name: Create list of LAN (non WAN) ifaces - shell: ls /sys/class/net | grep -v {{ virtual_network_devices }} -e wwlan -e ppp -e {{ device_gw }} -e {{ exclude_devices }} + shell: ls /sys/class/net | grep -v {{ virtual_network_devices }} -e {{ discovered_wireless_iface }} -e {{ device_gw }} -e {{ exclude_devices }} when: num_lan_interfaces != "0" register: lan_list_result @@ -165,7 +197,7 @@ with_items: - "{{ lan_list_result.stdout_lines }}" -- name: Set iiab_wireless_lan_iface to {{ discovered_wireless_iface }} if not none +- name: Set iiab_wireless_lan_iface to discovered_wireless_iface ({{ discovered_wireless_iface }}) if not none set_fact: iiab_wireless_lan_iface: "{{ discovered_wireless_iface }}" when: discovered_wireless_iface != "none" and not wifi_up_down @@ -189,7 +221,8 @@ - name: For Debian, always use bridging set_fact: iiab_lan_iface: br0 - when: num_lan_interfaces|int >= 1 and is_debuntu + when: num_lan_interfaces|int >= 1 + #when: num_lan_interfaces|int >= 1 and is_debuntu - name: WiFi is on the LAN - use bridging set_fact: @@ -206,6 +239,41 @@ iiab_lan_iface: "{{ iiab_wireless_lan_iface }}" when: iiab_wireless_lan_iface is defined and nobridge is defined +- name: Detect WiFi country code in use + shell: iw reg get | grep country | grep -v UNSET | awk '{print $2}' | sed "s|:||" + register: REG_DOM + ignore_errors: True + +- name: Set host_country_code_found + set_fact: + host_country_code_found: "{{ REG_DOM.stdout }}" + when: REG_DOM.stdout is defined and REG_DOM.stdout | length > 0 + +- name: Set Wifi Region country to {{ REG_DOM.stdout }} for hostapd when present + set_fact: + host_country_code: "{{ REG_DOM.stdout }}" + when: REG_DOM.stdout is defined and REG_DOM.stdout | length > 0 and wifi_up_down and can_be_ap and has_wifi_gateway is defined + +- name: Detect current Wifi channel + shell: iw {{ discovered_wireless_iface }} info | grep channel | cut -d' ' -f2 + register: current_client_channel + when: wifi_up_down and can_be_ap and has_wifi_gateway is defined + +- name: Forcing wifi_up_down to False based on firmware selection "24" + set_fact: + wifi_up_down: False + when: rpi3bplus_rpi4_wifi_firmware == "24" + +- name: Detect "Firmware rejected country setting" in dmesg (invert return code, for intentional red error) + shell: '! dmesg | grep ieee80211 | grep "Firmware rejected country setting"' + register: FW_rejected_country + ignore_errors: True + +- name: Detect country code passed from cmdline in dmesg + shell: dmesg | grep -om1 'cfg80211\.ieee80211_regdom=\S*' | cut -d= -f2 + register: cmdline_country_code + ignore_errors: True + - name: In VM disable LAN - needs local_vars entry to activate set_fact: iiab_lan_iface: none @@ -228,38 +296,70 @@ option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: - - option: has_ifcfg_gw - value: "{{ has_ifcfg_gw }}" - - option: prior_gateway_device - value: "{{ prior_gw_device }}" - - option: dhcpcd_result - value: "{{ dhcpcd_result }}" - - option: network_manager_active - value: "{{ network_manager_active }}" - - option: systemd_networkd_active - value: "{{ systemd_networkd_active }}" - - option: wan_in_interfaces - value: "{{ wan_in_interfaces }}" - - option: wireless_list_1(wifi1) - value: "{{ wifi1 }}" - - option: wireless_list_2(wifi2) - value: "{{ wifi2 }}" - - option: num_wifi_interfaces - value: "{{ num_wifi_interfaces }}" - - option: discovered_wireless_iface - value: "{{ discovered_wireless_iface }}" - - option: discovered_wired_iface - value: "{{ discovered_wired_iface }}" - - option: 'exclude_devices' - value: "{{ exclude_devices }}" - - option: num_lan_interfaces - value: "{{ num_lan_interfaces }}" - - option: gui_static_wan - value: "{{ gui_static_wan }}" - - option: iiab_lan_iface - value: "{{ iiab_lan_iface }}" - - option: iiab_wan_iface - value: "{{ iiab_wan_iface }}" + - option: has_ifcfg_gw + value: "{{ has_ifcfg_gw }}" + - option: prior_gateway_device + value: "{{ prior_gw_device }}" + - option: dhcpcd_result + value: "{{ dhcpcd_result }}" + - option: network_manager_active + value: "{{ network_manager_active }}" + - option: systemd_networkd_active + value: "{{ systemd_networkd_active }}" + - option: wan_in_interfaces + value: "{{ wan_in_interfaces }}" + - option: wireless_list_1(wifi1) + value: "{{ wifi1 }}" + - option: wireless_list_2(wifi2) + value: "{{ wifi2 }}" + - option: num_wifi_interfaces + value: "{{ num_wifi_interfaces }}" + - option: discovered_wireless_iface + value: "{{ discovered_wireless_iface }}" + - option: discovered_wired_iface + value: "{{ discovered_wired_iface }}" + - option: 'exclude_devices' + value: "{{ exclude_devices }}" + - option: num_lan_interfaces + value: "{{ num_lan_interfaces }}" + - option: gui_static_wan + value: "{{ gui_static_wan }}" + - option: iiab_lan_iface + value: "{{ iiab_lan_iface }}" + - option: iiab_wan_iface + value: "{{ iiab_wan_iface }}" + - option: can_be_ap + value: "{{ can_be_ap }}" + - option: host_country_code_found + value: "{{ host_country_code_found }}" + - option: wifi_firmware_43430 + value: "{{ rpizerow_rpi3_wifi_firmware }}" + - option: wifi_firmware_43455 + value: "{{ rpi3bplus_rpi4_wifi_firmware }}" + +- name: Add 'detected_network' variable 'current_client_channel_found' stdout value ({{ current_client_channel.stdout }}) if defined and non-empty, to {{ iiab_ini_file }} + ini_file: + dest: "{{ iiab_ini_file }}" + section: detected_network + option: client_wifi_channel_found + value: "{{ current_client_channel.stdout }}" + when: current_client_channel.stdout is defined and current_client_channel.stdout != "" + +- name: Add 'detected_network' variable 'FW_rejected_country' stdout value ({{ FW_rejected_country.stdout }}) if defined and non-empty, to {{ iiab_ini_file }} + ini_file: + dest: "{{ iiab_ini_file }}" + section: detected_network + option: FW_rejected_country + value: "{{ FW_rejected_country.stdout }}" + when: FW_rejected_country.stdout is defined and FW_rejected_country.stdout != "" + +- name: Add 'detected_network' variable 'cmdline_country_code' stdout value ({{ cmdline_country_code.stdout }}) if defined and non-empty, to {{ iiab_ini_file }} + ini_file: + dest: "{{ iiab_ini_file }}" + section: detected_network + option: cmdline_country_code + value: "{{ cmdline_country_code.stdout }}" + when: cmdline_country_code.stdout is defined and cmdline_country_code.stdout != "" # well if there ever was a point to tell the user things are FUBAR this is it. # limit 2 network adapters wifi wired diff --git a/roles/network/tasks/dhcpd.yml b/roles/network/tasks/dhcpd.yml.unused similarity index 96% rename from roles/network/tasks/dhcpd.yml rename to roles/network/tasks/dhcpd.yml.unused index c306205cf..f3056dd4a 100644 --- a/roles/network/tasks/dhcpd.yml +++ b/roles/network/tasks/dhcpd.yml.unused @@ -28,7 +28,8 @@ name: "{{ dhcp_service }}6" enabled: no state: stopped - when: is_ubuntu and not is_ubuntu_16 + when: is_ubuntu + #when: is_ubuntu and not is_ubuntu_16 #when: is_ubuntu_18 - name: Install systemd unit file to /etc/systemd/system/dhcpd.service diff --git a/roles/network/tasks/dnsmasq.yml b/roles/network/tasks/dnsmasq.yml index 2678650ae..9ea710e4f 100644 --- a/roles/network/tasks/dnsmasq.yml +++ b/roles/network/tasks/dnsmasq.yml @@ -11,8 +11,8 @@ group: root mode: "{{ item.mode }}" with_items: - - { src: 'roles/network/templates/network/dnsmasq.service.u18', dest: '/etc/systemd/system/iiab-dnsmasq.service', mode: '0644' } - - { src: 'roles/network/templates/network/dnsmasq-iiab', dest: '/etc/dnsmasq.d/dnsmasq-iiab', mode: '644' } + - { src: 'roles/network/templates/network/dnsmasq.service.u18', dest: '/etc/systemd/system/iiab-dnsmasq.service', mode: '0644' } + - { src: 'roles/network/templates/network/dnsmasq-iiab', dest: '/etc/dnsmasq.d/dnsmasq-iiab', mode: '644' } - name: Don't use stock dnsmasq systemd unit file during boot but start now systemd: diff --git a/roles/network/tasks/down-debian.yml b/roles/network/tasks/down-debian.yml.unused similarity index 100% rename from roles/network/tasks/down-debian.yml rename to roles/network/tasks/down-debian.yml.unused diff --git a/roles/network/tasks/enable_services.yml b/roles/network/tasks/enable_services.yml index d87f9ab36..462b40868 100644 --- a/roles/network/tasks/enable_services.yml +++ b/roles/network/tasks/enable_services.yml @@ -1,70 +1,19 @@ -- name: Disable dhcpd service - service: - name: dhcpd - enabled: no - when: (dhcpd_install or dhcpd_installed is defined) and not dhcpd_enabled - -# service is restarted with NM dispatcher.d script -- name: Enable dhcpd service - service: - name: dhcpd - enabled: yes - when: dhcpd_install and dhcpd_enabled - -- name: Install /etc/sysconfig/dhcpd, /etc/dhcpd-iiab.conf from templates (root:root, 0644 by default) - template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - # owner: root - # group: root - # mode: "{{ item.mode }}" - with_items: - - { src: 'dhcp/dhcpd-env.j2', dest: '/etc/sysconfig/dhcpd' } - - { src: 'dhcp/dhcpd-iiab.conf.j2', dest: '/etc/dhcpd-iiab.conf' } - when: dhcpd_install and dhcpd_enabled - -- name: Install /etc/named-iiab.conf and two *.zone.db files into /var/named-iiab (root:root, 0644 by default) - template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - # owner: root - # group: root - # mode: "{{ item.mode }}" - with_items: - - { src: 'named/named-iiab.conf.j2', dest: '/etc/named-iiab.conf' } - - { src: 'named/school.local.zone.db', dest: '/var/named-iiab/' } - - { src: 'named/school.internal.zone.db', dest: '/var/named-iiab/' } - when: named_install and named_enabled - -- name: Enable named service ({{ dns_service }}) if named_enabled - systemd: - name: "{{ dns_service }}" - enabled: yes - when: named_install and named_enabled - -- name: Disable named service ({{ dns_service }}) if not named_enabled - systemd: - name: "{{ dns_service }}" - enabled: no - when: (named_install or named_installed is defined) and not named_enabled - - name: Install /etc/dnsmasq.d/iiab.conf from template, when dnsmasq_enabled and isn't Appliance template: src: network/dnsmasq.conf.j2 dest: /etc/dnsmasq.d/iiab.conf - when: dnsmasq_install and dnsmasq_enabled and (iiab_network_mode != "Appliance") + when: iiab_network_mode != "Appliance" - name: Install /etc/hosts.dnsmasq from template for /etc/dnsmasq.d/iiab.conf (instead of using /etc/hosts) template: src: network/hosts-dnsmasq.j2 dest: /etc/hosts.dnsmasq - when: dnsmasq_install and dnsmasq_enabled and (iiab_network_mode != "Appliance") + when: iiab_network_mode != "Appliance" - name: Update /etc/dnsmasq.d/dnsmasq-iiab for custom dns setting template: src: network/dnsmasq-iiab dest: /etc/dnsmasq.d/dnsmasq-iiab - when: dnsmasq_install # 2020-05-10: Are all these dnsmasq_install conditions really still necessary ? ## Another way to skin the cat ##- name: Check if systemd service networkd-dispatcher is enabled @@ -81,26 +30,19 @@ # command: systemctl is-enabled networkd-dispatcher # register: nd_enabled # ignore_errors: True -# -#- debug: -# var: nd_enabled - name: Check if /etc/networkd-dispatcher/routable.d exists stat: path: /etc/networkd-dispatcher/routable.d register: nd_dir -#- debug: -# var: nd_dir - - name: To restart dnsmasq whenever br0 comes up, install /etc/networkd-dispatcher/routable.d/dnsmasq.sh from template (if isn't Appliance, and directory /etc/networkd-dispatcher/routable.d exists, i.e. OS's like Ubuntu 18.04 or later) (root:root by default) template: src: roles/network/templates/network/dnsmasq.sh.j2 dest: /etc/networkd-dispatcher/routable.d/dnsmasq.sh mode: 0755 - # owner: root - # group: root - when: dnsmasq_install and dnsmasq_enabled and nd_dir.stat.exists and nd_dir.stat.isdir and (iiab_network_mode != "Appliance") + when: nd_dir.stat.exists and nd_dir.stat.isdir and (iiab_network_mode != "Appliance") + #when: dnsmasq_install and dnsmasq_enabled and nd_dir.stat.exists and nd_dir.stat.isdir and (iiab_network_mode != "Appliance") #when: dnsmasq_install and dnsmasq_enabled and nd_enabled is defined and nd_enabled.stdout == "enabled" and nd_dir.stat.exists and nd_dir.stat.isdir and (iiab_network_mode != "Appliance") #when: dnsmasq_install and dnsmasq_enabled and systemd_out.status.UnitFileState == "enabled" and networkd_dir.stat.exists and networkd_dir.stat.isdir and (iiab_network_mode != "Appliance") @@ -108,44 +50,33 @@ file: path: /etc/dnsmasq.d/iiab.conf state: absent - when: (not dnsmasq_enabled) or (iiab_network_mode == "Appliance") + when: not dnsmasq_enabled or iiab_network_mode == "Appliance" - name: Enable iiab-dnsmasq systemd service, if dnsmasq_enabled systemd: name: iiab-dnsmasq enabled: yes - when: dnsmasq_install and dnsmasq_enabled + when: dnsmasq_enabled - name: Disable iiab-dnsmasq, if not dnsmasq_enabled systemd: name: iiab-dnsmasq enabled: no - when: dnsmasq_install and not dnsmasq_enabled + when: not dnsmasq_enabled -# - name: Enable DansGuardian systemd service, if dansguardian_enabled -# systemd: -# name: dansguardian -# enabled: yes -# when: dansguardian_install and dansguardian_enabled - -# - name: Disable DansGuardian, if not dansguardian_enabled -# systemd: -# name: dansguardian -# enabled: no -# when: (dansguardian_install or dansguardian_installed is defined) and not dansguardian_enabled - name: Mandate 'HTTPCACHE_ON=True' in {{ iiab_env_file }} - if squid_install [{{ squid_install }}] and squid_enabled [{{ squid_enabled }}] lineinfile: path: "{{ iiab_env_file }}" regexp: '^HTTPCACHE_ON=*' line: 'HTTPCACHE_ON=True' - when: squid_install and squid_enabled + when: squid_installed is defined and squid_enabled - name: Enable systemd service '{{ proxy }}' - if squid_install and squid_enabled systemd: name: "{{ proxy }}" # squid (or 'squid3' on vars/debian-8.yml, vars/raspbian-8.yml) enabled: yes - when: squid_install and squid_enabled + when: squid_installed is defined and squid_enabled - name: Install /etc/{{ proxy }}/squid.conf from template (root:root, 0644 by default) - and create a timestamped backup of the original - if squid_install and squid_enabled template: @@ -154,7 +85,7 @@ # owner: "{{ proxy_user }}" # proxy (or 'squid' on vars/centos-7.yml, vars/fedora-18.yml, vars/fedora-12.yml) # group: "{{ proxy_user }}" backup: yes - when: squid_install and squid_enabled + when: squid_installed is defined and squid_enabled # - name: Point /etc/init.d/{{ proxy }} to /etc/{{ proxy }}/squid-iiab.conf - if squid_install and squid_enabled # lineinfile: @@ -167,47 +98,23 @@ systemd: name: "{{ proxy }}" enabled: no - when: (squid_install or squid_installed is defined) and not squid_enabled + when: squid_installed is defined and not squid_enabled - name: Revert {{ iiab_env_file }} to 'HTTPCACHE_ON=False' - if squid_install and not squid_enabled lineinfile: path: "{{ iiab_env_file }}" regexp: '^HTTPCACHE_ON=*' line: 'HTTPCACHE_ON=False' - when: squid_install and not squid_enabled + when: squid_installed is defined and not squid_enabled -# - name: Enable Wondershaper service, if wondershaper_enabled -# systemd: -# name: wondershaper -# enabled: yes -# when: wondershaper_install and wondershaper_enabled - -# - name: Disable Wondershaper service, if not wondershaper_enabled -# systemd: -# name: wondershaper -# enabled: no -# when: (wondershaper_install or wondershaper_installed is defined) and not wondershaper_enabled # check-LAN should be iptables.yml remove later - name: Install clean copy of /usr/bin/iiab-gen-iptables from template (root:root by default) template: src: gateway/iiab-gen-iptables dest: /usr/bin/iiab-gen-iptables - # owner: root - # group: root mode: 0755 -- name: Install /usr/bin/iiab-internet-on|off from template (root:root by default) - template: - src: "{{ item }}" - dest: /usr/bin/ - # owner: root - # group: root - mode: 0755 - with_items: - - gateway/iiab-internet-on - - gateway/iiab-internet-off - - name: Add 'squid' variable values to {{ iiab_ini_file }} - if squid_installed is defined ini_file: @@ -221,29 +128,3 @@ - option: squid_enabled value: "{{ squid_enabled }}" when: squid_installed is defined - -# - name: Add 'dansguardian' variable values to {{ iiab_ini_file }} -# ini_file: -# path: "{{ iiab_ini_file }}" -# section: dansguardian -# option: "{{ item.option }}" -# value: "{{ item.value | string }}" -# with_items: -# - option: dansguardian_install -# value: "{{ dansguardian_install }}" -# - option: dansguardian_enabled -# value: "{{ dansguardian_enabled }}" -# when: dansguardian_installed is defined - -# - name: Add 'wondershaper' variable values to {{ iiab_ini_file }} -# ini_file: -# path: "{{ iiab_ini_file }}" -# section: wondershaper -# option: "{{ item.option }}" -# value: "{{ item.value | string }}" -# with_items: -# - option: wondershaper_install -# value: "{{ wondershaper_install }}" -# - option: wondershaper_enabled -# value: "{{ wondershaper_enabled }}" -# when: wondershaper_installed is defined diff --git a/roles/network/tasks/hostapd.yml b/roles/network/tasks/hostapd.yml index 33e0a6468..c845bd637 100644 --- a/roles/network/tasks/hostapd.yml +++ b/roles/network/tasks/hostapd.yml @@ -1,43 +1,28 @@ -- name: Unmask the Access Point 'hostapd' service +- name: Disable hostapd when not using ap0 and wifi gateway present, or no WiFi hardware present or support not detected + set_fact: + hostapd_enabled: False + when: (not wifi_up_down and discovered_wireless_iface == iiab_wan_iface) or discovered_wireless_iface == "none" or not can_be_ap + +- name: Disable the Access Point 'hostapd' service if hostapd_enabled False systemd: name: hostapd enabled: no - masked: no - -- name: Disable hostapd when not using ap0 and wifi gateway present, or no WiFi hardware present - set_fact: - hostapd_enabled: False - when: (not wifi_up_down and discovered_wireless_iface == iiab_wan_iface) or discovered_wireless_iface == "none" - -- name: Detect current Wifi channel - shell: iw {{ discovered_wireless_iface }} info | grep channel | cut -d' ' -f2 - register: current_client_channel - when: discovered_wireless_iface != "none" + when: not hostapd_enabled - name: Setting WiFi channel to {{ current_client_channel.stdout }} set_fact: host_channel: "{{ current_client_channel.stdout }}" when: current_client_channel.stdout is defined and current_client_channel.stdout != "" and current_client_channel.stdout|int <= 13 -- name: Create /etc/hostapd/hostapd.conf and backup .iiab from template - template: - owner: root - group: root - mode: 0644 - src: "{{ item.src }}" - dest: "{{ item.dest }}" - with_items: - - { src: 'hostapd/hostapd.conf.j2', dest: '/etc/hostapd/hostapd.conf' } - - { src: 'hostapd/hostapd.conf.j2', dest: '/etc/hostapd/hostapd.conf.iiab' } - when: discovered_wireless_iface != "none" - - name: Generate new random mac address for ap0 shell: tr -dc A-F0-9 < /dev/urandom | head -c 10 | sed -r 's/(..)/\1:/g;s/:$//;s/^/02:/' register: ap0_mac + when: can_be_ap - name: Setting ap0 mac address for use in hostapd service file set_fact: ap0_mac_addr: "{{ ap0_mac.stdout }}" + when: can_be_ap - name: "Use custom 'hostapd' systemd service unit file using ap0 -- install from template: /etc/systemd/system/hostapd.service, /etc/systemd/system/iiab-clone-wifi.service, /etc/systemd/system/iiab-wifi-test.service, /usr/sbin/iiab-test-wifi" template: @@ -51,7 +36,7 @@ - { src: 'hostapd/iiab-clone-wifi.service.j2', dest: '/etc/systemd/system/iiab-clone-wifi.service', mode: '0644' } - { src: 'hostapd/iiab-wifi-test.service.j2', dest: '/etc/systemd/system/iiab-wifi-test.service', mode: '0644'} - { src: 'hostapd/iiab-test-wifi.j2', dest: '/usr/sbin/iiab-test-wifi', mode: '0755' } - when: discovered_wireless_iface != "none" + when: can_be_ap - name: Use custom 'hostapd' systemd service unit file for {{ discovered_wireless_iface }} when not wifi_up_down template: @@ -60,78 +45,10 @@ owner: root group: root mode: 0644 - when: discovered_wireless_iface != "none" and not wifi_up_down + when: not wifi_up_down and can_be_ap -- name: Create /usr/bin/iiab-hotspot-on from template - template: - src: network/iiab-hotspot-on - dest: /usr/bin/iiab-hotspot-on - owner: root - group: root - mode: 0755 - -- name: Create /usr/bin/iiab-hotspot-off from template - template: - src: network/iiab-hotspot-off - dest: /usr/bin/iiab-hotspot-off - owner: root - group: root - mode: 0755 - -- name: Create dhcpcd hook for hostapd and ap0 when wifi_up_down True - template: - src: hostapd/50-hostapd - dest: /lib/dhcpcd/dhcpcd-hooks/50-hostapd - owner: root - group: root - mode: 0644 - when: is_raspbian and wifi_up_down - -- name: Remove dhcpcd hook for hostapd if WiFi is not split using ap0 - file: - path: /lib/dhcpcd/dhcpcd-hooks/50-hostapd - state: absent - when: is_raspbian and not wifi_up_down - -- name: Create networkd-dispatcher diagnostic hook for recording network events - template: - owner: root - group: root - mode: 0755 - src: "{{ item.src }}" - dest: "{{ item.dest }}" - with_items: - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/carrier.d/00-iiab-debug' } - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/degraded.d/00-iiab-debug' } - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/dormant.d/00-iiab-debug' } - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/no-carrier.d/00-iiab-debug' } - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/off.d/00-iiab-debug' } - - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/routable.d/00-iiab-debug' } - when: systemd_networkd_active and discovered_wireless_iface != "none" - -- name: Create networkd-dispatcher hook for hostapd wifi_up_down True - template: - owner: root - group: root - mode: 0755 - src: "{{ item.src }}" - dest: "{{ item.dest }}" - with_items: - - { src: 'hostapd/netd-disp', dest: '/etc/networkd-dispatcher/carrier.d/iiab-wifi' } - - { src: 'hostapd/netd-disp', dest: '/etc/networkd-dispatcher/no-carrier.d/iiab-wifi' } - - { src: 'hostapd/netd-disp2', dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi2' } - when: systemd_networkd_active and discovered_wireless_iface != "none" and wifi_up_down - -- name: Remove networkd-dispatcher hook wifi_up_down False - file: - path: "{{ item.dest }}" - state: absent - with_items: - - { dest: '/etc/networkd-dispatcher/carrier.d/iiab-wifi' } - - { dest: '/etc/networkd-dispatcher/no-carrier.d/iiab-wifi' } - - { dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi' } - - { dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi2' } - when: systemd_networkd_active and discovered_wireless_iface != "none" and not wifi_up_down +# 2022-07-11: Install of iiab-hotspot-on|off moved to network/tasks/main.yml +# as required for Admin Console - name: Enable the Access Point 'hostapd' service systemd: @@ -143,7 +60,7 @@ systemd: name: "{{ item }}" enabled: no - daemon_reload: yes + daemon_reload: yes with_items: - iiab-clone-wifi.service - iiab-wifi-test.service @@ -166,3 +83,35 @@ regexp: '^HOSTAPD_ENABLED=*' line: 'HOSTAPD_ENABLED={{ hostapd_enabled }}' state: present + +- name: Create /etc/hostapd/hostapd.conf and backup .iiab from template if needed + template: + owner: root + group: root + mode: 0644 + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: 'hostapd/hostapd.conf.j2', dest: '/etc/hostapd/hostapd.conf' } + - { src: 'hostapd/hostapd.conf.j2', dest: '/etc/hostapd/hostapd.conf.iiab' } + when: can_be_ap + +- name: Record host_country_code_applied and host_channel in network of {{ iiab_ini_file }} + ini_file: + dest: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: network + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: hostapd_enabled + value: "{{ hostapd_enabled }}" + - option: host_ssid + value: "{{ host_ssid }}" + - option: host_wifi_mode + value: "{{ host_wifi_mode }}" + - option: wifi_up_down + value: "{{ wifi_up_down }}" + - option: host_country_code_applied + value: "{{ host_country_code }}" + - option: host_channel + value: "{{ host_channel }}" diff --git a/roles/network/tasks/install.yml b/roles/network/tasks/install.yml new file mode 100644 index 000000000..f7c1a5b9a --- /dev/null +++ b/roles/network/tasks/install.yml @@ -0,0 +1,135 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# 2022-03-16: 'apt show | grep Size' revealed download sizes, on 64-bit RasPiOS with desktop. + +- name: Install dnsmasq -- configure LATER in 'network', after Stage 9 + include_tasks: roles/network/tasks/dnsmasq.yml # Invoked by 1-prep (so full path needed) + +# 2021-07-27 from @jvonau: 3 apt packages BELOW (iw, rfkill, wireless-tools) +# are provided by RasPiOS. Ubuntu|Debian on the other hand are hit or miss: +# desktops might have some/all 3 preinstalled, while servers tend not to have +# these present at all, but need to be installed if you want to take full +# advantage of WiFi on Ubuntu and friends. +# +# 2022-03-16 update: Let's make these 3 mandatory as they're only 300kB (grand +# total download size) and they can help IIAB field operators with BOTH +# (1) internal WiFi AND (2) USB WiFi devices inserted anytime/later. + +- name: 'Install 11 network packages: avahi-daemon, hostapd, iproute2, iptables-persistent, iw, libnss-mdns, netmask, net-tools, networkd-dispatcher, rfkill, wpasupplicant -- later used by https://github.com/iiab/iiab/tree/master/roles/network' + package: + name: + - avahi-daemon # 97kB download: RasPiOS (and package libnss-mnds, below) install this regardless -- holdover from the XO days and used to advertise ssh/admin-console being available via avahi-daemon -- used with https://github.com/iiab/iiab/blob/master/roles/network/tasks/avahi.yml + #- avahi-discover # 46kB download: 2021-07-27: Commented out long ago + - hostapd # 764kB download: IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator -- has its service masked out of the box, and only used when IIAB's network roles detects the presence of WiFi and an AP is desired + #- inetutils-syslogd # 240kB download: 2021-07-27: Error logging facility -- holdover from the XO days, journalctl has replaced this in newer distros + - iproute2 # 902kB download: RasPiOS installs this regardless -- the new networking and traffic control tools, meant to replace net-tools + - iptables-persistent # 12kB download: Boot-time loader for netfilter rules, iptables (firewall) plugin -- however Netfilter / nftables is ever moving forward so keep an eye on it! + - iw # 97kB download: RasPiOS installs this regardless -- configure Linux wireless devices -- hard dependence for ap0 creation, SEE https://github.com/iiab/iiab/blob/master/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 + - libnss-mdns # 27kB download: RasPiOS (and package avahi-daemon, above) install this regardless -- client-side library -- provides name resolution via mDNS (Multicast DNS) using Zeroconf/Bonjour e.g. Avahi + - netmask # 25kB download: Handy utility -- helps determine network masks + - net-tools # 248kB download: RasPiOS installs this regardless -- @jvonau suggests possibly deleting this...unless oldtimers really want these older commands in iiab-diagnostics output? + - rfkill # 87kB download: RasPiOS installs this regardless -- enable & disable wireless devices + - wpasupplicant # 1188kB download: RasPiOS installs this regardless -- client library for connections to a WiFi AP + state: present + +# 2024-10-02: Legacy apt package 'wireless-tools' no longer offered by Ubuntu +# 24.10+ (#3805) but FYI: https://en.wikipedia.org/wiki/Wireless_tools_for_Linux +- name: "Install legacy apt package wireless-tools, if OS still supports it -- or intentionally show (HARMLESS!) red error -- helping to monitor Linux's evolution" + package: + name: wireless-tools # 112kB download: RasPiOS installs this regardless -- manipulate Linux Wireless Extensions + state: present + ignore_errors: True # Intentionally show red error, and continue. + #failed_when: False # Hides red errors (stronger than 'ignore_errors: yes') + +# 2021-08-17: Debian ignores this, according to 2013 post: +# https://serverfault.com/questions/511099/debian-ignores-etc-network-if-pre-up-d-iptables +# - name: Install /etc/network/if-pre-up.d/iptables from template (0755) +# template: +# src: iptables +# dest: /etc/network/if-pre-up.d/iptables +# mode: '0755' + +- name: Unmask the Access Point 'hostapd' service + systemd: + name: hostapd + enabled: no + masked: no + +- name: Install Avahi (mDNS, Zeroconf/Bonjour) + include_tasks: roles/network/tasks/avahi.yml # Invoked by 1-prep (so full path needed) + +# Ongoing rework (e.g. PR #2652) arising from ansible.posix collection changes: +- name: "4 network settings in /etc/sysctl.conf -- e.g. disabling IPv6 (this might be overkill, as IPv6 should really only be disabled on the LAN side, i.e. br0)" + sysctl: # Places these settings in /etc/sysctl.conf, to survive reboot + name: "{{ item.name }}" + value: "{{ item.value }}" + with_items: + - { name: 'net.ipv4.ip_forward', value: '1' } # Default: 0. Masquerading LAN->Internet + - { name: 'net.ipv4.conf.default.rp_filter', value: '1' } # Default: 2. Enable Spoof protection (reverse-path filter) + - { name: 'net.ipv4.conf.default.accept_source_route', value: '0' } # Default: 1. Do not accept IP source route packets (we are not a router) + #- { name: 'net.ipv4.tcp_syncookies', value: '1' } # Very standard in 2020 + - { name: 'net.ipv6.conf.all.disable_ipv6', value: '1' } # Default: 0. Disable IPv6. SEE ALSO: roles/munin/tasks/install.yml & enable-and-disable.yml + #- { name: 'net.ipv6.conf.default.disable_ipv6', value: '1' } # AUTO-SET + #- { name: 'net.ipv6.conf.lo.disable_ipv6', value: '1' } # BY ABOVE + + +# UNUSED +#- name: Install named / BIND +# include_tasks: roles/network/tasks/named.yml +# when: named_install is defined and named_install + +# UNUSED +#- name: Install dhcpd +# include_tasks: roles/network/tasks/dhcpd.yml +# when: dhcpd_install is defined and dhcpd_install + +# LESS MAINTAINED +- name: Install Squid + include_tasks: roles/network/tasks/squid.yml # Invoked by 1-prep (so full path needed) + when: squid_install and squid_installed is undefined + + #preprep for backends +- name: Netplan in use on Ubuntu 18.04+ + include_tasks: roles/network/tasks/netplan.yml # Invoked by 1-prep (so full path needed) + when: is_ubuntu + +# all installs + +- name: Install /usr/bin/iiab-internet-on|off from template (root:root by default) + template: + src: "{{ item }}" + dest: /usr/bin/ + mode: 0755 + with_items: + - roles/network/templates/gateway/iiab-internet-on # Invoked by 1-prep (so full path needed) + - roles/network/templates/gateway/iiab-internet-off # Invoked by 1-prep (so full path needed) + +- name: 'Install /usr/local/sbin/iiab-netwarn for pop-ups on boot, if iiab-network should be run' + include_tasks: roles/network/tasks/netwarn.yml # Invoked by 1-prep (so full path needed) + + +# RECORD Network AS INSTALLED + +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'network_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: network + option: network_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + +- name: "Set 'network_installed: True'" + set_fact: + network_installed: True + +- name: "Add 'network_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^network_installed' + line: 'network_installed: True' diff --git a/roles/network/tasks/main.yml b/roles/network/tasks/main.yml index d849cebaf..bb05482f5 100644 --- a/roles/network/tasks/main.yml +++ b/roles/network/tasks/main.yml @@ -1,8 +1,3 @@ -- name: Select RPi firmware mode - include_role: - name: firmware - when: rpi_model != "none" - - name: detected_network include_tasks: detected_network.yml @@ -21,59 +16,101 @@ - name: computed_network include_tasks: computed_network.yml -# - name: Configure wondershaper -# include_tasks: wondershaper.yml -# when: wondershaper_install or wondershaper_installed is defined +# 2022-07-22: @jvonau asks for this to be (1) BELOW computed_network.yml +# (what goes into iiab-hotspot-on|off depends on can_be_ap and wifi_up_down) +# AND (2) ABOVE install.yml for some reason? REQUIREMENT: Admin Console reads +# iiab_network_mode from /etc/iiab/iiab.ini + uses /usr/bin/iiab-hotspot-on|off +- name: Install /usr/bin/iiab-hotspot-on|off from template (root:root by default) + template: + src: "{{ item }}" + dest: /usr/bin/ + mode: 0755 + with_items: + - hostapd/iiab-hotspot-on + - hostapd/iiab-hotspot-off -- name: (Re)Install named - include_tasks: named.yml - when: named_install and FQDN_changed and iiab_stage|int == 9 +- name: Install network packages (including many WiFi tools, and also iptables-persistent for firewall) + include_tasks: install.yml + when: network_install and network_installed is undefined -- name: (Re)Install dhcpd - include_tasks: dhcpd.yml - when: dhcpd_install and FQDN_changed and iiab_stage|int == 9 -- name: (Re)Install Squid - include_tasks: squid.yml - when: squid_install and FQDN_changed and iiab_stage|int == 9 +- name: Configuring Network if enabled + block: -#preprep for backends -- name: Netplan in use on Ubuntu 18.04+ - include_tasks: netplan.yml - when: is_ubuntu and not is_ubuntu_16 + # DEPRECATED + #- name: Configure wondershaper + # include_tasks: wondershaper.yml + # when: wondershaper_install or wondershaper_installed is defined + # + #- name: (Re)Install named + # include_tasks: named.yml + # when: named_install and FQDN_changed and iiab_stage|int == 9 + # + #- name: (Re)Install dhcpd + # include_tasks: dhcpd.yml + # when: dhcpd_install and FQDN_changed and iiab_stage|int == 9 -#### Start services -- name: avahi - include_tasks: avahi.yml -- name: hostapd - include_tasks: hostapd.yml -- name: computed_services - include_tasks: computed_services.yml -- name: enable_services - include_tasks: enable_services.yml -#### End services + # 2022-07-22: Is './runrole --reinstall network' the new way to make this run? + #- name: (Re)Install Squid + # include_tasks: squid.yml + # when: squid_install and FQDN_changed and iiab_stage|int == 9 -#### Start network layout -#- name: Redhat networking -# include_tasks: ifcfg_mods.yml -# when: is_redhat + #### Start services + - name: computed_services + include_tasks: computed_services.yml + - name: enable_services + include_tasks: enable_services.yml + #### End services -- name: NetworkManager in use - include_tasks: NM-debian.yml - when: is_debuntu and network_manager_active + #### Start network layout -- name: systemd-networkd in use - include_tasks: sysd-netd-debian.yml - when: is_debuntu and systemd_networkd_active + # 2024-12-18: As `rfkill unblock wifi` formerly in rpi_debian.yml wasn't enough, especially with NM (NetworkManager) + - name: Run 'raspi-config nonint do_wifi_country {{ host_country_code }}' (using var host_country_code) to unblock WiFi, if RasPiOS + command: raspi-config nonint do_wifi_country {{ host_country_code }} + when: is_raspbian + #ignore_errors: True -- name: Raspbian uses dhcpcd only with no N-M or SYS-NETD active - include_tasks: rpi_debian.yml - when: is_raspbian + #- name: Redhat networking + # include_tasks: ifcfg_mods.yml + # when: is_redhat -- name: Not RPi, Not NetworkManager, Not systemd-networkd in use - include_tasks: debian.yml - when: (not is_raspbian and not network_manager_active and not systemd_networkd_active and is_debuntu) or is_ubuntu_16 -#### end network layout + - name: NetworkManager in use + include_tasks: NM-debian.yml + when: network_manager_active -- name: Restart services - include_tasks: restart.yml + - name: systemd-networkd in use + include_tasks: sysd-netd-debian.yml + when: systemd_networkd_active + #when: systemd_networkd_active and not network_manager_active # 2023-10-11: NOT the right way to solve #3657 (systemd-resolved issue on RasPiOS 12+) as this would damage Ubuntu/Mint. + + # 2023-10-11: Should rpi_debian.yml go away in future, now that RasPiOS Bookworm uses NetworkManager? + - name: Raspbian can use dhcpcd only with no N-M or SYS-NETD active + include_tasks: rpi_debian.yml + when: is_raspbian and not network_manager_active + + - name: Not RPi, Not NetworkManager, Not systemd-networkd in use + include_tasks: debian.yml + when: not is_raspbian and not network_manager_active and not systemd_networkd_active + #when: (not is_raspbian and not network_manager_active and not systemd_networkd_active and is_debuntu) or is_ubuntu_16 + #### end network layout + + - name: hostapd + include_tasks: hostapd.yml + + - name: Restart services + include_tasks: restart.yml + + # end block + when: network_installed is defined and network_enabled + +- name: Select RPi firmware mode + include_role: + name: firmware + when: rpi_model != "none" + + +- name: Create {{ iiab_etc_path }}/install-flags/iiab-network-complete on second pass of network role. + file: + path: "{{ iiab_etc_path }}/install-flags/iiab-network-complete" + state: touch + when: iiab_stage|int == 9 diff --git a/roles/network/tasks/named.yml b/roles/network/tasks/named.yml.unused similarity index 96% rename from roles/network/tasks/named.yml rename to roles/network/tasks/named.yml.unused index 9183242f9..0123ef03f 100644 --- a/roles/network/tasks/named.yml +++ b/roles/network/tasks/named.yml.unused @@ -58,8 +58,8 @@ - { src: 'roles/network/templates/named/school.internal.zone.32.in-addr.db.j2', dest: '/var/named-iiab/school.internal.zone.32.in-addr.db', owner: "{{ dns_user }}", mode: '0644' } - { src: 'roles/network/templates/named/school.internal.zone.48.in-addr.db.j2', dest: '/var/named-iiab/school.internal.zone.48.in-addr.db', owner: "{{ dns_user }}", mode: '0644' } # the following two files are not writeable by named, but bind 9.4 cannot discover that fact correctly - - { src: 'roles/network/templates/named/school.internal.zone.db', dest: '/var/named-iiab/school.internal.zone.db', owner: "root", mode: '0644' } - - { src: 'roles/network/templates/named/school.local.zone.db', dest: '/var/named-iiab/school.local.zone.db', owner: "root", mode: '0644' } + - { src: 'roles/network/templates/named/school.internal.zone.db.j2', dest: '/var/named-iiab/school.internal.zone.db', owner: "root", mode: '0644' } + - { src: 'roles/network/templates/named/school.local.zone.db.j2', dest: '/var/named-iiab/school.local.zone.db', owner: "root", mode: '0644' } - { src: 'roles/network/templates/named/school.internal.zone.in-addr.db.j2', dest: '/var/named-iiab/school.internal.zone.in-addr.db', owner: "{{ dns_user }}", mode: '0644' } - { src: 'roles/network/templates/named/dummy', dest: '/var/named-iiab/data/dummy', owner: "{{ dns_user }}", mode: '0644' } - { src: 'roles/network/templates/named/named.blackhole', dest: '/var/named-iiab/named.blackhole', owner: "{{ dns_user }}", mode: '0644' } diff --git a/roles/network/tasks/netplan.yml b/roles/network/tasks/netplan.yml index 799af001d..8af6b807c 100644 --- a/roles/network/tasks/netplan.yml +++ b/roles/network/tasks/netplan.yml @@ -1,3 +1,22 @@ +# 2022-07-22: Moved from detected_network.yml to netplan.yml AND restart.yml (REMOVE DUPLICATE CODE LATER?!) +- name: Figure out netplan file name + shell: ls /etc/netplan + register: netplan + #ignore_errors: True # pre 17.10 doesn't use netplan + +# 2022-07-23: PR #3319 "Ubuntu variants [all] use NetworkManager as the backend +# for use with netplan and ship with systemd-networkd present but disabled" +- name: "Force default 'systemd_networkd_active: False' -- nec b/c network/default/main.yml is omitted when 1-prep directly invokes network/tasks/install.yml" + set_fact: + systemd_networkd_active: False + +# 2022-07-22: Copied from detected_network.yml (REMOVE DUPLICATE CODE LATER?!) +- name: "Set 'systemd_networkd_active: True' if local_facts.systemd_networkd confirms" + set_fact: + systemd_networkd_active: True + when: ansible_local.local_facts.systemd_networkd == "enabled" or ansible_local.local_facts.systemd_networkd == "enabled-runtime" + + - name: Disable cloud-init the easy way shell: touch /etc/cloud/cloud-init.disabled when: item|trim == "50-cloud-init.yaml" @@ -59,14 +78,22 @@ with_items: - "{{ netplan.stdout_lines }}" -- name: Replace networkd-dispatcher #2585 for "groovy" - get_url: - url: https://gitlab.com/craftyguy/networkd-dispatcher/-/raw/2.1/networkd-dispatcher - dest: /usr/bin/networkd-dispatcher - timeout: "{{ download_timeout }}" - when: internet_available and fix_dispatcher and ansible_distribution_release == "groovy" - # 2021-08-29 context from @jvonau: Fix is 'Groovy' specific, 21.04 and later - # should have the fix baked into a newer apt package installed by default. +# 2022-06-30: Ubuntu Groovy (20.10) is ancient history but this code might now +# help Linux Mint ? +# +# 2022-05-29: @jvonau wrote on #3106 "networkd-dispatcher has a traceback, +# I suspect the cause is the same as found #2645, need to confirm the package +# version installed with apt list networkd-dispatcher before suggesting the +# workaround be extended to LinuxMint" +# +# - name: Replace networkd-dispatcher #2585 for "groovy" +# get_url: +# url: https://gitlab.com/craftyguy/networkd-dispatcher/-/raw/2.1/networkd-dispatcher +# dest: /usr/bin/networkd-dispatcher +# timeout: "{{ download_timeout }}" +# when: iiab_stage|int < 9 and fix_dispatcher and ansible_distribution_release == "groovy" +# # 2021-08-29 context from @jvonau: Fix is 'Groovy' specific, 21.04 and later +# # should have the fix baked into a newer apt package installed by default. #- name: Supply netplan template # template: diff --git a/roles/network/tasks/netwarn.yml b/roles/network/tasks/netwarn.yml new file mode 100644 index 000000000..78aae19be --- /dev/null +++ b/roles/network/tasks/netwarn.yml @@ -0,0 +1,47 @@ +# 2022-07-22: SIMILAR TO roles/iiab-admin/tasks/pwd-warnings.yml FOR passwords +# AND roles/www_options/tasks/main.yml FOR browser + +# 2022-07-22: An /etc/profile.d/ version like /etc/local/sbin/iiab-netwarn but for +# shell / ssh logins (across all OS's/distros/window managers) might also make sense? + + +- name: Does directory /home/{{ iiab_admin_user }}/.config/labwc/ exist? + stat: + path: /home/{{ iiab_admin_user }}/.config/labwc/ + register: labwc_dir + +- name: If so, add '/usr/local/sbin/iiab-netwarn &' to /home/{{ iiab_admin_user }}/.config/labwc/autostart + lineinfile: + path: /home/{{ iiab_admin_user }}/.config/labwc/autostart # iiab-admin + create: yes + line: '/usr/local/sbin/iiab-netwarn &' + when: labwc_dir.stat.exists and labwc_dir.stat.isdir + + +# mate desktop detection based on 'register: nd_dir' in enable_services +- name: Does /usr/share/mate/autostart/ exist? + stat: + path: /usr/share/mate/autostart/ + register: mate_dir + +# contents work with mate as of 'switch to using dash via sh' +# 'text' is up for debate other structural changes I do not recommend JV + +- name: 'Install from template: /usr/share/mate/autostart/netwarn-iiab-network.desktop' + template: + src: roles/network/templates/netwarn/netwarn-iiab-network.desktop # Invoked by 1-prep (so full path needed) + dest: /usr/share/mate/autostart/ + when: mate_dir.stat.exists and mate_dir.stat.isdir + + +# 2022-07-21: Is autostart pop-up logic for Mint & stock Ubuntu much the same? + +# (Let's insert those here if so, and refine the 'when:' line below.) + + +- name: 'If a supported graphical OS is detected, install from template: /usr/local/sbin/iiab-netwarn' + template: + src: roles/network/templates/netwarn/iiab-netwarn # Invoked by 1-prep (so full path needed) + dest: /usr/local/sbin/ + mode: 0755 + when: (labwc_dir.stat.exists and labwc_dir.stat.isdir) or (mate_dir.stat.exists and mate_dir.stat.isdir) diff --git a/roles/network/tasks/restart.yml b/roles/network/tasks/restart.yml index d286e987c..d5de9e27d 100644 --- a/roles/network/tasks/restart.yml +++ b/roles/network/tasks/restart.yml @@ -1,20 +1,57 @@ +# 2022-07-22: Moved from detected_network.yml to netplan.yml AND restart.yml (REMOVE DUPLICATE CODE LATER?!) +# - name: Figure out netplan file name +# shell: ls /etc/netplan +# register: netplan +# #ignore_errors: True # pre 17.10 doesn't use netplan +# when: is_ubuntu + + - name: Restart wpa_supplicant service systemd: name: "{{ item }}" state: restarted with_items: - wpa_supplicant - when: wifi_up_down and hostapd_enabled + when: wifi_up_down and hostapd_enabled and not network_manager_active -- name: Reload netplan for Wifi gateway on Ubuntu 18+ - shell: netplan apply - when: wifi_up_down and is_ubuntu and netplan.stdout.find("yaml") != -1 - -- name: Start named service +- name: Enable & Restart networkd-dispatcher.service systemd: - name: "{{ dns_service }}" + name: networkd-dispatcher state: restarted - when: named_enabled and named_install + enabled: yes + masked: no + when: systemd_networkd_active + +- name: Clone wifi if needed + systemd: + name: iiab-clone-wifi + state: restarted + when: wifi_up_down and can_be_ap and ansible_ap0 is undefined + +- name: Waiting {{ hostapd_wait }} seconds for network to stabilize for ap0 + shell: sleep {{ hostapd_wait }} + when: ansible_ap0 is undefined + +- name: Restart hostapd when WiFi is present but not when using WiFi as gateway + systemd: + name: hostapd + state: restarted + daemon_reload: yes + when: hostapd_enabled and not no_net_restart + +# 2022-07-22: @jvonau suggests commenting this out as: "we really don't touch +# any of the config files... netplan.yml renames one file if it's a container +# build like on MATE, could possibly skip netplan.yml in future or toss that in +# the mix now and see what shakes up" [ok, but keep netplan.yml as is for now] +# - name: Reload netplan for Wifi gateway on Ubuntu 18+ +# shell: netplan apply +# when: wifi_up_down and is_ubuntu and netplan.stdout.find("yaml") != -1 + +#- name: Start named service +# systemd: +# name: "{{ dns_service }}" +# state: restarted +# when: named_enabled and named_install - name: Stop Squid service systemd: @@ -74,16 +111,18 @@ systemd: name: hostapd state: restarted - when: hostapd_enabled and wifi_slave.stdout is defined and wifi_slave.stdout == 0 + when: hostapd_enabled and not no_net_restart and wifi_slave.stdout is defined and wifi_slave.stdout == 0 #both interfaces.d and systemd-networkd should have br0 available and Appliance lacks br0 #keep an eye on legacy wifi installs where br0 is present but not 'online' with an ip address #due to hostapd didn't go to a carrier state. All others should get dnsmasq restarted -- name: User choice of dnsmasq or dhcpd - restarting {{ dhcp_service2 }} +#- name: User choice of dnsmasq or dhcpd - restarting {{ dhcp_service2 }} +- name: Restarting dnsmasq systemd: - name: "{{ dhcp_service2 }}" + name: dnsmasq state: restarted - when: (not no_net_restart or (is_ubuntu and wifi_up_down)) or (iiab_stage|int == 9) + when: dnsmasq_enabled and ((not no_net_restart or (is_ubuntu and wifi_up_down)) or (iiab_stage|int == 9)) +# when: (not no_net_restart or (is_ubuntu and wifi_up_down)) or (iiab_stage|int == 9) #when: (not no_net_restart or (is_ubuntu_20 and wifi_up_down)) or (iiab_stage|int == 9) #when: (not no_net_restart or (is_ubuntu_20 and wifi_up_down)) #when: (iiab_network_mode != "Appliance") # Sufficient b/c br0 exists thanks to /etc/network/interfaces.d/iiab diff --git a/roles/network/tasks/rpi_debian.yml b/roles/network/tasks/rpi_debian.yml index 1887a7d15..e85c673dd 100644 --- a/roles/network/tasks/rpi_debian.yml +++ b/roles/network/tasks/rpi_debian.yml @@ -20,21 +20,44 @@ dest: /etc/dhcpcd.conf src: network/dhcpcd.conf.j2 +- name: Create dhcpcd hook for hostapd and ap0 when wifi_up_down True + template: + src: hostapd/50-hostapd + dest: /lib/dhcpcd/dhcpcd-hooks/50-hostapd + owner: root + group: root + mode: 0644 + when: wifi_up_down + +- name: Remove dhcpcd hook for hostapd if WiFi is not split using ap0 + file: + path: /lib/dhcpcd/dhcpcd-hooks/50-hostapd + state: absent + when: not wifi_up_down + - name: New Raspbian requires country code -- check for it - shell: grep country /etc/wpa_supplicant/wpa_supplicant.conf + shell: grep country /etc/wpa_supplicant/wpa_supplicant.conf | awk -F = '{print $2}' register: country_code ignore_errors: True + when: wifi_up_down and can_be_ap + +- name: Set country code for hostapd to value found in /etc/wpa_supplicant/wpa_supplicant.conf + set_fact: + host_country_code: "{{ country_code.stdout }}" + when: country_code.stdout is defined and country_code.stdout | length > 0 - name: Put country code ({{ host_country_code }}) in /etc/wpa_supplicant/wpa_supplicant.conf if nec - lineinfile: + lineinfile: path: /etc/wpa_supplicant/wpa_supplicant.conf regexp: "^country.*" line: country={{ host_country_code }} - when: country_code is defined and country_code.stdout == "" + when: country_code.stdout is defined and country_code.stdout | length == 0 -- name: Enable the WiFi with rfkill - shell: rfkill unblock 0 - ignore_errors: True +# 2024-12-18: SEE 'raspi-config nonint do_wifi_country {{ host_country_code }}' in roles/network/tasks/main.yml +# # This should go away, should only be unblocked by raspi-config +# - name: Enable the WiFi with rfkill +# shell: rfkill unblock wifi +# ignore_errors: True - name: Copy the bridge script for RPi template: @@ -49,21 +72,13 @@ src: network/dnsmasq-iiab when: iiab_lan_iface == "br0" -- name: Stopping services - include_tasks: down-debian.yml +#- name: Stopping services +# include_tasks: down-debian.yml - name: Reload systemd systemd: daemon_reload: yes -- name: Clone wifi if needed - systemd: - name: iiab-clone-wifi - state: started - when: discovered_wireless_iface != "none" - # Whereas sysd-netd-debian.yml uses... - # when: wifi_up_down and discovered_wireless_iface != "none" - - name: Restart the networking service if appropriate systemd: name: networking @@ -71,12 +86,6 @@ state: restarted when: iiab_wired_lan_iface is defined -- name: Restart hostapd when WiFi is present but not when using WiFi as gateway with wifi_up_down False - systemd: - name: hostapd - state: restarted - when: hostapd_enabled and (wifi_up_down or not no_net_restart) - #- name: Stop wpa_supplicant on Raspbian # shell: killall wpa_supplicant diff --git a/roles/network/tasks/squid.yml b/roles/network/tasks/squid.yml index 1f6acc39d..a84facb03 100644 --- a/roles/network/tasks/squid.yml +++ b/roles/network/tasks/squid.yml @@ -34,7 +34,7 @@ # Squid auto-creation of cache_dir (or the old way, 'squid -z') both fail: # "FATAL: Failed to make swap directory /library/cache: (13) Permission denied" # -# SEE ALSO: https://github.com/iiab/iiab/blob/master/roles/network/templates/squid/squid.conf.j2#L10-L30 +# SEE ALSO: https://github.com/iiab/iiab/blob/master/roles/network/templates/squid/squid.conf.j2#L12-L32 - name: Create Squid directory /library/cache ({{ proxy_user }}:{{ proxy_user }}, 0750) file: diff --git a/roles/network/tasks/sysd-netd-debian.yml b/roles/network/tasks/sysd-netd-debian.yml index 4b3048256..9868d5b96 100644 --- a/roles/network/tasks/sysd-netd-debian.yml +++ b/roles/network/tasks/sysd-netd-debian.yml @@ -1,4 +1,20 @@ # sysd-netd-debian.yml +- name: Install networkd-dispatcher + package: + name: networkd-dispatcher # 15kB download: Dispatcher service for systemd-networkd connection status changes + +# 2023-10-14 #3657, #3658, #3659: New RasPiOS 12/Bookworm issue. +# FWIW Ubuntu >= 22.10 offers 'systemd-resolved' as a distinct apt package. +# Whereas Ubuntu <= 22.04 bundled the functionality within apt package 'systemd' +# Debian 12/Bookworm (like Ubuntu >= 22.10) offers it as a distinct package: +# https://www.debian.org/releases/bookworm/amd64/release-notes/ch-information.en.html#systemd-resolved +- name: Install systemd-resolved (or intentionally show red error then continue, if apt package not available) + package: + name: systemd-resolved # 278kB download: For RasPiOS 12/Bookworm + ignore_errors: yes + #shell: apt -y install systemd-resolved || true + #when: is_raspbian and os_ver is version('raspbian-12', '>=') + - name: Copy the bridge script - Creates br0 template: dest: /etc/systemd/network/IIAB-Bridge.netdev @@ -40,23 +56,53 @@ template: dest: /etc/systemd/network/IIAB-Static.network src: network/systemd-static-net.j2 - when: wan_ip != "dhcp" and ( is_ubuntu_16 or not network_manager_active ) + when: wan_ip != "dhcp" and not network_manager_active + #when: wan_ip != "dhcp" and ( is_ubuntu_16 or not network_manager_active ) - #when: wan_ip != "dhcp" and not is_ubuntu_18 +- name: Create networkd-dispatcher diagnostic hook for recording network events + template: + owner: root + group: root + mode: 0755 + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/carrier.d/00-iiab-debug' } + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/degraded.d/00-iiab-debug' } + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/dormant.d/00-iiab-debug' } + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/no-carrier.d/00-iiab-debug' } + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/off.d/00-iiab-debug' } + - { src: 'hostapd/00-iiab-debug', dest: '/etc/networkd-dispatcher/routable.d/00-iiab-debug' } + # when: discovered_wireless_iface != "none" or discovered_wired_iface != "none" -- name: Stopping services - include_tasks: down-debian.yml +- name: Create networkd-dispatcher hook for ap0 on RPi hardware with wifi_up_down True + template: + owner: root + group: root + mode: 0755 + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: 'hostapd/netd-disp', dest: '/etc/networkd-dispatcher/carrier.d/iiab-wifi' } + - { src: 'hostapd/netd-disp', dest: '/etc/networkd-dispatcher/no-carrier.d/iiab-wifi' } + - { src: 'hostapd/netd-disp2', dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi2' } + when: discovered_wireless_iface != "none" and rpi_model != "none" and wifi_up_down + +- name: Remove networkd-dispatcher hook for ap0 on RPi hardware with wifi_up_down False + file: + path: "{{ item.dest }}" + state: absent + with_items: + - { dest: '/etc/networkd-dispatcher/carrier.d/iiab-wifi' } + - { dest: '/etc/networkd-dispatcher/no-carrier.d/iiab-wifi' } + - { dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi' } + - { dest: '/etc/networkd-dispatcher/routable.d/iiab-wifi2' } + when: discovered_wireless_iface != "none" and rpi_model != "none" and not wifi_up_down - name: Reload systemd systemd: daemon_reload: yes -- name: Clone wifi if needed - systemd: - name: iiab-clone-wifi - state: started - when: wifi_up_down and discovered_wireless_iface != "none" - - name: Enable & Restart systemd-networkd.service systemd: name: systemd-networkd @@ -64,15 +110,9 @@ enabled: yes masked: no -- name: Enable & Restart networkd-dispatcher.service +- name: Enable & Restart systemd-resolved.service systemd: - name: networkd-dispatcher + name: systemd-resolved state: restarted enabled: yes masked: no - -- name: Restart hostapd when WiFi is present but not when using WiFi as gateway with wifi_up_down False - systemd: - name: hostapd - state: restarted - when: hostapd_enabled and (wifi_up_down or not no_net_restart) diff --git a/roles/network/templates/captive-portal/captive-portal.py.j2 b/roles/network/templates/captive-portal.unused/captive-portal.py.j2 similarity index 100% rename from roles/network/templates/captive-portal/captive-portal.py.j2 rename to roles/network/templates/captive-portal.unused/captive-portal.py.j2 diff --git a/roles/network/templates/dhcp/dhcpd-env.j2 b/roles/network/templates/dhcp.unused/dhcpd-env.j2 similarity index 100% rename from roles/network/templates/dhcp/dhcpd-env.j2 rename to roles/network/templates/dhcp.unused/dhcpd-env.j2 diff --git a/roles/network/templates/dhcp.unused/dhcpd-iiab.conf.j2 b/roles/network/templates/dhcp.unused/dhcpd-iiab.conf.j2 new file mode 100644 index 000000000..66cd3e706 --- /dev/null +++ b/roles/network/templates/dhcp.unused/dhcpd-iiab.conf.j2 @@ -0,0 +1,48 @@ +# +# School server 1 DHCP Server Configuration file. +# +ddns-update-style interim; +#ignore client-updates; + +option domain-name "{{ iiab_domain }}"; +option domain-name-servers {{ lan_ip }}; +option ntp-servers {{ lan_ip }}; + +{% if network_172 %} +subnet 172.18.96.0 netmask 255.255.224.0 { + {% if iiab_network_mode == "Gateway" %} + option routers {{ lan_ip }}; + {% endif %} + option subnet-mask 255.255.224.0; + option broadcast-address 172.18.127.255; + # Description of network allocations in old OLPC school server + # this is the whole range we have available - 8K addresses + # range 172.18.96.2 172.18.127.254; + # instead, we'll save 510 addresses for later. + range 172.18.96.2 172.18.125.254; + # the other /24s: + # -> 172.18.126.0/24 for static IP addresses + # for printers, AP management consoles, etc. + # -> 172.18.127.0/24 for temporary addresses for + # XO activation + + # As this subnet is wired or wifi a/b/g, these lease + # times are on the long side + default-lease-time 10800; + max-lease-time 21600; +} +{% else %} +subnet 10.10.10.0 netmask 255.255.255.0 { + {% if iiab_network_mode == "Gateway" %} + option routers {{ lan_ip }}; + {% endif %} + option subnet-mask 255.255.255.0; + option broadcast-address 10.10.10.255; + range 10.10.10.11 10.10.10.254; + + # As this subnet is wired or wifi a/b/g, these lease + # times are on the long side + default-lease-time 10800; + max-lease-time 21600; +} +{% endif %} diff --git a/roles/network/templates/dhcp/dhcpd.service b/roles/network/templates/dhcp.unused/dhcpd.service similarity index 100% rename from roles/network/templates/dhcp/dhcpd.service rename to roles/network/templates/dhcp.unused/dhcpd.service diff --git a/roles/network/templates/dhcp/dhcpd-iiab.conf.j2 b/roles/network/templates/dhcp/dhcpd-iiab.conf.j2 deleted file mode 100644 index a3c844120..000000000 --- a/roles/network/templates/dhcp/dhcpd-iiab.conf.j2 +++ /dev/null @@ -1,31 +0,0 @@ -# -# School server 1 DHCP Server Configuration file. -# -ddns-update-style interim; -#ignore client-updates; - -option domain-name "{{ iiab_domain }}"; -option domain-name-servers 172.18.96.1; -option ntp-servers 172.18.96.1; - -subnet 172.18.96.0 netmask 255.255.224.0 { - {% if iiab_network_mode == "Gateway" %} - option routers 172.18.96.1; - {% endif %} - option subnet-mask 255.255.224.0; - option broadcast-address 172.18.127.255; - # this is the whole range we have available - 8K addresses - # range 172.18.96.2 172.18.127.254; - # instead, we'll save 510 addresses for later. - range 172.18.96.2 172.18.125.254; - # the other /24s: - # -> 172.18.126.0/24 for static IP addresses - # for printers, AP management consoles, etc. - # -> 172.18.127.0/24 for temporary addresses for - # XO activation - - # As this subnet is wired or wifi a/b/g, these lease - # times are on the long side - default-lease-time 10800; - max-lease-time 21600; -} diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index 60f44774a..77717a748 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -34,12 +34,12 @@ IPTABLES=/usr/sbin/iptables IPTABLES_DATA=/etc/sysconfig/iptables {% endif %} -# 2021-08-18: bash scripts using default_vars.yml &/or local_vars.yml +# 2023-02-25: bash scripts using default_vars.yml &/or local_vars.yml # https://github.com/iiab/iiab-factory/blob/master/iiab -# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L13 +# https://github.com/iiab/iiab/blob/master/roles/firmware/templates/iiab-check-firmware#L10-14 # https://github.com/iiab/iiab/blob/master/roles/network/templates/gateway/iiab-gen-iptables#L48-L52 -# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L25-L34 -# https://github.com/iiab/iiab/blob/master/roles/openvpn/templates/iiab-support READS AND WRITES, INCL NON-BOOLEAN +# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region#L23-L39 +# https://github.com/iiab/iiab/blob/master/roles/0-DEPRECATED-ROLES/openvpn/templates/iiab-support READS AND WRITES, INCL NON-BOOLEAN # "awk '{print $2}'" almost works, but: (1) Fails to remove outer quotes, and # (2) Chops up Ansible vars containing multiple words w/o surrounding quotes. @@ -64,7 +64,7 @@ echo "iiab_gateway_enabled: $iiab_gateway_enabled" echo #network_mode=`grep iiab_network_mode_applied /etc/iiab/iiab.ini | gawk '{print $3}'` #echo -e "Network Mode: $network_mode\n" -lan_ip=$(iiab_var_value lan_ip) # 172.18.96.1 +lan_ip=$(iiab_var_value lan_ip) # e.g. 10.10.10.10 ports_externally_visible=$(iiab_var_value ports_externally_visible) gw_block_https=$(iiab_var_value gw_block_https) diff --git a/roles/network/templates/gateway/iiab-internet-off b/roles/network/templates/gateway/iiab-internet-off index d2c4c404d..f5a2e0578 100644 --- a/roles/network/templates/gateway/iiab-internet-off +++ b/roles/network/templates/gateway/iiab-internet-off @@ -11,5 +11,5 @@ https://github.com/iiab/iiab/wiki/IIAB-Networking#firewall-iptables WARNING: If you want to _permanently_ change your IIAB's default behavior (i.e. to specify whether student/client devices should have Internet or not, in general!) then modify variable 'iiab_gateway_enabled' in -/etc/iiab/local_vars.yml β€” and finally run 'cd /opt/iiab/iiab ; ./iiab-network' +/etc/iiab/local_vars.yml β€” and finally run: sudo iiab-network EOF diff --git a/roles/network/templates/gateway/iiab-internet-on b/roles/network/templates/gateway/iiab-internet-on index be99c1533..d616498a7 100644 --- a/roles/network/templates/gateway/iiab-internet-on +++ b/roles/network/templates/gateway/iiab-internet-on @@ -11,5 +11,5 @@ https://github.com/iiab/iiab/wiki/IIAB-Networking#firewall-iptables WARNING: If you want to _permanently_ change your IIAB's default behavior (i.e. to specify whether student/client devices should have Internet or not, in general!) then modify variable 'iiab_gateway_enabled' in -/etc/iiab/local_vars.yml β€” and finally run 'cd /opt/iiab/iiab ; ./iiab-network' +/etc/iiab/local_vars.yml β€” and finally run: sudo iiab-network EOF diff --git a/roles/network/templates/hostapd/50-hostapd b/roles/network/templates/hostapd/50-hostapd index 37a363b72..5b13b14b5 100644 --- a/roles/network/templates/hostapd/50-hostapd +++ b/roles/network/templates/hostapd/50-hostapd @@ -1,4 +1,14 @@ if [ "$interface" = "br0" ] && [ $if_up = "true" ]; then + WPA=$(grep country /etc/wpa_supplicant/wpa_supplicant.conf | awk -F = '{print $2}') + AP=$(grep country_code /etc/hostapd/hostapd.conf | awk -F = '{print $2}') + if ! [ "$WPA" = "$AP" ]; then + sed -i -e "s/^country_code.*/country_code=$WPA /" /etc/hostapd/hostapd.conf + echo "50-iiab set country_code $WPA" + syslog info "50-iiab set country_code $WPA" + echo "THIS MACHINE SHOULD BE REBOOTED" + syslog info "THIS MACHINE SHOULD BE REBOOTED 50-iiab country_code" +# systemctl restart hostapd + fi syslog info "50-iiab IF_UP br0 restarting dnsmasq - kicking ap0" ip link set ap0 up systemctl --no-block restart dnsmasq @@ -10,8 +20,9 @@ if [ "$interface" = "wlan0" ]; then syslog info "50-iiab CARRIER change wlan0" # wpa_supplicant wants MHz for frequency= while hostapd wants channel..... whatever # FREQ=`iw wlan0 info|grep channel|cut -d' ' -f9` - FREQ=`iw wlan0 info|grep channel|cut -d' ' -f2` + FREQ=$(iw wlan0 info|grep channel|cut -d' ' -f2) FREQ2="" + for result in $FREQ; do echo "frequency is $result for carrier" if [ $result -lt 13 ]; then @@ -22,14 +33,14 @@ if [ "$interface" = "wlan0" ]; then done echo "Using $FREQ2 for carrier" syslog info "50-iiab set channel $FREQ2" - HOSTAPD=`grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}'` + HOSTAPD=$(grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}') echo "Hostapd set for $HOSTAPD" if [ $FREQ2 -ne $HOSTAPD ] && [ ! -z $FREQ2 ]; then echo "Editing Hostapd for channel $FREQ2" cp /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf sed -i -e "s/^channel.*/channel=$FREQ /" /etc/hostapd/hostapd.conf echo "THIS MACHINE SHOULD BE REBOOTED" - syslog info "THIS MACHINE SHOULD BE REBOOTED" + syslog info "THIS MACHINE SHOULD BE REBOOTED 50-iiab channel" # systemctl restart hostapd fi fi diff --git a/roles/network/templates/hostapd/hostapd.legacy.j2 b/roles/network/templates/hostapd/hostapd.legacy.j2 index 4094b812a..d6f0acf4f 100644 --- a/roles/network/templates/hostapd/hostapd.legacy.j2 +++ b/roles/network/templates/hostapd/hostapd.legacy.j2 @@ -1,5 +1,9 @@ [Unit] Description=Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator +# https://unix.stackexchange.com/questions/257888/systemd-wait-for-network-interface-to-be-up-before-running-service/417839#417839 +# 2022-08-22: #3352 Raspberry Pi Zero W requires 2 lines below... +BindsTo=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device +After=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device Before=network.target Wants=network-pre.target diff --git a/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 b/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 index 87ae2fa09..92ee86c09 100644 --- a/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 +++ b/roles/network/templates/hostapd/iiab-clone-wifi.service.j2 @@ -1,6 +1,10 @@ [Unit] Description=IIAB ap0 clone wifi device Wants=network-pre.target +# https://unix.stackexchange.com/questions/257888/systemd-wait-for-network-interface-to-be-up-before-running-service/417839#417839 +# 2022-08-22: #3352 Raspberry Pi Zero W requires 2 lines below... +BindsTo=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device +After=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device After=network-pre.target Before=dhcpcd.service Before=wpa_supplicant.service diff --git a/roles/network/templates/network/iiab-hotspot-off b/roles/network/templates/hostapd/iiab-hotspot-off similarity index 59% rename from roles/network/templates/network/iiab-hotspot-off rename to roles/network/templates/hostapd/iiab-hotspot-off index 78d86cdd1..fb45603a6 100755 --- a/roles/network/templates/network/iiab-hotspot-off +++ b/roles/network/templates/hostapd/iiab-hotspot-off @@ -1,5 +1,9 @@ #!/bin/bash -sed -i -e "s/^HOSTAPD_ENABLED.*/HOSTAPD_ENABLED=False/" {{ iiab_env_file }} +{% if not network_enabled %} +echo -e "Networking role disabled\n" +echo -e "For details, see: https://github.com/iiab/iiab/pull/3302\n" +{% else %} +sed -i "s/^HOSTAPD_ENABLED.*/HOSTAPD_ENABLED=False/" {{ iiab_env_file }} systemctl disable hostapd systemctl stop hostapd {% if wifi_up_down %} @@ -7,13 +11,12 @@ systemctl disable iiab-clone-wifi.service systemctl disable iiab-wifi-test.service systemctl stop iiab-clone-wifi.service echo " IIAB hotspot access point Disabled" -exit 0 +#exit 0 {% else %} -{% if is_raspbian %} +echo " IIAB hotspot access point Disabled" +{% if dhcpcd_result == "enabled" %} # hotspot-off before ap0_updown -sed -i -e "s/^denyinterfaces/#denyinterfaces/" /etc/dhcpcd.conf -systemctl disable hostapd -systemctl stop hostapd +sed -i "s/^denyinterfaces/#denyinterfaces/" /etc/dhcpcd.conf #systemctl disable dnsmasq #systemctl stop dnsmasq systemctl daemon-reload @@ -27,12 +30,15 @@ systemctl restart dhcpcd # ip link set dev wlan0 promisc on #fi {% else %} -#ubuntu +#ubuntu (or Mint, or pure Debian?) if [ -f /etc/NetworkManager/conf.d/wifi-manage.conf ]; then - sed -i -e "s|managed=0|managed=1|" /etc/NetworkManager/conf.d/wifi-manage.conf + sed -i "s|managed=0|managed=1|" /etc/NetworkManager/conf.d/wifi-manage.conf fi -echo -e "\nPlease reboot to enable upstream WiFi access.\n" -exit 0 +echo -e "\nIf you're enabling upstream WiFi, please reboot now.\n" +#exit 0 +{% endif %} +#if dhcpcd_result == "enabled" {% endif %} #wifi_up_down {% endif %} +#network_enabled diff --git a/roles/network/templates/network/iiab-hotspot-on b/roles/network/templates/hostapd/iiab-hotspot-on similarity index 55% rename from roles/network/templates/network/iiab-hotspot-on rename to roles/network/templates/hostapd/iiab-hotspot-on index d92cb5f21..35ccc7adf 100755 --- a/roles/network/templates/network/iiab-hotspot-on +++ b/roles/network/templates/hostapd/iiab-hotspot-on @@ -1,16 +1,25 @@ #!/bin/bash -sed -i -e "s/^HOSTAPD_ENABLED.*/HOSTAPD_ENABLED=True/" {{ iiab_env_file }} +{% if not network_enabled %} +echo -e "Networking role disabled\n" +echo -e "For details, see: https://github.com/iiab/iiab/pull/3302\n" +{% else %} +{% if not can_be_ap %} +echo -e "\nUH-OH: Your Wi-Fi firmware doesn't support AP mode, according to 'iw list'\n" +echo -e "If you add Wi-Fi hardware, run 'cd /opt/iiab/iiab' then 'sudo ./iiab-network'\n" +echo -e "For details, see: https://github.com/iiab/iiab/pull/3179\n" +exit 1 +{% else %} +sed -i "s/^HOSTAPD_ENABLED.*/HOSTAPD_ENABLED=True/" {{ iiab_env_file }} {% if wifi_up_down %} systemctl enable iiab-clone-wifi.service systemctl enable hostapd systemctl enable iiab-wifi-test.service -echo -e "\nPlease reboot to activate hostapd feature.\n" -exit 0 +#exit 0 {% else %} -{% if is_raspbian %} +{% if dhcpcd_result == "enabled" %} # just do what we have always done in hotspot-on cp -f /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf -sed -i -e "s/^#denyinterfaces/denyinterfaces/" /etc/dhcpcd.conf +sed -i "s/^#denyinterfaces/denyinterfaces/" /etc/dhcpcd.conf # shut down wlan0 in case connected to network ip link set wlan0 down systemctl enable hostapd @@ -28,13 +37,19 @@ systemctl start dnsmasq # ip link set dev wlan0 promisc off #fi {% else %} -#ubuntu +#ubuntu (or Mint, or pure Debian?) if [ -f /etc/NetworkManager/conf.d/wifi-manage.conf ]; then - sed -i -e "s|managed=1|managed=0|" /etc/NetworkManager/conf.d/wifi-manage.conf + sed -i "s|managed=1|managed=0|" /etc/NetworkManager/conf.d/wifi-manage.conf fi systemctl enable hostapd -echo -e "\nPlease reboot to activate hostapd feature.\n" -exit 0 +#exit 0 +{% endif %} +#if dhcpcd_result == "enabled" {% endif %} #wifi_up_down {% endif %} +#can_be_ap +{% endif %} +#network_enabled + +echo -e "\nPlease reboot to activate hostapd feature.\n" diff --git a/roles/network/templates/hostapd/iiab-test-wifi.j2 b/roles/network/templates/hostapd/iiab-test-wifi.j2 index a87dd003b..709a92fbb 100755 --- a/roles/network/templates/hostapd/iiab-test-wifi.j2 +++ b/roles/network/templates/hostapd/iiab-test-wifi.j2 @@ -1,90 +1,132 @@ -#!/bin/bash +#!/bin/sh + +# 2023-04-24 PR #3542 / PR #3549 context: +# "systemd-network" "RasPiOS" have files with the client wifi info within them, +# those can be parsed for the ssid without needing the related service running +# first. +# "Netplan systemd" "NetworkManager" need to be running to be able to parse for +# the ssid, from the generated config file for "Netplan systemd" and from the +# running environment for "NetworkManager". +# "iiab-wifi-test.service" acts as a bit of a traffic cop keeping the ordering +# of the services more deterministic when active and tries to catch a channel +# mismatch between client wifi's current setting and what is contained within +# hostapd.conf early in the boot process. + IFACE={{ discovered_wireless_iface }} -RASPBIAN=0 NETPLAN=0 -SSID="NA" -# when we get here br0 should be available and dbus wpa_supplicant was started if enabled. None -# of the backends that use wpa_supplicant should be active yet based on the Before= After= lines -# in the iiab-wifi-test.service unit file. +SSID="" +# when we get here br0 should be available and dbus wpa_supplicant was started if enabled. Some +# of the backends that use wpa_supplicant should be active based on the Before= After= lines in +# the iiab-wifi-test.service unit file. +# https://github.com/iiab/iiab/pull/3542#issuecomment-1519647266 + +echo "iiab-test-wifi called" +echo "running pid $$" # covers systemd-networkd if [ -f /etc/wpa_supplicant/wpa_supplicant-$IFACE.conf ]; then - SSID=`grep ssid /etc/wpa_supplicant/wpa_supplicant-$IFACE.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//` + echo "systemd-network" + SSID=$(grep ssid /etc/wpa_supplicant/wpa_supplicant-$IFACE.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//) fi -# covers raspbian -if [ -f /etc/wpa_supplicant/wpa_supplicant.conf ]; then - RASPBIAN=1 - if /usr/sbin/rfkill list wifi | grep -q "Soft blocked: yes" ; then - echo "unblocking WiFi" - rfkill unblock wifi - fi - SSID=`grep ssid /etc/wpa_supplicant/wpa_supplicant.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//` +# covers stock raspbian +if [ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && [ -n "$(pgrep dhcpcd)" ]; then + echo "RasPiOS" + SSID=$(grep ssid /etc/wpa_supplicant/wpa_supplicant.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//) fi -# covers netplan's bugs workaround # https://bugs.launchpad.net/ubuntu/+source/linux-firmware/+bug/1862760 # https://bugs.launchpad.net/netplan/+bug/1951586 +# WiFi country code progress on arm64 OS's discussed on #3078 +# covers netplan systemd use on server with bug workarounds if [ -f /run/netplan/wpa-$IFACE.conf ]; then NETPLAN=1 - SSID=`grep ssid /run/netplan/wpa-$IFACE.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//` - echo "cover netplan lack of country=" - sed -i 's|ctrl_interface=/run/wpa_supplicant|&\ncountry=US|' /run/netplan/wpa-$IFACE.conf -fi -# IIAB hint for NetworkManager -# could scrape /etc/NetworkManager/system-connections/ looking for ssid -if [ -f /etc/iiab/iiab.env ]; then - source /etc/iiab/iiab.env - if [ ! -z $CLIENT_SSID ]; then - SSID=$CLIENT_SSID + echo "Netplan systemd" + SSID=$(grep ssid /run/netplan/wpa-$IFACE.conf | awk -F = '{print $2}' | sed -r s/\"// | sed -r s/\"//) + REG_DOM=$(grep country /run/netplan/wpa-$IFACE.conf | awk -F = '{ print $2 }') + if [ -z "$REG_DOM" ]; then + NETPLAN=2 + echo "cover netplan wifi client lack of country= setting to {{ host_country_code }}" + sed -i "s|ctrl_interface=/run/wpa_supplicant|&\ncountry={{ host_country_code }}|" /run/netplan/wpa-$IFACE.conf + else + echo "set hostapd wifi country to $REG_DOM" + if [ -f /etc/hostapd/hostapd.conf.iiab ]; then + sed -i "s|^country.*|country_code=$REG_DOM|" /etc/hostapd/hostapd.conf.iiab + cp /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf + fi fi fi + +# NetworkManager +if [ -z "$SSID" ] && [ -n "$(pgrep NetworkManager)" ]; then + echo "NetworkManager" + sleep 15 + SSID=$(iw $IFACE info | grep ssid | awk '{print $2}' ) +fi echo "ssid is $SSID" -if [[ $SSID == "" ]] || [[ $SSID == "NA" ]]; then - echo "Couldn't find ssid $SSID to use exiting" - if [ $NETPLAN -eq 1 ]; then + +if [ -z "$SSID" ]; then + echo "Couldn't find an UPSTREAM SSID in files like wpa_supplicant.conf -- so exiting." + echo "CLARIF: This is normal when UPSTREAM WIFI is not active, as there would be no" + echo "UPSTREAM SSID to extract, e.g. if 'wifi_up_down: False'" + if [ $NETPLAN -gt 0 ]; then echo "Netplan1" fi exit 0 fi + +if [ $NETPLAN -gt 0 ]; then + echo "Netplan2 sleep 10" + sleep 10 + wifi_processes=$(ps -A | grep wpa_supplicant | wc -l) + if [ $wifi_processes -eq 1 ]; then + # This is more of a netplan workaround should go away. + echo "Problem - Now Starting netplan wifi" + NETPLAN=2 + else + echo "Not Restarting netplan wifi sleep 20" + sleep 20 + fi + # This one handles the changing of the country code from above + if [ $NETPLAN -eq 2 ]; then + echo "Restarting netplan-wpa-$IFACE sleep 20" + /bin/systemctl --no-block restart netplan-wpa-$IFACE.service + sleep 20 + fi +fi +sleep 10 wpa_cli -i $IFACE scan > /dev/null sleep 2 -FREQ=`wpa_cli -i $IFACE scan_results | grep $SSID | awk '{print $2}'` +FREQ=$(wpa_cli -i $IFACE scan_results | grep "$SSID" | awk '{print $2}') for result in $FREQ; do echo "frequency is $result for $SSID" - if [ $result -lt 2485 ] && [ $result -gt 2407 ]; then + if [ "$result" -lt 2485 ] && [ "$result" -gt 2407 ]; then FREQ2=$result break else echo "channel $result is 5Ghz - ignoring" fi done + echo "Using $FREQ2 for $SSID" -if [[ $FREQ2 == "" ]]; then + +if [ -z "$FREQ2" ]; then echo "Couldn't find frequency to use exiting" - if [ $NETPLAN -eq 1 ]; then - echo "Netplan2" + if [ $NETPLAN -gt 0 ]; then + echo "Netplan3" fi exit 0 fi -# ubuntu on boot exits at this point timing - issue with wpa_cli and scanning -CHAN=$(($FREQ2 - 2407 )) -CHAN=$(($CHAN / 5 )) + +CHAN=$((FREQ2 - 2407)) +CHAN=$((CHAN / 5)) echo "channel is $CHAN for $SSID" -HOSTAPD=`grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}'` +HOSTAPD=$(grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}') echo "Hostapd set for $HOSTAPD" -if [ $CHAN -ne $HOSTAPD ]; then +if [ "$CHAN" -ne "$HOSTAPD" ]; then echo "Editing Hostapd for channel $CHAN" cp /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf sed -i -e "s/^channel.*/channel=$CHAN/" /etc/hostapd/hostapd.conf + /bin/systemctl --no-block restart hostapd + echo "Restarted hostapd" fi -systemctl stop wpa_supplicant -systemctl stop hostapd -systemctl start hostapd -systemctl start wpa_supplicant -if [ $NETPLAN -eq 1 ]; then - echo "Netplan3" - # This is more of a netplan workaround should go away. - systemctl restart netplan-wpa-$IFACE.service -fi -exit 0 diff --git a/roles/network/templates/hostapd/iiab-wifi-test.service.j2 b/roles/network/templates/hostapd/iiab-wifi-test.service.j2 index 682680a07..baa73eed6 100644 --- a/roles/network/templates/hostapd/iiab-wifi-test.service.j2 +++ b/roles/network/templates/hostapd/iiab-wifi-test.service.j2 @@ -1,15 +1,27 @@ [Unit] Description=IIAB find channel freq for ssid -After=wpa_supplicant.service -Wants=wpa_supplicant.service -Before=hostapd.service +Requisite=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device +Requisite=iiab-clone-wifi.service +Requisite=wpa_supplicant.service + +# 2023-04-24 PR #3549: c49adcf went too far and broke netplan-systemd +#Requires=network-pre.target +#BindsTo=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device +#After=sys-subsystem-net-devices-{{ discovered_wireless_iface }}.device +#After=iiab-clone-wifi.service + +#After=network-pre.target +#After=wpa_supplicant.service +#Wants=wpa_supplicant.service + +After=NetworkManager.service +After=netplan-wpa-{{ discovered_wireless_iface }}.service Before=dhcpcd.service Before=wpa_supplicant@{{ discovered_wireless_iface }}.service -Before=NetworkManager.service -Before=netplan-wpa-{{ discovered_wireless_iface }}.service -Before=network.target +#Before=network.target [Service] +TimeoutStartSec=120 Type=oneshot RemainAfterExit=yes ExecStart=/usr/sbin/iiab-test-wifi diff --git a/roles/network/templates/hostapd/netd-disp2 b/roles/network/templates/hostapd/netd-disp2 index 78e258627..2e39b26c2 100644 --- a/roles/network/templates/hostapd/netd-disp2 +++ b/roles/network/templates/hostapd/netd-disp2 @@ -2,17 +2,15 @@ if [ "$IFACE" == "{{ discovered_wireless_iface }}" ]; then echo "NET-DISP-WiFi $IFACE $STATE" # If we are here we have a dhcp ip address - CHAN=`iw $IFACE info|grep channel|cut -d' ' -f2` + CHAN=$(iw "$IFACE" info|grep channel|cut -d' ' -f2) echo "Using channel $CHAN for carrier" - HOSTAPD=`grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}'` + HOSTAPD=$(grep channel /etc/hostapd/hostapd.conf | awk -F = '{print $2}') echo "Hostapd set for $HOSTAPD" if [ $CHAN -ne $HOSTAPD ] && [ $CHAN -lt 14 ]; then echo "Editing Hostapd for channel $CHAN" cp /etc/hostapd/hostapd.conf.iiab /etc/hostapd/hostapd.conf - sed -i -e "s/^channel.*/channel=$CHAN/" /etc/hostapd/hostapd.conf - systemctl stop wpa_supplicant + sed -i "s/^channel.*/channel=$CHAN/" /etc/hostapd/hostapd.conf systemctl restart hostapd - systemctl start wpa_supplicant else echo "Upstream Channel greater than 13 or is the same - not changing hostapd.conf" fi diff --git a/roles/network/templates/named/bind9.service b/roles/network/templates/named.unused/bind9.service similarity index 100% rename from roles/network/templates/named/bind9.service rename to roles/network/templates/named.unused/bind9.service diff --git a/roles/network/templates/named/dns-jail.conf b/roles/network/templates/named.unused/dns-jail.conf similarity index 100% rename from roles/network/templates/named/dns-jail.conf rename to roles/network/templates/named.unused/dns-jail.conf diff --git a/roles/network/templates/named/dummy b/roles/network/templates/named.unused/dummy similarity index 100% rename from roles/network/templates/named/dummy rename to roles/network/templates/named.unused/dummy diff --git a/roles/network/templates/named/localdomain.zone b/roles/network/templates/named.unused/localdomain.zone similarity index 100% rename from roles/network/templates/named/localdomain.zone rename to roles/network/templates/named.unused/localdomain.zone diff --git a/roles/network/templates/named/localhost.zone b/roles/network/templates/named.unused/localhost.zone similarity index 100% rename from roles/network/templates/named/localhost.zone rename to roles/network/templates/named.unused/localhost.zone diff --git a/roles/network/templates/named/named b/roles/network/templates/named.unused/named similarity index 100% rename from roles/network/templates/named/named rename to roles/network/templates/named.unused/named diff --git a/roles/network/templates/named/named-iiab.conf.j2 b/roles/network/templates/named.unused/named-iiab.conf.j2 similarity index 100% rename from roles/network/templates/named/named-iiab.conf.j2 rename to roles/network/templates/named.unused/named-iiab.conf.j2 diff --git a/roles/network/templates/named/named.blackhole b/roles/network/templates/named.unused/named.blackhole similarity index 100% rename from roles/network/templates/named/named.blackhole rename to roles/network/templates/named.unused/named.blackhole diff --git a/roles/network/templates/named/named.broadcast b/roles/network/templates/named.unused/named.broadcast similarity index 100% rename from roles/network/templates/named/named.broadcast rename to roles/network/templates/named.unused/named.broadcast diff --git a/roles/network/templates/named/named.ip6.local b/roles/network/templates/named.unused/named.ip6.local similarity index 100% rename from roles/network/templates/named/named.ip6.local rename to roles/network/templates/named.unused/named.ip6.local diff --git a/roles/network/templates/named/named.j2 b/roles/network/templates/named.unused/named.j2 similarity index 100% rename from roles/network/templates/named/named.j2 rename to roles/network/templates/named.unused/named.j2 diff --git a/roles/network/templates/named/named.local b/roles/network/templates/named.unused/named.local similarity index 100% rename from roles/network/templates/named/named.local rename to roles/network/templates/named.unused/named.local diff --git a/roles/network/templates/named/named.rfc1912.zones b/roles/network/templates/named.unused/named.rfc1912.zones similarity index 100% rename from roles/network/templates/named/named.rfc1912.zones rename to roles/network/templates/named.unused/named.rfc1912.zones diff --git a/roles/network/templates/named/named.root b/roles/network/templates/named.unused/named.root similarity index 100% rename from roles/network/templates/named/named.root rename to roles/network/templates/named.unused/named.root diff --git a/roles/network/templates/named/named.root.hints b/roles/network/templates/named.unused/named.root.hints similarity index 100% rename from roles/network/templates/named/named.root.hints rename to roles/network/templates/named.unused/named.root.hints diff --git a/roles/network/templates/named/named.service b/roles/network/templates/named.unused/named.service similarity index 100% rename from roles/network/templates/named/named.service rename to roles/network/templates/named.unused/named.service diff --git a/roles/network/templates/named/named.zero b/roles/network/templates/named.unused/named.zero similarity index 100% rename from roles/network/templates/named/named.zero rename to roles/network/templates/named.unused/named.zero diff --git a/roles/network/templates/named/school.external.zone.db b/roles/network/templates/named.unused/school.external.zone.db similarity index 100% rename from roles/network/templates/named/school.external.zone.db rename to roles/network/templates/named.unused/school.external.zone.db diff --git a/roles/network/templates/named/school.internal.zone.16.in-addr.db.j2 b/roles/network/templates/named.unused/school.internal.zone.16.in-addr.db.j2 similarity index 100% rename from roles/network/templates/named/school.internal.zone.16.in-addr.db.j2 rename to roles/network/templates/named.unused/school.internal.zone.16.in-addr.db.j2 diff --git a/roles/network/templates/named/school.internal.zone.32.in-addr.db.j2 b/roles/network/templates/named.unused/school.internal.zone.32.in-addr.db.j2 similarity index 100% rename from roles/network/templates/named/school.internal.zone.32.in-addr.db.j2 rename to roles/network/templates/named.unused/school.internal.zone.32.in-addr.db.j2 diff --git a/roles/network/templates/named/school.internal.zone.48.in-addr.db.j2 b/roles/network/templates/named.unused/school.internal.zone.48.in-addr.db.j2 similarity index 100% rename from roles/network/templates/named/school.internal.zone.48.in-addr.db.j2 rename to roles/network/templates/named.unused/school.internal.zone.48.in-addr.db.j2 diff --git a/roles/network/templates/named.unused/school.internal.zone.db.j2 b/roles/network/templates/named.unused/school.internal.zone.db.j2 new file mode 100644 index 000000000..ec930bee8 --- /dev/null +++ b/roles/network/templates/named.unused/school.internal.zone.db.j2 @@ -0,0 +1,27 @@ +@ in soa localhost. root 1 3H 15M 1W 1D + ns localhost. + +{{ iiab_hostname }} IN A {{ lan_ip }} +schoolserver IN A {{ lan_ip }} +school IN A {{ lan_ip }} +www IN A {{ lan_ip }} +ntp IN A {{ lan_ip }} +time IN A {{ lan_ip }} +presence IN A {{ lan_ip }} +xs IN A {{ lan_ip }} +library IN A {{ lan_ip }} +box IN A {{ lan_ip }} + + +conference.schoolserver IN A {{ lan_ip }} + + +; translations of school - in plain latin script +; or un punycode of the utf-8 representation + +; es - escuela +escuela IN CNAME school + +; de - schule +schule IN CNAME school + diff --git a/roles/network/templates/named/school.internal.zone.in-addr.db.j2 b/roles/network/templates/named.unused/school.internal.zone.in-addr.db.j2 similarity index 100% rename from roles/network/templates/named/school.internal.zone.in-addr.db.j2 rename to roles/network/templates/named.unused/school.internal.zone.in-addr.db.j2 diff --git a/roles/network/templates/named/school.local.zone.db b/roles/network/templates/named.unused/school.local.zone.db.j2 similarity index 58% rename from roles/network/templates/named/school.local.zone.db rename to roles/network/templates/named.unused/school.local.zone.db.j2 index 3d0619e96..8b4bc384e 100644 --- a/roles/network/templates/named/school.local.zone.db +++ b/roles/network/templates/named.unused/school.local.zone.db.j2 @@ -3,18 +3,18 @@ @ in soa localhost. root 1 3H 15M 1W 1D ns localhost. -{{ iiab_hostname }} IN A 172.18.96.1 -schoolserver IN A 172.18.96.1 -school IN A 172.18.96.1 -www IN A 172.18.96.1 -ntp IN A 172.18.96.1 -time IN A 172.18.96.1 -presence IN A 172.18.96.1 -xs IN A 172.18.96.1 -library IN A 172.18.96.1 -box IN A 172.18.96.1 +{{ iiab_hostname }} IN A {{ lan_ip }} +schoolserver IN A {{ lan_ip }} +school IN A {{ lan_ip }} +www IN A {{ lan_ip }} +ntp IN A {{ lan_ip }} +time IN A {{ lan_ip }} +presence IN A {{ lan_ip }} +xs IN A {{ lan_ip }} +library IN A {{ lan_ip }} +box IN A {{ lan_ip }} -conference.schoolserver IN A 172.18.96.1 +conference.schoolserver IN A {{ lan_ip }} ; translations of school - in plain latin script diff --git a/roles/network/templates/named/school.internal.zone.db b/roles/network/templates/named/school.internal.zone.db deleted file mode 100644 index 99a131aa2..000000000 --- a/roles/network/templates/named/school.internal.zone.db +++ /dev/null @@ -1,27 +0,0 @@ -@ in soa localhost. root 1 3H 15M 1W 1D - ns localhost. - -{{ iiab_hostname }} IN A 172.18.96.1 -schoolserver IN A 172.18.96.1 -school IN A 172.18.96.1 -www IN A 172.18.96.1 -ntp IN A 172.18.96.1 -time IN A 172.18.96.1 -presence IN A 172.18.96.1 -xs IN A 172.18.96.1 -library IN A 172.18.96.1 -box IN A 172.18.96.1 - - -conference.schoolserver IN A 172.18.96.1 - - -; translations of school - in plain latin script -; or un punycode of the utf-8 representation - -; es - escuela -escuela IN CNAME school - -; de - schule -schule IN CNAME school - diff --git a/roles/network/templates/netwarn/iiab-netwarn b/roles/network/templates/netwarn/iiab-netwarn new file mode 100755 index 000000000..87865e0f1 --- /dev/null +++ b/roles/network/templates/netwarn/iiab-netwarn @@ -0,0 +1,41 @@ +#!/bin/bash + +# CONFUSING BUT FYI: Steps below run *strictly sequentially* when this script +# (/usr/local/sbin/iiab-netwarn) is run on boot, triggered by either autostart: +# https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html +# ...or by Wayland compositor's ~/.config/labwc/autostart in new RasPiOS 12+: +# https://forums.raspberrypi.com/viewtopic.php?t=379321 +# (Prior to Dec 2024, RasPiOS compositor Wayfire did the same...) +# https://github.com/iiab/iiab/pull/3685 +# https://github.com/WayfireWM/wayfire/wiki/Configuration#autostart +# +# This allows return codes ($rc) to be meaningful, at each successive step. +# (As of July 2022, this is tested to work well with Ubuntu Mate and "Raspberry +# Pi OS with desktop" on Raspberry Pi 4!) +# +# IN CONTRAST: return codes below are NOT MEANINGFUL when this script is +# invoked manually after boot from a regular graphical desktop session -- so +# make sure to test (either kind of) "autostart" during actual OS boot-up! + +if [ -f /etc/iiab/install-flags/iiab-network-complete ]; then + exit +fi + +zenity --question --width=360 --text="IIAB needs to configure networking:\n\nβ–Ί Internet must be live before you begin.\nβ–ΊYou might be prompted for your password.\n\nContinue? (This can take 2-3 minutes)" +rc=$? +if [[ $rc != "0" ]]; then + exit $rc +fi + +# mate-terminal always returns 255 w/ autostart, so intercept/record return code +x-terminal-emulator -e "bash -c '/usr/local/bin/iiab-network; echo \"\$?\" > /tmp/iiab-network.rc'" +rc=$(cat /tmp/iiab-network.rc) +if [[ $rc != "0" ]]; then + zenity --warning --width=360 --text="iiab-network exited with error: $rc\n\nPlease review /opt/iiab/iiab/iiab-network.log" + exit $rc +fi + +zenity --question --width=360 --text="iiab-network complete.\n\nWould you like to REBOOT now? (Recommended)" +if [[ $? == "0" ]]; then + x-terminal-emulator -e "sudo reboot" +fi diff --git a/roles/network/templates/netwarn/netwarn-iiab-network.desktop b/roles/network/templates/netwarn/netwarn-iiab-network.desktop new file mode 100644 index 000000000..f109f88b0 --- /dev/null +++ b/roles/network/templates/netwarn/netwarn-iiab-network.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name[en_US]=iiab-network +Comment[en_US]=iiab-network +Name[en_CA]=iiab-network +Comment[en_CA]=iiab-network +Type=Application +Exec=/usr/local/sbin/iiab-netwarn +Hidden=false +Name=iiab-network +Comment=iiab-network diff --git a/roles/network/templates/network/bridge-br0 b/roles/network/templates/network/bridge-br0 index 8aaa27968..59d85db73 100644 --- a/roles/network/templates/network/bridge-br0 +++ b/roles/network/templates/network/bridge-br0 @@ -6,7 +6,11 @@ interface-name=br0 permissions= [ipv4] +{% if network_172 %} address1={{ lan_ip }}/19 +{% else %} +address1={{ lan_ip }}/24 +{% endif %} dns-search={{ iiab_domain }} method=manual diff --git a/roles/network/templates/network/dhcpcd.conf.j2 b/roles/network/templates/network/dhcpcd.conf.j2 index b44eb297d..cebff6e51 100644 --- a/roles/network/templates/network/dhcpcd.conf.j2 +++ b/roles/network/templates/network/dhcpcd.conf.j2 @@ -58,7 +58,11 @@ denyinterfaces {{ iiab_wired_lan_iface }} {% if dhcpcd_result == "enabled" and iiab_lan_iface != "none" %} interface {{ iiab_lan_iface }} +{% if network_172 %} static ip_address={{ lan_ip }}/19 +{% else %} +static ip_address={{ lan_ip }}/24 +{% endif %} static domain_name_servers=127.0.0.1 {% endif %} diff --git a/roles/network/templates/network/dnsmasq.conf.j2 b/roles/network/templates/network/dnsmasq.conf.j2 index 782f38049..152369cad 100644 --- a/roles/network/templates/network/dnsmasq.conf.j2 +++ b/roles/network/templates/network/dnsmasq.conf.j2 @@ -18,7 +18,12 @@ addn-hosts=/etc/hosts.dnsmasq expand-hosts # Specify the range of IP addresses the DHCP server will lease out to devices, and the duration of the lease +{% if network_172 %} dhcp-range=172.18.100.1,172.18.126.254,1h +{% else %} +dhcp-range=10.10.10.11,10.10.10.254,1h +{% endif %} + # Specify the default route dhcp-option=3,{{ lan_ip }} # Specify the DNS server address diff --git a/roles/network/templates/network/dnsmasq.sh.j2 b/roles/network/templates/network/dnsmasq.sh.j2 index 00df42bf3..6a7f7179a 100755 --- a/roles/network/templates/network/dnsmasq.sh.j2 +++ b/roles/network/templates/network/dnsmasq.sh.j2 @@ -1,7 +1,6 @@ #!/bin/bash if [ "$IFACE" == "{{ iiab_lan_iface }}" ]; then - echo "Restarting dnsmasq in 5 seconds" - /bin/sleep 5 && /bin/systemctl --no-block restart dnsmasq.service - echo "Restarted dnsmasq" + /bin/systemctl --no-block start dnsmasq.service + echo "Started dnsmasq" fi diff --git a/roles/network/templates/network/ifcfg-WAN.j2 b/roles/network/templates/network/ifcfg-WAN.j2.unused similarity index 100% rename from roles/network/templates/network/ifcfg-WAN.j2 rename to roles/network/templates/network/ifcfg-WAN.j2.unused diff --git a/roles/network/templates/network/ifcfg-slave.j2 b/roles/network/templates/network/ifcfg-slave.j2.unused similarity index 100% rename from roles/network/templates/network/ifcfg-slave.j2 rename to roles/network/templates/network/ifcfg-slave.j2.unused diff --git a/roles/network/templates/network/ifcfg.j2 b/roles/network/templates/network/ifcfg.j2.unused similarity index 100% rename from roles/network/templates/network/ifcfg.j2 rename to roles/network/templates/network/ifcfg.j2.unused diff --git a/roles/network/templates/network/netplan.j2 b/roles/network/templates/network/netplan.j2.unused similarity index 100% rename from roles/network/templates/network/netplan.j2 rename to roles/network/templates/network/netplan.j2.unused diff --git a/roles/network/templates/network/sysconfig.network.j2 b/roles/network/templates/network/sysconfig.network.j2.unused similarity index 100% rename from roles/network/templates/network/sysconfig.network.j2 rename to roles/network/templates/network/sysconfig.network.j2.unused diff --git a/roles/network/templates/network/systemd-br0-network.j2 b/roles/network/templates/network/systemd-br0-network.j2 index 619196b8b..07c5a1246 100644 --- a/roles/network/templates/network/systemd-br0-network.j2 +++ b/roles/network/templates/network/systemd-br0-network.j2 @@ -3,7 +3,11 @@ Name=br0 [Network] +{% if network_172 %} Address={{ lan_ip }}/19 +{% else %} +Address={{ lan_ip }}/24 +{% endif %} LinkLocalAddressing=no ConfigureWithoutCarrier=yes RequiredForOnline=degraded-carrier diff --git a/roles/network/templates/network/systemd-br0-slave.j2 b/roles/network/templates/network/systemd-br0-slave.j2 index 15fb5b16e..9c8555286 100644 --- a/roles/network/templates/network/systemd-br0-slave.j2 +++ b/roles/network/templates/network/systemd-br0-slave.j2 @@ -1,6 +1,6 @@ -# /etc/systemd/network/IIAB-Slave-{{ iiab_wired_lan_iface }}.network +# /etc/systemd/network/IIAB-Slave-{{ item|trim }}.network [Match] -Name={{ iiab_wired_lan_iface }} +Name={{ item|trim }} [Link] RequiredForOnline=no diff --git a/roles/network/templates/squid/squid.conf.j2 b/roles/network/templates/squid/squid.conf.j2 index 666a6a677..05a2e8f84 100644 --- a/roles/network/templates/squid/squid.conf.j2 +++ b/roles/network/templates/squid/squid.conf.j2 @@ -1,3 +1,5 @@ +# This is /etc/squid/squid.conf <- roles/network/templates/squid/squid.conf.j2 + # 2021-08-16 IIAB PR #2948 - April 2007 OLPC School Server legacy moved to: # https://github.com/iiab/iiab/blob/master/roles/network/templates/squid/squid-iiab.conf.j2.unused diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index da5ab374f..c0eb0f9b3 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -1,6 +1,6 @@ # Nextcloud README -Students and teachers can store their documents, calendars, contacts and photos locally within [Nextcloud](https://nextcloud.com), which is much like having a (local) version of Dropbox or Google Drive on your very own [Internet-in-a-Box](http://internet-in-a-box.org). +Students and teachers can store their documents, calendars, contacts and photos locally within [Nextcloud](https://nextcloud.com), which is much like having a (local) version of Dropbox or Google Drive on your very own [Internet-in-a-Box](https://internet-in-a-box.org). This Ansible playbook was derived from an earlier ownCloud playbook thanks to [Josh Dennis](https://github.com/floydianslips) in 2016/2017. @@ -14,7 +14,7 @@ The Nextcloud suite is divided into three main categories: ## Install It -(1) Set these 2 variable in [/etc/iiab/local_vars.yml](http://FAQ.IIAB.IO#What_is_local_vars.yml_and_how_do_I_customize_it.3F) prior to installing Internet-in-a-Box: +(1) Set these 2 variable in [/etc/iiab/local_vars.yml](http://FAQ.IIAB.IO#What_is_local_vars.yml_and_how_do_I_customize_it%3F) prior to installing Internet-in-a-Box: nextcloud_install: True nextcloud_enabled: True @@ -25,7 +25,7 @@ The Nextcloud suite is divided into three main categories: To further refine Nextcloud access controls based on IPv4 addresses, you can edit `/etc/apache2/sites-available/nextcloud.conf` _after_ it's created by this template: [/opt/iiab/iiab/roles/nextcloud/templates/nextcloud.conf.j2](https://github.com/iiab/iiab/blob/master/roles/nextcloud/templates/nextcloud.conf.j2) -(3) Strongly consider also setting `nginx_high_php_limits: True` in your /etc/iiab/local_vars.yml, to allocate important RAM/resources to PHP. Of course, enabling this might cause excess use of RAM/disk or other resources if not calibrated to your hardware and network! So _after_ install is complete, verify and evaluate these 6 settings in /etc/php/[ACTUAL PHP VERSION]/fpm/php.ini: +(3) Be aware of `nginx_high_php_limits: True` in your /etc/iiab/local_vars.yml, which allocates important RAM/resources to PHP, and is effectively auto-enabled for Nextcloud ([PR #3624](https://github.com/iiab/iiab/pull/3624)). Verify that your Internet-in-a-Box server has enough RAM and disk! And _after_ Nextcloud is installed, verify and evaluate these 6 settings in `/etc/php/[ACTUAL PHP VERSION]/fpm/php.ini` to be sure: - upload_max_filesize - post_max_size @@ -34,26 +34,34 @@ To further refine Nextcloud access controls based on IPv4 addresses, you can edi - max_input_time - max_input_vars (Moodle 3.11+ requires 5000+ with PHP 8+) -Useful PHP recommendations for these settings (while largely tailored to WordPress, and aimed at very low-end hardware) can be found here: [/opt/iiab/iiab/roles/www_options/tasks/main.yml#L53-L133](../www_options/tasks/main.yml#L53-L133) +FYI IIAB will also update `/etc/php/[ACTUAL PHP VERSION]/cli/php.in` (as Moodle requires). -(4) If you're running Nextcloud 22+ in production, carefully check that Nextcloud's latest formal prereqs (required AND recommended) are included per your community's needs. In places like these: +Useful PHP recommendations for these settings (while largely tailored to WordPress, and aimed at very low-end hardware) can be found here: [/opt/iiab/iiab/roles/www_options/tasks/php-settings.yml#L55-L110](../www_options/tasks/php-settings.yml#L55-L110) -- https://docs.nextcloud.com/server/22/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation +(4) Verify system requirements and recommendations for the [latest version Nextcloud](https://github.com/nextcloud/server/wiki/Maintenance-and-Release-Schedule): + +- https://docs.nextcloud.com/server/latest/admin_manual/installation/system_requirements.html +- https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation +- https://docs.nextcloud.com/server/30/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation - https://github.com/iiab/iiab/blob/master/roles/nextcloud/tasks/install.yml ## Using It -Log in to Nextcloud at http://box/nextcloud, http://box.lan/nextcloud, http://172.18.96.1/nextcloud (or similar) using: +Log in to Nextcloud at http://box/nextcloud, http://box.lan/nextcloud, http://10.10.10.10/nextcloud (or similar) using: Username: Admin Password: changeme +## Known Issues + +Do not install the [Nextcloud News](https://apps.nextcloud.com/apps/news) app (an RSS/Atom Feed reader) if your OS is 32-bits: [#3069](https://github.com/iiab/iiab/issues/3069) + ## Future Directions Going forward, should Internet-in-a-Box consider integrating optimizations (or more!) from these below? -- https://ownyourbits.com/nextcloudpi/ -- https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/ +- ~https://ownyourbits.com/nextcloudpi/~ +- ~https://ownyourbits.com/2017/02/13/nextcloud-ready-raspberry-pi-image/~ - https://github.com/nextcloud/nextcloudpi -Please [contact us](http://internet-in-a-box.org/pages/contributing.html) if you can help! +Please [contact us](https://internet-in-a-box.org/contributing.html) if you can help! diff --git a/roles/nextcloud/defaults/main.yml b/roles/nextcloud/defaults/main.yml index 9fb31c593..1a0b1741d 100644 --- a/roles/nextcloud/defaults/main.yml +++ b/roles/nextcloud/defaults/main.yml @@ -14,7 +14,7 @@ # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # The following line can avoid that: (but might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 nextcloud_dl_url: https://download.nextcloud.com/server/releases/latest.tar.bz2 nextcloud_url: /nextcloud diff --git a/roles/nextcloud/tasks/install.yml b/roles/nextcloud/tasks/install.yml index 541029206..37429ea0e 100644 --- a/roles/nextcloud/tasks/install.yml +++ b/roles/nextcloud/tasks/install.yml @@ -1,9 +1,29 @@ +- name: "Set 'mysql_install: True' and 'mysql_enabled: True'" + set_fact: + mysql_install: True + mysql_enabled: True + +- name: MYSQL - run 'mysql' role (attempt to install & enable MySQL / MariaDB) + include_role: + name: mysql + +- name: FAIL (STOP THE INSTALL) IF 'mysql_installed is undefined' + fail: + msg: "Nextcloud install cannot proceed, as MySQL / MariaDB is not installed." + when: mysql_installed is undefined + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # CHECK FOR PHP VERSION AUTOMATICALLY, TO DETERMINE WHICH NEXTCLOUD TO INSTALL. # INSPIRED BY: github.com/iiab/iiab/blob/master/roles/nodejs/tasks/main.yml # - name: Try to run 'php -v' to get PHP version # # e.g. converts multi-line "PHP 7.0.33-0ubuntu0.16.04.5 (cli) ( NTS ) ..." to "7.0.33" -# shell: php -v | head -1 | sed 's/^[^0-9.]*//' | sed 's/[^0-9.].*//' +# shell: php -v | head -1 | sed 's/^[^0-9.]*//; s/[^0-9.].*//' # register: php_version_installed # #ignore_errors: yes # NOT NEC: if php is not installed, php_version_installed.stdout will get set to "" @@ -41,9 +61,18 @@ # February 2020: See @m-anish's PR #2119 and follow-up PR #2258. -# 2021-07-06: If you're running Nextcloud 22+ in production, carefully check the latest required AND recommended prereqs: +# December 2023: Check latest required AND recommended prereqs below! +# e.g. Nextcloud 26 works with PHP 8.2; Nextcloud 27 deprecates PHP 8.0; Nextcloud 28 works with PHP 8.3 +# https://docs.nextcloud.com/server/latest/admin_manual/installation/system_requirements.html # https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation -# https://docs.nextcloud.com/server/21/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation +# https://docs.nextcloud.com/server/latest/admin_manual/installation/php_configuration.html +# https://docs.nextcloud.com/server/28/admin_manual/installation/ + +# 2023-12-15: Lifesaver manual upgrade instructions below! As Nextcloud OFTEN +# gets badly stuck (PHP timeouts, leading to FALSE instructions erroneously +# asking you to wait) if its web-based upgrade process is attempted :/ +# https://docs.nextcloud.com/server/latest/admin_manual/maintenance/manual_upgrade.html + - name: Install ffmpeg + libxml2 + 11 PHP packages (run 'php -m' or 'php -i' to verify) package: name: @@ -61,11 +90,11 @@ - php{{ php_version }}-gmp # OPTIONAL (for SFTP storage) - php-imagick # OPTIONAL (for preview generation). BUT drags in Apache's libapache2-mod-phpX.Y etc, as confirmed by 'apt depends php-imagick' -- while php{{ php_version }}-imagick installs (despite not being shown within 'apt list "php*imagick"') it's no better -- and 'apt depends phpX.Y-imagick' mysteriously does NOT show its deps. Likewise installed in wordpress/tasks/install.yml - php{{ php_version }}-intl # OPTIONAL (increases language translation performance and fixes sorting of non-ASCII characters): Likewise installed in mediawiki/tasks/install.yml, moodle/tasks/install.yml, wordpress/tasks/install.yml - #- php{{ php_version }}-json # See stanza just below + #- php{{ php_version }}-json # Included with PHP >= 8.0 -- see stanza just below #- php{{ php_version }}-libxml # NOT INSTALLABLE: ENABLED BY DEFAULT (https://www.php.net/manual/en/libxml.installation.php) - php{{ php_version }}-mbstring # Likewise installed in mediawiki/tasks/install.yml, moodle/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml, wordpress/tasks/install.yml - php{{ php_version }}-mysql # Likewise installed in mysql/tasks/install.yml, pbx/tasks/freepbx_dependencies.yml, wordpress/tasks/install.yml - #- php{{ php_version }}-openssl # NOT INSTALLABLE: ENABLED BY DEFAULT? + #- php{{ php_version }}-openssl # Included with PHP >= 8.0 -- NOT INSTALLABLE #- php{{ php_version }}-pdo_mysql # NOT INSTALLABLE: php{{ php_version }}-mysql handles this on all OS's? #- php{{ php_version }}-redis # @m-anish future work? #- php{{ php_version }}-session # NOT INSTALLABLE: ENABLED BY DEFAULT? @@ -85,13 +114,24 @@ # state: present # when: php_version is version('8.0', '<') +- name: "Run roles/www_options/tasks/php-settings.yml with 'nginx_high_php_limits: True' by default" + include_tasks: roles/www_options/tasks/php-settings.yml + when: php_settings_done is undefined + - name: Create dir {{ nextcloud_root_dir }} (by default 755 dirs & 644 files) file: state: directory path: "{{ nextcloud_root_dir }}" # /library/www/nextcloud -- name: Unarchive {{ nextcloud_dl_url }} (~139 MB) to {{ nextcloud_root_dir }} (~474 MB initially, 496+ MB later, {{ apache_user }}:{{ apache_user }}) +# Nextcloud 25 EOL was 2023-10-01: https://endoflife.date/nextcloud +# https://github.com/nextcloud/server/wiki/Maintenance-and-Release-Schedule#eol-versions +#- name: "2023-03-24: NEXTCLOUD 26 REQUIRES PHP 8 -- SO THIS TEMPORARY PATCH INSTALLS THE OLDER NEXTCLOUD 25 ON OS's WITH PHP 7.x -- WHOSE END-OF-LIFE WAS NOVEMBER 2022" +# set_fact: +# nextcloud_dl_url: https://download.nextcloud.com/server/releases/latest-25.tar.bz2 +# when: php_version is version('8.0', '<') + +- name: Unarchive {{ nextcloud_dl_url }} (~216 MB) to {{ nextcloud_root_dir }} (~844 MB initially, sometimes ~878 MB later, {{ apache_user }}:{{ apache_user }}) unarchive: remote_src: yes # Overwrite even if "already exists on the target" src: "{{ nextcloud_dl_url }}" @@ -107,6 +147,17 @@ # RECORD Nextcloud AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'nextcloud_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nextcloud + option: nextcloud_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'nextcloud_installed: True'" set_fact: nextcloud_installed: True diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml index 83877e92e..1308da347 100644 --- a/roles/nextcloud/tasks/main.yml +++ b/roles/nextcloud/tasks/main.yml @@ -19,38 +19,44 @@ quiet: yes -- name: Install Nextcloud if 'nextcloud_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: nextcloud_installed is undefined +- block: + - name: Install Nextcloud if 'nextcloud_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: nextcloud_installed is undefined -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml - when: nginx_enabled + - name: Enable/Disable/Restart NGINX + include_tasks: nginx.yml + - name: Add 'nextcloud' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nextcloud + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Nextcloud + - option: description + value: '"Nextcloud is a local server-based facility for sharing files, photos, contacts, calendars, etc."' + - option: nextcloud_install + value: "{{ nextcloud_install }}" + - option: nextcloud_enabled + value: "{{ nextcloud_enabled }}" + - option: nextcloud_dl_url + value: "{{ nextcloud_dl_url }}" + - option: nextcloud_url + value: "{{ nextcloud_url }}" + - option: nextcloud_base_dir + value: "{{ nextcloud_base_dir }}" + - option: nextcloud_root_dir + value: "{{ nextcloud_root_dir }}" + - option: nextcloud_data_dir + value: "{{ nextcloud_data_dir }}" -- name: Add 'nextcloud' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: Nextcloud - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Nextcloud - - option: description - value: '"Nextcloud is a local server-based facility for sharing files, photos, contacts, calendars, etc."' - - option: nextcloud_install - value: "{{ nextcloud_install }}" - - option: nextcloud_enabled - value: "{{ nextcloud_enabled }}" - - option: nextcloud_dl_url - value: "{{ nextcloud_dl_url }}" - - option: nextcloud_url - value: "{{ nextcloud_url }}" - - option: nextcloud_base_dir - value: "{{ nextcloud_base_dir }}" - - option: nextcloud_root_dir - value: "{{ nextcloud_root_dir }}" - - option: nextcloud_data_dir - value: "{{ nextcloud_data_dir }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/nextcloud/templates/nextcloud-nginx.conf.j2 b/roles/nextcloud/templates/nextcloud-nginx.conf.j2 index a1d1a53b3..9b7e8ee5f 100644 --- a/roles/nextcloud/templates/nextcloud-nginx.conf.j2 +++ b/roles/nextcloud/templates/nextcloud-nginx.conf.j2 @@ -59,7 +59,7 @@ location ^~ {{ nextcloud_url }} { } # set max upload size - client_max_body_size 512M; + client_max_body_size 10000M; fastcgi_buffers 64 4K; # Enable gzip but do not remove ETag headers @@ -85,7 +85,7 @@ location ^~ {{ nextcloud_url }} { deny all; } - location ~ ^\/nextcloud\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) { + location ~ ^\/nextcloud\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+)\.php(?:$|\/) { fastcgi_split_path_info ^(.+?\.php)(\/.*|)$; set $path_info $fastcgi_path_info; try_files $fastcgi_script_name =404; @@ -102,7 +102,7 @@ location ^~ {{ nextcloud_url }} { fastcgi_request_buffering off; } - location ~ ^\/nextcloud\/(?:updater|oc[ms]-provider)(?:$|\/) { + location ~ ^\/nextcloud\/(?:updater|ocs-provider)(?:$|\/) { try_files $uri/ =404; index index.php; } diff --git a/roles/nginx/README.md b/roles/nginx/README.md index e677c7ba2..2c5f65590 100644 --- a/roles/nginx/README.md +++ b/roles/nginx/README.md @@ -35,7 +35,7 @@ * usb_lib * wordpress - 2. These support "Native" NGINX ***AND*** Apache, a.k.a. "dual support" for legacy testing (if suitable "Shims" from *Section iii.* below are preserved!) Both "Native" NGINX and "Shim" proxying from NGINX to Apache port 8090 *cannot be enabled simultaneously* for these IIAB Apps/Service: + 2. These support "Native" NGINX ***AND*** Apache, a.k.a. "dual support" for legacy testing (if suitable "Shims" from *Section iii.* below are preserved!) Both "Native" NGINX and "Shim" proxying from NGINX to Apache port 8090 *cannot be enabled simultaneously* for these IIAB Apps/Service: * **NONE: Apache support is now fully REMOVED as of 2021-08-08** ([PR #2850](https://github.com/iiab/iiab/pull/2850)) @@ -52,11 +52,11 @@ * kalite (menu goes directly to ports 8006-8008) * minetest * mosquitto - * openvpn * pbx [FreePBX is usable with _both_ NGINX and Apache as of 2021-08-18, thanks to PR [#2954](https://github.com/iiab/iiab/pull/2954)] * phpmyadmin [*, requires Apache for now, as in Section iii.] * samba [*, [PR #2923](https://github.com/iiab/iiab/pull/2923)] * sshd + * tailscale * transmission * vnstat diff --git a/roles/nginx/tasks/install.yml b/roles/nginx/tasks/install.yml index d9f3c4dda..b45920dd1 100644 --- a/roles/nginx/tasks/install.yml +++ b/roles/nginx/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Stop & Disable '{{ apache_service }}' systemd service, in case it exists systemd: name: "{{ apache_service }}" # apache2 or httpd, per /opt/iiab/iiab/vars/.yml @@ -66,6 +71,17 @@ # RECORD NGINX AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'nginx_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nginx + option: nginx_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'nginx_installed: True'" set_fact: nginx_installed: True diff --git a/roles/nginx/templates/iiab.conf.j2 b/roles/nginx/templates/iiab.conf.j2 index b66f69cfa..20773967f 100644 --- a/roles/nginx/templates/iiab.conf.j2 +++ b/roles/nginx/templates/iiab.conf.j2 @@ -5,10 +5,30 @@ location / { location /usb { alias /library/www/html/local_content/; fancyindex on; # autoindex on; + add_before_body /upload2usb/button.html; +} + +location ~ ^/upload2usb/(.*)\.php$ { + alias /library/www/html/upload2usb/$1.php; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + fastcgi_pass php; + fastcgi_index index.php; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + include fastcgi_params; } location /local_content/ { fancyindex on; # autoindex on; + add_before_body /upload2usb/button.html; +} + +location /info { + fancyindex on; # Directory listing for http://box/info/admin-console/ + fancyindex_exact_size off; # Output human-readable file sizes. } location /modules/ { diff --git a/roles/nginx/templates/server.conf.j2 b/roles/nginx/templates/server.conf.j2 index 4760bce64..9b6aeaaba 100644 --- a/roles/nginx/templates/server.conf.j2 +++ b/roles/nginx/templates/server.conf.j2 @@ -7,6 +7,15 @@ server { index index.php index.html index.htm; + # NGINX's 1MB default is far too low for Calibre-Web and LMS-like apps. + # So IIAB sets this to 10000M, roughly aligning with similar settings... + # 1. 'upload_max_filesize = 10000M' and 'post_max_size = 10000M' are SOMETIMES set in: + # https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml#L90-L91 + # https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml#L104-L105 + # 2. 'client_max_body_size 10000M;' is set in: + # https://github.com/iiab/iiab/blob/master/roles/nextcloud/templates/nextcloud-nginx.conf.j2#L62 + client_max_body_size 10000M; + # let individual services drop location blocks in conf.d include {{ nginx_conf_dir }}/*; diff --git a/roles/nodejs/README.md b/roles/nodejs/README.md new file mode 100644 index 000000000..7e2716bc9 --- /dev/null +++ b/roles/nodejs/README.md @@ -0,0 +1,48 @@ +Please see IIAB's recommended Node.js version number [around line 439 of /opt/iiab/iiab/vars/default_vars.yml](https://github.com/iiab/iiab/blob/master/vars/default_vars.yml#L434-L439) + +If Nodesource.com doesn't yet support your OS +--------------------------------------------- + +Nodesource.com often supports Debian long before each Debian release, whereas for other OS's, Nodesource.com support usually arrives a few days or weeks after the OS release. + +For late-breaking details on Nodesource.com support for your particular Linux OS, keep an eye on: + +- https://github.com/nodesource/distributions#deb +- https://deb.nodesource.com/node_20.x/dists/ + - https://deb.nodesource.com/node_20.x/pool/main/n/nodejs/ + - https://nodejs.org/dist/latest-v20.x/ +- https://deb.nodesource.com/node_19.x/dists/ + - https://deb.nodesource.com/node_19.x/pool/main/n/nodejs/ + - https://nodejs.org/dist/latest-v19.x/ +- _ETC!_ + +If Nodesource.com does not yet support your Linux OS and IIAB's asked to install Node.js — IIAB will then [fall back](https://github.com/iiab/iiab/blob/91a5cd33f34d5d2a55e75bf0cdc85bcd9d7b4821/roles/nodejs/tasks/install.yml#L103-L107) to: (running the equivalent of) + +``` +sudo apt install nodejs npm +sudo echo 'nodejs_installed: True' >> /etc/iiab/iiab_state.yml +``` + +(The above installs your OS's own versions of Node.js and npm.) + +Separately, if you later want to try **wiping** nodejs and npm (AT YOUR OWN RISK!) to attempt the Nodesource approach instead, run: + +``` +cd /opt/iiab/iiab +sudo ./runrole --reinstall nodejs +``` + +Raspberry Pi Zero W Warning +--------------------------- + +UPDATE: The Zero 2 W released 2021-10-28 is 64-bit (ARMv7) so may not have such serious problems... + +On the original Raspberry Pi Zero W (ARMv6) however: Node.js applications like Internet Archive, JupyterHub, Node-RED, PBX (Asterisk/FreePBX) and Sugarizer won't work β€” if you installed Node.js while on Raspberry Pi 3, 3 B+ (ARMv7) or Raspberry Pi 4 (ARMv8). + +If necessary, run `sudo apt purge nodejs npm` then `sudo rm /etc/apt/sources.list.d/nodesource.list` then `sudo apt update` and then attempt to [install Node.js](https://github.com/iiab/iiab/blob/master/roles/nodejs/tasks/install.yml) _on the Raspberry Pi Zero W itself_ (`cd /opt/iiab/iiab` then `sudo ./runrole --reinstall nodejs`). + +Earlier, some preferred installing the tar file version mentioned at [#2082](https://github.com/iiab/iiab/issues/2082#issuecomment-569344617) — if that is your preference, consider a more recent version like: https://nodejs.org/dist/latest-v20.x/ + +Either way, you'll (likely) then also need to run: `sudo apt install npm` + +Whatever versions of Node.js and npm you install, make sure `/etc/iiab/iiab_state.yml` contains the line `nodejs_installed: True` (add it if necessary!) Finally, proceed to install Internet Archive, JupyterHub, Node-RED ([Raspberry Pi notes](https://nodered.org/docs/hardware/raspberrypi#swapping-sd-cards)), PBX (Asterisk/FreePBX) and/or Sugarizer: [#1799](https://github.com/iiab/iiab/issues/1799) diff --git a/roles/nodejs/defaults/main.yml b/roles/nodejs/defaults/main.yml index 6bda8c2d4..69785399a 100644 --- a/roles/nodejs/defaults/main.yml +++ b/roles/nodejs/defaults/main.yml @@ -5,7 +5,7 @@ # nodejs_install: False # nodejs_enabled: False -# nodejs_version: 16.x # was 8.x til 2019-02-02, 10.x til 2019-12-21, 12.x til 2020-10-29, 14.x til 2021-06-17 +# nodejs_version: 18.x # was 8.x til 2019-02-02, 10.x til 2019-12-21, 12.x til 2020-10-29, 14.x til 2021-06-17, 16.x til 2022-04-20 # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! diff --git a/roles/nodejs/tasks/install.yml b/roles/nodejs/tasks/install.yml index f2843bc47..96e1ec9df 100644 --- a/roles/nodejs/tasks/install.yml +++ b/roles/nodejs/tasks/install.yml @@ -1,4 +1,13 @@ -# 1. TEST IF Node.js ALEADY INSTALLED & WARN AS NEC +# Lokole PDF (User's Guide) gets copied for offline use (http://box/info) here: +# https://github.com/iiab/iiab/blob/master/roles/www_base/templates/iiab-refresh-wiki-docs.sh#L51-L52 + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +# 1. TEST IF Node.js ALEADY INSTALLED & IF SO WARN IT'LL BE REPLACED # 2019-02-03: BELOW TESTS IF 'nodejs' VERSION IS ALREADY INSTALLED: # IF SO & THIS DOESN'T MATCH nodejs_version AS SET IN defaults_vars.yml @@ -10,19 +19,21 @@ - name: Try to run 'node -v' to get Node.js version # 'node -v' doesn't work with older versions e.g. Ubuntu 16.04's Node.js 4.2.6 # 'nodejs -v' doesn't work with newer versions e.g. Node.js 16.x - # Both below convert v10.15.1 to 10.x, but this is safer: (removes non-digits) - shell: node -v | sed 's/[^0-9]*//' | sed 's/[^0-9].*/.x/' + # Each below convert v10.15.1 to 10.x, but this is safest: + shell: node -v | sed 's/^[^0-9]*\([0-9][0-9]*\).*$/\1.x/' + # Capturing Groups & Backreferences -> GNU BRE: (Basic Regular Expression) + # https://www.regular-expressions.info/refcapture.html + # https://www.regular-expressions.info/gnu.html#bre + #shell: node -v | sed 's/[^0-9]*//; s/[^0-9].*/.x/' + #shell: node -v | sed 's/[^[:digit:]]*//; s/[^[:digit:]].*/.x/' #shell: node -v | sed 's/^[vV]//' | sed 's/\..*/.x/' register: nodejs_version_installed -#- debug: -# var: nodejs_version_installed - # When nodejs is NOT installed: -# nodejs_version_installed.rc == 0 # Crazy with stderr below, "due to pipes" +# nodejs_version_installed.rc == 0 # COUNTERINTUITIVE BUT 'echo $?' CONFIRMS (pipe zeros out error) -- thankfully STDERR msg from left side of pipe preserved below. # nodejs_version_installed.stdout == "" # nodejs_version_installed.stderr == "/bin/sh: 1: nodejs: not found" -# BOTH ABOVE (incl non-null stderr) are USED BELOW to confirm install is nec! +# BOTH ABOVE (incl non-null stderr) [were] USED BELOW to confirm install is nec! #- name: "ENFORCE PRECONDITION: Stop installing (intentionally fail) IF an installed 'nodejs' version isn't {{ nodejs_version }}" # fail: @@ -39,24 +50,27 @@ # file: # state: absent # path: /etc/apt/sources.list.d/nodesource.list +# when: nodejs_version_installed is defined and nodejs_version_installed.stdout != nodejs_version # when: nodejs_version_installed is defined and nodejs_version_installed.stdout != nodejs_version and nodejs_version_installed.stdout != "" -# BRUTAL but ensures consistency across OS's / distros like Raspbian Desktop & Ubermix that often include an older version of Node.js -# Forces < 16.x or > 16.x to be uninstalled -- name: ASK apt/yum/dnf TO REMOVE PRE-EXISTING Node.js "{{ nodejs_version_installed.stdout }}" (IF IT'S NOT {{ nodejs_version }}) +- name: LOUD WARNING if Node.js will be replaced -- BRUTAL but helps OS's / distros with older Node.js + #debug: # GREEN + fail: # FORCE IT RED THIS ONCE! + msg: "WARNING: YOUR Node.js {{ nodejs_version_installed.stdout }} WILL BE WIPED AND REPLACED" + when: nodejs_version_installed.stderr == "" # and nodejs_version_installed.stdout == nodejs_version + ignore_errors: yes + +# 2022-10-22: Above 2 stanzas could be removed (tho informational value remains) + +- name: ASK apt TO REMOVE ANY PRE-EXISTING Node.js AND npm package: - name: nodejs + name: + - nodejs + - npm state: absent - when: nodejs_version_installed is defined and nodejs_version_installed.stdout != nodejs_version - #when: nodejs_version_installed is defined and nodejs_version_installed.stdout != nodejs_version and nodejs_version_installed.stdout != "" - -- name: Warn if Node.js {{ nodejs_version}} already installed & might be updated - debug: - msg: "WARN: YOUR Node.js {{ nodejs_version }} MIGHT NOW BE UPDATED USING nodesource.com" - when: nodejs_version_installed is defined and nodejs_version_installed.stdout == nodejs_version -# 2. INSTALL Node.js USING nodesource.com +# 2. INSTALL Node.js AND npm USING nodesource.com (OR OS's apt IF THAT FAILS!) # 2019-02-12: Should not be nec, as stanza below it should overwrite # /etc/apt/sources.list.d/nodesource.list regardless! @@ -67,30 +81,59 @@ # state: absent # when: internet_available and is_debuntu -- name: Run 'curl -sL https://deb.nodesource.com/setup_{{ nodejs_version }} | bash -' to overwrite /etc/apt/sources.list.d/nodesource.list - shell: curl -sL https://deb.nodesource.com/setup_{{ nodejs_version }} | bash - - #args: - # warn: no - # creates: /etc/apt/sources.list.d/nodesource.list - #when: internet_available # 2021-08-04: Better to fail & notify implementer! - #when: internet_available and (is_debian_8 or is_debian_9 or is_ubuntu_16 or is_ubuntu_17) - # NOT NEC TO TEST FOR is_raspbian_8 OR is_raspbian_9 AS /opt/iiab/iiab/vars/.yml - # DEFINES THESE AS SUBSETS OF is_debian_8 OR is_debian_9 (FOR NOW!) +# MANUAL NODESOURCE INSTALL *WORKS* EVEN PRIOR TO OFFICIAL DISTRO SUPPORT AT: +# https://github.com/nodesource/distributions#deb +# https://deb.nodesource.com/node_18.x/dists/ +# +# 1) e.g. Ubuntu 22.04: +# wget https://deb.nodesource.com/node_18.x/pool/main/n/nodejs/nodejs_18.0.0-deb-1nodesource1_amd64.deb +# apt install ./nodejs_18.0.0-deb-1nodesource1_amd64.deb # SMARTER + CLEANER THAN: dpkg -i nodejs_18... +# echo 'nodejs_installed: True' >> /etc/iiab/iiab_state.yml +# +# 2) e.g. Ubuntu 22.10: +# wget https://deb.nodesource.com/node_18.x/pool/main/n/nodejs/nodejs_18.11.0-deb-1nodesource1_amd64.deb +# apt install ./nodejs_18.11.0-deb-1nodesource1_amd64.deb # SMARTER + CLEANER THAN: dpkg -i nodejs_18... +# echo 'nodejs_installed: True' >> /etc/iiab/iiab_state.yml -# 2019-03-29: Above works on Debian 10 Buster pre-releases, but fails on Ubuntu -# 19.04 Beta. Comment it out for now, and manually run: "apt install npm" then -# "npm install -g npm@latest" (all *SHOULD* be magically fixed by 2019-04-18 ?) +- name: Try NEW (since August 2023) approach setting up /etc/apt/keyrings/nodesource.gpg and /etc/apt/sources.list.d/nodesource.list -- per https://github.com/nodesource/distributions#installation-instructions + shell: | + mkdir -p /etc/apt/keyrings + rm -f /etc/apt/keyrings/nodesource.gpg + curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_{{ nodejs_version }} nodistro main" > /etc/apt/sources.list.d/nodesource.list + register: curl_nodesource + ignore_errors: yes -# Forces update -- name: Install latest Node.js {{ nodejs_version }} which includes /usr/bin/npm - package: +# 2023-09-06: OBSOLETE as nodesource.com no longer supports https://deb.nodesource.com/node_{{ nodejs_version }}/dists/ +# - name: Try 'curl -fsSL https://deb.nodesource.com/setup_{{ nodejs_version }} | bash -' to overwrite /etc/apt/sources.list.d/nodesource.list +# shell: curl -fsSL https://deb.nodesource.com/setup_{{ nodejs_version }} | bash - +# register: curl_nodesource +# ignore_errors: yes +# #args: +# # warn: no +# # creates: /etc/apt/sources.list.d/nodesource.list + +- name: Remove /etc/apt/sources.list.d/nodesource.list if above failed + file: + path: /etc/apt/sources.list.d/nodesource.list + state: absent + when: curl_nodesource.failed + +- name: Install Node.js -- also includes /usr/bin/npm if nodesource.list installed above + apt: #name: nodejs={{ nodejs_version }} name: nodejs - state: latest - #state: present - #when: internet_available # 2021-08-04: Better to fail & notify implementer! - #when: internet_available and (is_debian_8 or is_debian_9 or is_ubuntu_16 or is_ubuntu_17) + state: latest # Equivalent to 'state: present' ? + update_cache: yes +# Also run 'npm install -g npm' later, if you truly want the LATEST! +- name: Also install latest npm (OS's) if nodesource failed to install above -- i.e. if OS not yet supported by https://github.com/nodesource/distributions + package: + name: npm + state: latest # Equivalent to 'state: present' ? + when: curl_nodesource.failed + +# NEED BLEEDING EDGE? Then Also Run: npm install -g npm@latest # 2018-07-14: BOTH STEPS ABOVE TAKE TIME, but Raspbian (apt offers npm # 1.4.21) & Debian 9 (apt offers no npm!) STILL NEED the above @@ -105,10 +148,10 @@ # which appears suffic "SO FAR"? 18.04's nodejs 8.10.0 is more reassuring! # # CRAZY IDEA: most versions of npm can upgrade themselves to the latest -# (6.2.0 for now) using command "npm install -g npm", if that helps us in -# future, e.g. TK's memory issue etc? If so, be CAREFUL this puts npm -# in /usr/local/bin on Ubuntu 18.04 -- unlike Ubuntu 16.04 and Raspbian -# where it upgrades /usr/bin/npm in place: +# (6.2.0 for now) using "npm install -g npm" or "npm install -g npm@latest", +# if that helps us in future, e.g. TK's memory issue etc? If so, be CAREFUL +# this puts npm in /usr/local/bin on Ubuntu 18.04 -- unlike Ubuntu 16.04 and +# Raspbian where it upgrades /usr/bin/npm in place: # https://askubuntu.com/questions/1036278/npm-is-incorrect-version-on-latest-ubuntu-18-04-installation # 2019-02-03: OLD WAY (PRIOR TO 2019) BELOW. Since then, @m-anish helped @@ -139,6 +182,17 @@ # 3. RECORD Node.js AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'nodejs_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nodejs + option: nodejs_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'nodejs_installed: True'" set_fact: nodejs_installed: True diff --git a/roles/nodejs/tasks/main.yml b/roles/nodejs/tasks/main.yml index e13c68934..07de2bcf8 100644 --- a/roles/nodejs/tasks/main.yml +++ b/roles/nodejs/tasks/main.yml @@ -35,23 +35,31 @@ var: nodejs_installed -- name: Install Node.js if 'nodejs_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: nodejs_installed is undefined +- block: + - name: Install Node.js if 'nodejs_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: nodejs_installed is undefined -- name: Add 'nodejs' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab_state.yml - section: nodejs - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Node.js - - option: description - value: '"Node.js is a JavaScript runtime environment built on Chrome''s V8 JavaScript engine, that executes JavaScript code outside of a browser."' - - option: nodejs_install - value: "{{ nodejs_install }}" - - option: nodejs_enabled - value: "{{ nodejs_enabled }}" + - name: Add 'nodejs' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nodejs + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Node.js + - option: description + value: '"Node.js is a JavaScript runtime environment built on Chrome''s V8 JavaScript engine, that executes JavaScript code outside of a browser."' + - option: nodejs_install + value: "{{ nodejs_install }}" + - option: nodejs_enabled + value: "{{ nodejs_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/nodered/README.rst b/roles/nodered/README.rst index 102e4a995..769905f7f 100644 --- a/roles/nodered/README.rst +++ b/roles/nodered/README.rst @@ -9,7 +9,7 @@ Node-RED is a flow-based development tool for visual programming developed origi Using It -------- -Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: +Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: nodered_install: True nodered_enabled: True @@ -20,7 +20,7 @@ Username: ``Admin`` Password: ``changeme`` -To change this password, please see: `roles/nodered/defaults/main.yml `_ +To change this password, please see: `roles/nodered/defaults/main.yml `_ You can monitor the Node-RED service with command:: diff --git a/roles/nodered/defaults/main.yml b/roles/nodered/defaults/main.yml index f68a595d3..a98463197 100644 --- a/roles/nodered/defaults/main.yml +++ b/roles/nodered/defaults/main.yml @@ -9,9 +9,10 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -nodered_user: Admin -nodered_password: changeme # REMOVE THIS PASSWORD REMINDER LINE AS NECESSARY -nodered_password_hash: $2b$08$oxgvoU9et3deSbXY8UNVTOWHSTQAyEASIal86RHVMqYQJhpPMNz7q +nodered_linux_user: nodered + +nodered_admin_user: Admin +nodered_admin_pwd_hash: $2b$08$oxgvoU9et3deSbXY8UNVTOWHSTQAyEASIal86RHVMqYQJhpPMNz7q # Password itself is "changeme" # TO GENERATE A NEW PASSWORD HASH, run 'node-red-admin hash-pw' and enter # the new password. Paste the resulting hash as above, but into your own: @@ -21,7 +22,7 @@ nodered_password_hash: $2b$08$oxgvoU9et3deSbXY8UNVTOWHSTQAyEASIal86RHVMqYQJhpPMN # username and password hash are stored in: # /home/nodered/.node-red/settings.js # -# Or...on Raspberry Pi they're stored in: +# Or...on Raspberry Pi they [USED TO BE] stored in: # /home/pi/.node-red/settings.js # # See http://nodered.org/docs/security.html for more detail. diff --git a/roles/nodered/tasks/apache.yml b/roles/nodered/tasks/apache.yml.unused similarity index 100% rename from roles/nodered/tasks/apache.yml rename to roles/nodered/tasks/apache.yml.unused diff --git a/roles/nodered/tasks/nginx.yml b/roles/nodered/tasks/enable-or-disable.yml similarity index 54% rename from roles/nodered/tasks/nginx.yml rename to roles/nodered/tasks/enable-or-disable.yml index e7affdab7..87a1c8d2a 100644 --- a/roles/nodered/tasks/nginx.yml +++ b/roles/nodered/tasks/enable-or-disable.yml @@ -1,3 +1,19 @@ +- name: Enable & (Re)start 'nodered' systemd service, if nodered_enabled + systemd: + name: nodered + daemon_reload: yes + enabled: yes + state: restarted + when: nodered_enabled + +- name: Disable & Stop 'nodered' systemd service, if not nodered_enabled + systemd: + name: nodered + enabled: no + state: stopped + when: not nodered_enabled + + - name: Enable http://box/nodered via NGINX, by installing {{ nginx_conf_dir }}/nodered-nginx.conf from template template: src: nodered-nginx.conf.j2 @@ -6,7 +22,7 @@ - name: Disable http://box/nodered via NGINX, by removing {{ nginx_conf_dir }}/nodered-nginx.conf file: - path: "{{ nginx_conf_dir }}/nodered-nginx.conf" # /etc/nginx/conf.d + path: "{{ nginx_conf_dir }}/nodered-nginx.conf" state: absent when: not nodered_enabled diff --git a/roles/nodered/tasks/group.yml b/roles/nodered/tasks/group.yml deleted file mode 100644 index ad4499023..000000000 --- a/roles/nodered/tasks/group.yml +++ /dev/null @@ -1,26 +0,0 @@ -- name: Ensure Linux group 'nodered' exists (if not rpi) - group: - name: nodered - state: present - -- name: Ensure Linux user 'nodered' exists and is added to group 'nodered' (if not rpi) - user: - name: nodered - group: nodered - -- name: Ensure directory /home/nodered/.node-red/ exists (if not rpi) - file: - path: /home/nodered/.node-red - state: directory - owner: nodered - group: nodered - mode: 0775 - -- name: Install /home/nodered/.node-red/settings.js from template, with authentication (if not rpi) - template: - backup: yes - src: settings.js.j2 - dest: /home/nodered/.node-red/settings.js - owner: nodered - group: nodered - mode: 0755 diff --git a/roles/nodered/tasks/install.yml b/roles/nodered/tasks/install.yml index 3c95f7408..b7c711ac5 100644 --- a/roles/nodered/tasks/install.yml +++ b/roles/nodered/tasks/install.yml @@ -16,13 +16,18 @@ msg: "Node-RED install cannot proceed, as Node.js is not installed." when: nodejs_installed is undefined -# 2020-10-29: not really be nec as Node-RED supports recent Node.js versions +# 2020-10-29: not really nec as Node-RED supports recent Node.js versions #- name: FAIL (STOP THE INSTALL) IF 'nodejs_version != "12.x"' # fail: # msg: "Node-RED install cannot proceed, as it currently requires Node.js 12.x, whereas nodejs_version is set to {{ nodejs_version }}. Please check the value of nodejs_version in /opt/iiab/iiab/vars/default_vars.yml, /etc/iiab/local_vars.yml, /opt/iiab/iiab/roles/nodejs, etc." # when: nodejs_version != "12.x" +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # BRUTAL but ensures consistency across OS's / distros like Raspbian Desktop & # Ubermix that often include an older version of Node-RED. Brutal, as this # removes customizations on graphical desktop OS's e.g. Raspbian Desktop's: @@ -36,7 +41,6 @@ package: name: nodered state: absent - when: nodered_install # 2019-02-13: the 6 RPi stanzas below recreate Raspbian Desktop's Node-RED # environment, inspired by: @@ -44,15 +48,22 @@ # https://github.com/node-red/raspbian-deb-package/blob/master/resources/update-nodejs-and-nodered # https://github.com/iiab/iiab/pull/1497 -- name: "Globally 'npm install' 3 Node-RED packages: node-red, node-red-admin, node-red-dashboard" - command: npm install -g --unsafe-perm node-red node-red-admin node-red-dashboard - #command: npm install -g --unsafe-perm node-red@latest node-red-admin@latest node-red-dashboard@latest - # Above "@latest" is recommended by https://nodered.org/docs/hardware/raspberrypi (SHOULD WE CONSIDER?) - when: nodered_install +# https://nodered.org/docs/user-guide/node-red-admin built in since Node-RED +# 1.1.0 (2020-06-30). Run it using: node-red admin +# If you install it separately, run: node-red-admin +# +#- name: "Globally 'npm install' 3 Node-RED packages: node-red, node-red-admin, node-red-dashboard" +- name: "Globally 'npm install' 2 Node-RED packages: node-red, node-red-dashboard" + #command: npm install -g --unsafe-perm node-red node-red-admin node-red-dashboard + command: npm install -g --unsafe-perm node-red@latest node-red-dashboard@latest + # Above "@latest" recommended by https://nodered.org/docs/hardware/raspberrypi back in 2019 -- name: "Globally 'npm install' 8 Node-RED learning examples for RPi: node-red-contrib-ibm-watson-iot, node-red-contrib-play-audio, node-red-node-ledborg, node-red-node-ping, node-red-node-pi-sense-hat, node-red-node-random, node-red-node-serialport, node-red-node-smooth" - command: npm install -g --unsafe-perm node-red-contrib-ibm-watson-iot node-red-contrib-play-audio node-red-node-ledborg node-red-node-ping node-red-node-pi-sense-hat node-red-node-random node-red-node-serialport node-red-node-smooth - when: nodered_install and is_raspbian +# 2022-06-08: New list copied from $EXTRANODES in https://github.com/node-red/linux-installers/blob/master/deb/update-nodejs-and-nodered +- name: "Globally 'npm install' 6 Node-RED learning examples IF Raspberry Pi hardware detected: node-red-node-pi-gpio, node-red-node-random, node-red-node-ping, node-red-contrib-play-audio, node-red-node-smooth, node-red-node-serialport" + #command: npm install -g --unsafe-perm node-red-contrib-ibm-watson-iot node-red-contrib-play-audio node-red-node-ledborg node-red-node-ping node-red-node-pi-sense-hat node-red-node-random node-red-node-serialport node-red-node-smooth + command: npm install -g --unsafe-perm node-red-node-pi-gpio@latest node-red-node-random@latest node-red-node-ping@latest node-red-contrib-play-audio@latest node-red-node-smooth@latest node-red-node-serialport@latest + #command: npm i --unsafe-perm --save --no-progress --no-update-notifier --no-audit --no-fund node-red-node-pi-gpio@latest node-red-node-random@latest node-red-node-ping@latest node-red-contrib-play-audio@latest node-red-node-smooth@latest node-red-node-serialport@latest 2>&1 + when: rpi_model != "none" ## To protect pre-installed packages within /usr/lib/node_modules in graphical ## desktop OS's like Raspbian Desktop & Ubermix, we now only install those that @@ -89,18 +100,39 @@ # creates: /usr/lib/node_modules/node-red-dashboard # when: nodered_install and internet_available -- include_tasks: group.yml - when: nodered_install and not is_raspbian +- include_tasks: settings.yml + #when: not is_raspbian -- include_tasks: rpi_desk.yml - when: nodered_install and is_raspbian +- include_tasks: os-integration.yml +#- include_tasks: rpi_desk.yml +# when: is_raspbian -- name: Install /etc/systemd/system/nodered.service systemd unit file from template - template: - backup: no - src: nodered.service.j2 +# 2022-06-08 OFFICIALLY RECOMMENDED /lib/systemd/system/nodered.service IS: +# https://github.com/node-red/linux-installers/blob/master/resources/nodered.service +# EXPLAINED AT https://nodered.org/docs/faq/customising-systemd-on-pi +# +# AS RECOMMENDED BY OFFICIAL INSTALLER SCRIPT: +# https://github.com/node-red/linux-installers/blob/master/deb/update-nodejs-and-nodered +# OFFICIAL INSTRUCTIONS: https://nodered.org/docs/getting-started/local +# https://nodered.org/docs/getting-started/raspberrypi +# +# Should /lib be considered instead of /etc ? +# - name: Install /etc/systemd/system/nodered.service systemd unit file from template +# template: +# src: nodered.service.j2 +# dest: /etc/systemd/system/nodered.service + +- name: Start by downloading https://github.com/node-red/linux-installers/blob/master/resources/nodered.service to /etc/systemd/system/nodered.service + get_url: + url: https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.service dest: /etc/systemd/system/nodered.service - # mode: '0666' + timeout: "{{ download_timeout }}" + +- name: Replace every '[=/]pi' with '[=/]{{ nodered_linux_user }}' (nodered_linux_user) in /etc/systemd/system/nodered.service + replace: + path: /etc/systemd/system/nodered.service + regexp: '([=/])pi' # e.g. nodered_linux_user: nodered + replace: '\1{{ nodered_linux_user }}' # \1 is a back-reference to above '=' or '/' -- like sed, but Ansible uses https://docs.python.org/3/library/re.html # SEE ALSO THE apache2_module SECTION IN roles/httpd/tasks/main.yml #- name: Enable proxy_wstunnel apache2 module @@ -111,6 +143,17 @@ # RECORD Node-RED AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'nodered_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nodered + option: nodered_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'nodered_installed: True'" set_fact: nodered_installed: True diff --git a/roles/nodered/tasks/main.yml b/roles/nodered/tasks/main.yml index 2add807b2..2c197013e 100644 --- a/roles/nodered/tasks/main.yml +++ b/roles/nodered/tasks/main.yml @@ -19,42 +19,33 @@ quiet: yes -- name: Install Node-RED if nodered_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: nodered_installed is undefined +- block: + - name: Install Node-RED if nodered_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: nodered_installed is undefined -- name: Enable & (Re)start 'nodered' systemd service, if nodered_enabled - systemd: - name: nodered - daemon_reload: yes - enabled: yes - state: restarted - when: nodered_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'nodered' systemd service, if not nodered_enabled - systemd: - name: nodered - enabled: no - state: stopped - when: not nodered_enabled + - name: Add 'nodered' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: nodered + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Node-RED + - option: description + value: '"Node-RED is a flow-based development tool for visual programming developed originally by IBM for wiring together hardware devices, APIs and online services as part of the Internet of Things. Node-RED provides a web browser-based flow editor, which can be used to create JavaScript functions."' + - option: nodered_install + value: "{{ nodered_install }}" + - option: nodered_enabled + value: "{{ nodered_enabled }}" -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + rescue: - -- name: Add 'nodered' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: nodered - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Node-RED - - option: description - value: '"Node-RED is a flow-based development tool for visual programming developed originally by IBM for wiring together hardware devices, APIs and online services as part of the Internet of Things. Node-RED provides a web browser-based flow editor, which can be used to create JavaScript functions."' - - option: nodered_install - value: "{{ nodered_install }}" - - option: nodered_enabled - value: "{{ nodered_enabled }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/nodered/tasks/os-integration.yml b/roles/nodered/tasks/os-integration.yml new file mode 100644 index 000000000..c7b008da3 --- /dev/null +++ b/roles/nodered/tasks/os-integration.yml @@ -0,0 +1,68 @@ +# 2022-06-08: This file used to be rpi_desk.yml + +# 2022-06-09: Crucially, the 3 "dest" dirs (below) exist on all mainline OS's +- name: "Download 3 Node-RED enhancements: Node-RED icon, start menu item, /etc/logrotate.d/nodered" + get_url: + url: "{{ item.url }}" + dest: "{{ item.dest }}" + force: yes + timeout: "{{ download_timeout }}" + with_items: + - url: https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-icon.svg + dest: /usr/share/icons/hicolor/scalable/apps/node-red-icon.svg + - url: https://raw.githubusercontent.com/node-red/linux-installers/master/resources/Node-RED.desktop + dest: /usr/share/applications/Node-RED.desktop + - url: https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.rotate + dest: /etc/logrotate.d/nodered + # 2022-06-08: New versions above, pasted from https://github.com/node-red/linux-installers/blob/master/deb/update-nodejs-and-nodered + # - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-icon.svg + # dest: /usr/share/icons/hicolor/scalable/apps/node-red-icon.svg + # - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Node-RED.desktop + # dest: /usr/share/applications/Node-RED.desktop + # - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/nodered.rotate + # dest: /etc/logrotate.d/nodered + # - url: 'https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Pi%20cpu%20temperature.json' + # dest: '/usr/lib/node_modules/node-red-contrib-ibm-watson-iot/examples/Pi cpu temperature.json' + +#- name: Replace/Tweak "node-red-contrib-ibm-watson-iot/examples/Pi cpu temperature.json" (rpi) +# command: 'curl -sL -o /usr/lib/node_modules/node-red-contrib-ibm-watson-iot/examples/Pi\ cpu\ temperature.json https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Pi%20cpu%20temperature.json' +# when: nodered_install and internet_available and is_raspbian + +#- name: 'Download/Install 4 RPi executables to /usr/bin: node-red-start, node-red-stop, node-red-restart, node-red-log' +- name: 'Install 5 executables to /usr/bin: node-red-start, node-red-stop, node-red-restart, node-red-reload, node-red-log' + get_url: + url: "{{ item }}" + dest: /usr/bin + mode: a+x + force: yes + timeout: "{{ download_timeout }}" + with_items: + - https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-start + - https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-stop + - https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-restart + - https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-reload + - https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-log + # 2022-08-06: New versions above, pasted from https://github.com/node-red/linux-installers/blob/master/deb/update-nodejs-and-nodered + # - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-start + # - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-stop + # - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-restart + # - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-log + +# 2022-06-08 #3245: Raspberry Pi OS recently removed the 'pi' user. For now, +# until converging on a longer-term strategy, let's comment out both stanzas: + +# - name: Create /home/pi/.node-red/ directory (rpi) +# file: +# path: /home/pi/.node-red +# state: directory +# owner: pi +# group: pi +# mode: 0775 + +# - name: Install /home/pi/.node-red/settings.js from template, with authentication (rpi) +# template: +# src: settings.js.j2 +# dest: /home/pi/.node-red/settings.js +# owner: pi +# group: pi +# mode: 0755 diff --git a/roles/nodered/tasks/rpi_desk.yml b/roles/nodered/tasks/rpi_desk.yml deleted file mode 100644 index bc61c971f..000000000 --- a/roles/nodered/tasks/rpi_desk.yml +++ /dev/null @@ -1,47 +0,0 @@ -# TEST UNNEC ICON/MENU FILE PLACEMENT ON RASPIAN LITE TOO ! -- name: 'Download/Install 4 useful items for RPi: Node-RED icon, start menu item, /etc/logrotate.d/nodered, tweaked "Pi cpu temperature.json"' - get_url: - url: "{{ item.url }}" - dest: "{{ item.dest }}" - timeout: "{{ download_timeout }}" - with_items: - - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-icon.svg - dest: /usr/share/icons/hicolor/scalable/apps/node-red-icon.svg - - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Node-RED.desktop - dest: /usr/share/applications/Node-RED.desktop - - url: https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/nodered.rotate - dest: /etc/logrotate.d/nodered - - url: 'https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Pi%20cpu%20temperature.json' - dest: '/usr/lib/node_modules/node-red-contrib-ibm-watson-iot/examples/Pi cpu temperature.json' - -#- name: Replace/Tweak "node-red-contrib-ibm-watson-iot/examples/Pi cpu temperature.json" (rpi) -# command: 'curl -sL -o /usr/lib/node_modules/node-red-contrib-ibm-watson-iot/examples/Pi\ cpu\ temperature.json https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/Pi%20cpu%20temperature.json' -# when: nodered_install and internet_available and is_raspbian - -- name: 'Download/Install 4 RPi executables to /usr/bin: node-red-start, node-red-stop, node-red-restart, node-red-log' - get_url: - url: "{{ item }}" - dest: /usr/bin - mode: a+x - timeout: "{{ download_timeout }}" - with_items: - - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-start - - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-stop - - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-restart - - https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-log - -- name: Create /home/pi/.node-red/ directory (rpi) - file: - path: /home/pi/.node-red - state: directory - owner: pi - group: pi - mode: 0775 - -- name: Install /home/pi/.node-red/settings.js from template, with authentication (rpi) - template: - src: settings.js.j2 - dest: /home/pi/.node-red/settings.js - owner: pi - group: pi - mode: 0755 diff --git a/roles/nodered/tasks/settings.yml b/roles/nodered/tasks/settings.yml new file mode 100644 index 000000000..92833d91a --- /dev/null +++ b/roles/nodered/tasks/settings.yml @@ -0,0 +1,126 @@ +# 2022-06-09: This file used to be group.yml + +- name: Ensure Linux group '{{ nodered_linux_user }}' exists + group: + name: "{{ nodered_linux_user }}" + state: present + +- name: Ensure nodered_linux_user '{{ nodered_linux_user }}' exists and is added to group '{{ nodered_linux_user }}' + user: + name: "{{ nodered_linux_user }}" + group: "{{ nodered_linux_user }}" # Primary group + +- name: Ensure directory /home/{{ nodered_linux_user }}/.node-red/ exists + file: + path: /home/{{ nodered_linux_user }}/.node-red + state: directory + owner: "{{ nodered_linux_user }}" + group: "{{ nodered_linux_user }}" + mode: 0775 + + +# - name: Install /home/{{ nodered_linux_user }}/.node-red/settings.js from template, with authentication +# template: +# backup: yes +# src: settings.js.j2 +# dest: /home/{{ nodered_linux_user }}/.node-red/settings.js +# owner: "{{ nodered_linux_user }}" +# group: "{{ nodered_linux_user }}" +# mode: 0755 + +# 2022-06-08 some alternative options arising from official installer +# https://github.com/node-red/linux-installers/blob/master/deb/update-nodejs-and-nodered +# +# 1) User {{ nodered_linux_user }} run 'node-red admin init' to create /home/{{ NODERED_LINUX_USER }}/.node-red/settings.js +# 2) Copy /usr/lib/node_modules/node-red/settings.js to /home/{{ NODERED_LINUX_USER }}/.node-red/settings.js +# 3) https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js +# +# Approach 1) (THEIR VERY INTERACTIVE SCRIPT) can't be automated like this: +#- name: Run 'node-red admin init' as user '{{ nodered_linux_user }}' to create /home/{{ nodered_linux_user }}/.node-red/settings.js +# command: runuser -u {{ nodered_linux_user }} node-red admin init + +# 2022-10-13: These 9 lines (OLD WAY) might be removable by ~2024? PR #3402 +- name: "OLD WAY: Copy /usr/lib/node_modules/node-red/settings.js to /home/{{ nodered_linux_user }}/.node-red/settings.js" + copy: + remote_src: yes + src: /usr/lib/node_modules/node-red/settings.js + dest: /home/{{ nodered_linux_user }}/.node-red/settings.js + owner: "{{ nodered_linux_user }}" + group: "{{ nodered_linux_user }}" + #mode: preserve # Implied (and required) w/ remote_src, since Ansible 2.6 + ignore_errors: yes + +- name: "NEW WAY: Copy /usr/local/lib/node_modules/node-red/settings.js to /home/{{ nodered_linux_user }}/.node-red/settings.js" + copy: + remote_src: yes + src: /usr/local/lib/node_modules/node-red/settings.js + dest: /home/{{ nodered_linux_user }}/.node-red/settings.js + owner: "{{ nodered_linux_user }}" + group: "{{ nodered_linux_user }}" + #mode: preserve # Implied (and required) w/ remote_src, since Ansible 2.6 + ignore_errors: yes + + +- name: Splice username and password into /home/{{ nodered_linux_user }}/.node-red/settings.js + blockinfile: + path: /home/{{ nodered_linux_user }}/.node-red/settings.js + block: |2 # |n MEANS: Set the block's left edge n CHARACTERS TO THE RIGHT of *this line's* indentation -- where n is {1..9} -- instead of setting its left edge to the 1st non-blank line's indentation below + adminAuth: { + type: "credentials", + users: [{ + username: "{{ nodered_admin_user }}", + password: "{{ nodered_admin_pwd_hash }}", + permissions: "*" + }] + }, + marker: "// {mark} ANSIBLE MANAGED BLOCK" # Surround block with comment lines: "// BEGIN ANSIBLE MANAGED BLOCK", "// END ANSIBLE MANAGED BLOCK" + insertafter: '^module.exports = {$' + #insertbefore: '^}$' + +# 2022-06-09: IF ABOVE SNIPPET ALREADY EXISTS *UNCOMMENTED* IN settings.js +# *WITHOUT* ANSIBLE MARKERS, THESE WOULD BE NEEDED INSTEAD OF blockinfile: + +# - name: Splice 'username: "{{ nodered_admin_user }}",' into /home/{{ nodered_linux_user }}/.node-red/settings.js +# lineinfile: +# path: /home/{{ nodered_linux_user }}/.node-red/settings.js +# regexp: 'username:' +# line: ' username: "{{ nodered_admin_user }}",' + +# - name: Splice 'password: "{{ nodered_admin_pwd_hash }}",' into /home/{{ nodered_linux_user }}/.node-red/settings.js +# lineinfile: +# path: /home/{{ nodered_linux_user }}/.node-red/settings.js +# regexp: 'password:' +# line: ' password: "{{ nodered_admin_pwd_hash }}",' + + +# 2022-06-09: httpRoot might be going away? Increasingly hidden from +# settings.js which used to say: "property can be used in place of +# 'httpAdminRoot' and 'httpNodeRoot', to apply the same root to both parts." +# +# "httpRoot sets the root url for both admin and node endpoints. +# It overrides the values set by httpAdminRoot and httpNodeRoot" +# https://nodered.org/docs/user-guide/runtime/configuration +# +# - name: Splice "httpRoot: '/{{ nodered_web_path }}'," into /home/{{ nodered_linux_user }}/.node-red/settings.js +# lineinfile: +# path: /home/{{ nodered_linux_user }}/.node-red/settings.js +# regexp: '^\s*httpRoot:' +# line: " httpRoot: '/{{ nodered_web_path }}'," +# insertafter: '^module.exports = {$' +# #insertbefore: '^}$' + +- name: 'Splice "httpNodeRoot: ''/{{ nodered_web_path }}''," into /home/{{ nodered_linux_user }}/.node-red/settings.js' + lineinfile: + path: /home/{{ nodered_linux_user }}/.node-red/settings.js + regexp: '^\s*httpNodeRoot:' + line: " httpNodeRoot: '/{{ nodered_web_path }}'," + insertafter: '^module.exports = {$' + #insertbefore: '^}$' + +- name: 'Splice "httpAdminRoot: ''/{{ nodered_web_path }}''," into /home/{{ nodered_linux_user }}/.node-red/settings.js' + lineinfile: + path: /home/{{ nodered_linux_user }}/.node-red/settings.js + regexp: '^\s*httpAdminRoot:' + line: " httpAdminRoot: '/{{ nodered_web_path }}'," + insertafter: '^module.exports = {$' + #insertbefore: '^}$' diff --git a/roles/nodered/templates/nodered.service.j2 b/roles/nodered/templates/nodered.service.j2.unused similarity index 100% rename from roles/nodered/templates/nodered.service.j2 rename to roles/nodered/templates/nodered.service.j2.unused diff --git a/roles/nodered/templates/settings.js.j2 b/roles/nodered/templates/settings.js.j2.unused similarity index 99% rename from roles/nodered/templates/settings.js.j2 rename to roles/nodered/templates/settings.js.j2.unused index 50923671c..c484a4bcb 100644 --- a/roles/nodered/templates/settings.js.j2 +++ b/roles/nodered/templates/settings.js.j2.unused @@ -118,8 +118,8 @@ module.exports = { adminAuth: { type: "credentials", users: [{ - username: "{{ nodered_user }}", - password: "{{ nodered_password_hash }}", + username: "{{ nodered_admin_user }}", + password: "{{ nodered_admin_pwd_hash }}", permissions: "*" }] }, diff --git a/roles/openvpn/templates/iiab-remote-off b/roles/openvpn/templates/iiab-remote-off deleted file mode 100755 index 9d3b0d258..000000000 --- a/roles/openvpn/templates/iiab-remote-off +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# /usr/bin/iiab-remote-off should fully turn off multiple remote support -# services like OpenVPN and others, to reduce risk of remote attacks. - -echo -e '\nWARNING: To disable OpenVPN long-term, it'"'"'s recommended you:\n' - -echo -e '1) Set this variable in /etc/iiab/local_vars.yml' -echo -e ' openvpn_enabled: False\n' - -echo -e '2) Run:' -echo -e ' cd /opt/iiab/iiab' -echo -e ' sudo ./runrole openvpn\n' - -# Do nothing if OpenVPN not installed -which openvpn -if [ $? -ne 0 ]; then - echo 'Cannot find the OpenVPN program (openvpn).' - exit 1 -fi - -systemctl disable openvpn -systemctl stop openvpn - -sleep 5 -ps -e | grep openvpn # 2018-09-05: "ps -e | grep vpn" no longer works (nor would "pgrep vpn") when invoked from iiab-vpn-off (as filename itself causes [multiple] "vpn" instances to appear in process list!) -if [ $? -eq 0 ]; then - echo OpenVPN failed to stop. -else - echo Successfully stopped and disabled OpenVPN. -fi diff --git a/roles/osm-vector-maps/README.md b/roles/osm-vector-maps/README.md index e5acf736e..030c411b8 100644 --- a/roles/osm-vector-maps/README.md +++ b/roles/osm-vector-maps/README.md @@ -1,28 +1,54 @@ -## What's New with IIAB Maps in IIAB 7.2? +## What's New with IIAB Maps? -1. If you install [IIAB 7.2](https://github.com/iiab/iiab/wiki/IIAB-7.2-Release-Notes) with [IIAB Maps](https://github.com/iiab/iiab/wiki/IIAB-Maps), a new **Install IIAB Maps** page is available (http://box/osm-vector-maps/installer/) with [instructions](https://github.com/iiab/iiab/wiki/IIAB-Maps#how-do-i-install-map-packs-and-satellite-photo-regions-on-iiab-72-), separate from IIAB's Admin Console: +1. If you install [IIAB 8.0+](https://github.com/iiab/iiab/wiki/IIAB-8.0-Release-Notes) (a pre-release is fine!) with [IIAB Maps](https://github.com/iiab/iiab/wiki/IIAB-Maps) an **Install IIAB Maps** page is available (http://box/osm-vector-maps/installer/) with [instructions](https://github.com/iiab/iiab/wiki/IIAB-Maps#how-do-i-install-map-packs-and-satellite-photo-regions-on-iiab-80-), separate from IIAB's Admin Console: 1. This [very visual page](https://user-images.githubusercontent.com/2458907/94740848-46c4eb00-0341-11eb-93ea-e3e4758dce48.png) facilitates selecting/downloading/installing of Map Pack(s) for your favorite "continent(s)". (SEE 2. BELOW) - 2. If you've installed at least one Map Pack, you can then use this same page to select/download/install Hi-Res Satellite Photo Region(s) for your local communities. (SEE 3. BELOW) - 3. All these downloads can now happen 10X to 100X faster, thanks to [PR #38](https://github.com/iiab/maps/pull/38) ! + 2. You can then use this same page to select/download/install Hi-Res Satellite Photo Region(s) for your local communities. (SEE 3. BELOW) + 3. All these downloads can now happen 10X to 100X faster, thanks to PR's [iiab/maps#38](https://github.com/iiab/maps/pull/38), [iiab/maps#58](https://github.com/iiab/maps/pull/58) and [iiab/iiab-admin-console#478](https://github.com/iiab/iiab-admin-console/pull/478) ! + 4. _When installing OpenStreetMap "continents" (a.k.a. regions), consider either the command-line ([/usr/bin/iiab-install-map-region](https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region)) or the visual alternative provided by IIAB's Admin Console: http://box.lan/admin > Install Content > Get Map Regions._ 2. **Map Packs** no longer bundle both data and program in a .zip file. All Map Packs are really now just a collection of 3 .mbtiles files: - 1. The main focus of a Map Pack remains Hi-Res Vector Map data from OpenStreetMap, for your selected "continent" β€” but Lo-Res vector map tiles (1.74GB .mbtiles) and Lo-Res satellite photos (932MB .mbtiles) are also included for the entire planet. Read more at: https://github.com/iiab/iiab/wiki/IIAB-Maps - 2. Every Map Pack's OSM vector tile data (originally from 2017) was updated to [September 2019](https://archive.org/details/osm-vector-mbtiles). - 3. The world view (planetwide OSM vector maps included with all Map Packs) increased zoom levels from 0-9 to 0-10 (1.74GB osm-planet_z0-z10_2019.mbtiles) so that city search is successful more of the time. + 1. The main focus of a Map Pack remains Hi-Res Vector Map data from OpenStreetMap, for your selected "continent" β€” but Lo-Res vector map tiles (2.0 GB .mbtiles) and Lo-Res satellite photos (1.2 GB .mbtiles) are also included for the entire planet. Read more at: https://github.com/iiab/iiab/wiki/IIAB-Maps + 2. Every Map Pack's OSM vector tile data (originally from 2017, and then September 2019) was updated to [November 2020](https://archive.org/details/osm-vector-mbtiles). + 3. The world view (planetwide OSM vector maps included with all Map Packs) increased zoom levels from 0-9 to 0-10 (2.0 GB osm-planet_z0-z10_2020.mbtiles) so that city search is successful more of the time. 4. Multiple Map Packs can be downloaded/installed (one "continent" at a time). However this can waste disk space with duplicate data, and potentially cause rendering slowness in areas where Map Packs overlap ("continent" bounding boxes have been designed to overlap on purpose, so multiple Map Packs are rarely necessary!) 3. **Hi-Res Satellite Photos** can be downloaded/installed for any 100 x 100 km, 300 x 300 km, or 1000 x 1000 km square region (around any map point that you click!) 1. These new Hi-Res Satellite Photo Regions are "squares" with 4 additional levels of satellite photo zoom (i.e. zoom levels 10-13) giving you 16X the resolution (i.e. 19 x 19 m pixels) and 256X more photographic information density. - 2. As compared to Lo-Res Satellite Photos i.e. zoom levels 0-9 (305 x 305 m pixels) everywhere else on the planet (932MB satellite_z0-z9_v3.mbtiles is included with all Map Packs). (SEE 2. ABOVE) + 2. As compared to Lo-Res Satellite Photos i.e. zoom levels 0-9 (305 x 305 m pixels) everywhere else on the planet (1.2 GB satellite_z0-z9_2020.mbtiles is included with all Map Packs). (SEE 2. ABOVE) 3. Multiple Hi-Res Satellite Photo Regions can be downloaded/installed (one "square" region at a time, thankfully duplicate disk space is avoided when such "squares" overlap!) 4. Some variables have newer meanings: - 1. `osm_vector_maps_install` in [/etc/iiab/local_vars.yml](http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F) means install the map program and 7 levels of zoom (about 40MB ?) - 2. `osm_vector_maps_enabled` in [/etc/iiab/local_vars.yml](http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F) is once again standardized, solving #2484 install delays. + 1. `osm_vector_maps_install` in [/etc/iiab/local_vars.yml](https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F) means install the map program and 7 basic levels of zoom (48MB for OSM + 25 MB for satellite photos). + 2. `osm_vector_maps_enabled` in [/etc/iiab/local_vars.yml](https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F) is once again standardized, solving #2484 install delays. 3. `osm_vector_maps_installed` in `/etc/iiab/iiab_state.yml` means a functioning world map with 7 levels of zoom (z0-z6) has been installed β€” i.e. a preview of IIAB's mapping system that helps you select Maps Pack(s) and Hi-Res Satellite Photo Region(s) to download and install on your IIAB. (SEE 1. ABOVE) 5. **Drag-and-Drop Map Overlays** β€” try this by dragging and dropping any relevant GeoJSON file onto the IIAB Maps (http://box/maps) in your browser! For example try this GeoJSON file, to explore the shape of gerrymandered US Congressional districts: https://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_500_11_20m.json -6. Similarly but separately: Students can _Right-Click_ on IIAB Maps (http://box/maps) to **add descriptions and photos** of local points of interest. Choose "Add Data Point" after right-clicking, and then later "Export Points" to share with others. [CAN ANYBODY SUGGEST STUDENT/TEACHER OUTDOOR EXPLORATION / GEOSPATIAL ADVENTURE TIPS THAT WORK WELL WITH STUDENT PHONES?] +#### How to (Wipe and) Upgrade IIAB Maps + + +In April 2022, IIAB revised our legacy catalog [/etc/iiab/map-catalog.json](https://github.com/iiab/maps/blob/master/2020/map-catalog.json), our new catalog [/library/www/html/common/assets/adm-map-catalog.json](https://github.com/iiab/iiab-admin-console/blob/master/roles/common/files/map/adm-map-catalog.json), associated programs — and the dozen core [OSM continent/region .mbtiles files](https://github.com/iiab/iiab/wiki/IIAB-Maps#where-are-iiab-maps-stored) listed in our catalog. + +_It's always best to start fresh with a [new install of IIAB](https://download.iiab.io) if you want the latest maps!_ + +Or, if you absolutely must attempt an upgrade (ENTIRELY AT YOUR OWN RISK) run the following — to attempt to delete your existing maps — and then add new IIAB Maps: + + ``` + sudo rm -rf /library/www/osm-vector-maps + cd /opt/iiab/iiab + sudo git pull + sudo ./runrole --reinstall osm-vector-maps + sudo iiab-install-map-region .mbtiles + ``` + +Where `.mbtiles` is one of the [major region files](https://github.com/iiab/iiab/wiki/IIAB-Maps#where-are-iiab-maps-stored) (e.g. with "2020" in its filename) that you choose from IIAB's [map catalog](https://github.com/iiab/iiab/wiki/IIAB-Maps#how-do-i-upgrade-an-iiab-map-pack). + + ~cd /library/www/
+ rm -rf osm-vector-maps/
+ nano /etc/iiab/iiab_state.yml # Delete line 'osm_vector_maps_installed: True'
+ git remote add ghunt git@github.com:/georgejhunt/iiab
+ git fetch --all
+ git checkout -b maps7.3 ghunt/maps7.3
+ ./runroles osm-vector-maps~ #### Please also see the IIAB Maps doc: https://github.com/iiab/iiab/wiki/IIAB-Maps diff --git a/roles/osm-vector-maps/defaults/main.yml b/roles/osm-vector-maps/defaults/main.yml index 5c8f219ba..b000c992a 100644 --- a/roles/osm-vector-maps/defaults/main.yml +++ b/roles/osm-vector-maps/defaults/main.yml @@ -1,19 +1,34 @@ # osm_vector_maps_install: True # osm_vector_maps_enabled: True -# iiab_map_url : http://download.iiab.io/content/OSM/vector-tiles/maplist/hidden -# vector_map_path: "{{ content_base }}/www/osm-vector-maps" +# maps_from_internet_archive: False +# vector_map_path: "{{ content_base }}/www/osm-vector-maps" # /library/www/osm-vector-maps # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -# The following soft coded variables allow testing, before pulling PR's into master -osm_repo_url: https://raw.githubusercontent.com/iiab/maps -#osm_repo_url: https://raw.githubusercontent.com/georgejhunt/maps -maps_branch: 'master' # Quotes not required -#maps_branch: '7.2-maps' -# soft code sources +# Pulls in ~37 files thx to @jvonau's #3192 -- change these 2 during testing: +osm_repo_url: https://raw.githubusercontent.com/iiab/maps +maps_branch: master # Quotes not required +#osm_repo_url: https://raw.githubusercontent.com/georgejhunt/maps +#maps_branch: maps7.3 + +# 2022-04-30 -- Bluehost (timmoody.com) has become extremely slow! +#maps_assets_url: https://timmoody.com/iiab-files/maps +#maps_assets_url: https://download.iiab.io/content/OSM/vector-tiles +maps_assets_url: https://raw.githubusercontent.com/iiab/maps-assets/main + +# cities1000.sqlite # 26MB +installer_planet: planet_z0-z6_2020.mbtiles # 48MB +installer_satellite: satellite_z0-z6_2020.mbtiles # 25MB + + +# 2022-04-30 WIP -- CLI approach to installing larger .mbtiles OSM "continents" a.k.a. regions: +# https://github.com/iiab/maps/blob/master/osm-source/pages/viewer/scripts/iiab-install-map-region +# 2022-04-30 WIP -- This var might be used in future: (with boolean var maps_from_internet_archive) archive_org_url: https://archive.org/download -map_catalog_url: http://download.iiab.io/content/OSM/vector-tiles -satellite_version: satellite_z0-z9_v3.mbtiles # 2021-12-20: Var unused, but hard-coded in 11 places within https://github.com/iiab/iiab-admin-console -- #3077 discusses map-catalog.json & adm-map-catalog.json + + +# 2022-04-30 -- Unused, but URL illustrates legacy approach: +#iiab_map_url: https://download.iiab.io/content/OSM/vector-tiles/maplist/hidden diff --git a/roles/osm-vector-maps/tasks/install.yml b/roles/osm-vector-maps/tasks/install.yml index c57a07700..f46016ebc 100644 --- a/roles/osm-vector-maps/tasks/install.yml +++ b/roles/osm-vector-maps/tasks/install.yml @@ -1,3 +1,18 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: "Install packages for map installation: python3-geojson, python3-pil, python3-wget, php{{ php_version }}-sqlite3 (can also be installed by www_base/tasks/php-stem.yml)" + package: + state: present + name: + - python3-geojson + - python3-pil + - python3-wget + #- php{{ php_version }}-common # Auto-installed as an apt dependency. REGARDLESS: php{{ php_version }}-common superset php{{ php_version }}-cli is auto-installed by php{{ php_version }}-fpm in nginx/tasks/install.yml + - php{{ php_version }}-sqlite3 + - name: Make 5 directories (0755 by default) file: path: "{{ item }}" @@ -10,30 +25,18 @@ - "{{ vector_map_path }}/viewer/tiles" - "{{ vector_map_path }}/installer" -- name: Download {{ map_catalog_url }}/map-catalog.json to {{ iiab_etc_path }} +- name: Download 26MB {{ maps_assets_url }}/cities1000.sqlite to {{ vector_map_path }}/viewer/ get_url: - url: "{{ map_catalog_url }}/map-catalog.json" # http://download.iiab.io/content/OSM/vector-tiles - dest: "{{ iiab_etc_path }}" # /etc/iiab - timeout: "{{ download_timeout }}" - -- name: Download {{ iiab_map_url }}/assets/regions.json to {{ iiab_etc_path }} - get_url: - url: "{{ iiab_map_url }}/assets/regions.json" # http://download.iiab.io/content/OSM/vector-tiles/maplist/hidden - dest: "{{ iiab_etc_path }}" - timeout: "{{ download_timeout }}" - -# - name: Does 26M cities database {{ vector_map_path }}/viewer/cities1000.sqlite exist? -# stat: -# path: "{{ vector_map_path }}/viewer/cities1000.sqlite" -# register: cities_installed - -# - name: If not, download {{ iiab_map_url }}/regional-resources/cities1000.sqlite to {{ vector_map_path }}/viewer/ -- name: Download 26M {{ iiab_map_url }}/regional-resources/cities1000.sqlite to {{ vector_map_path }}/viewer/ - get_url: - url: "{{ iiab_map_url }}/regional-resources/cities1000.sqlite" + url: "{{ maps_assets_url }}/cities1000.sqlite" # e.g. https://raw.githubusercontent.com/iiab/maps-assets/main dest: "{{ vector_map_path }}/viewer/" timeout: "{{ download_timeout }}" -# when: not cities_installed.stat.exists + + +- name: Download {{ osm_repo_url }}/{{ maps_branch }}/2020/map-catalog.json to {{ iiab_etc_path }} + get_url: + url: "{{ osm_repo_url }}/{{ maps_branch }}/2020/map-catalog.json" # e.g. https://raw.githubusercontent.com/iiab/maps/master + dest: "{{ iiab_etc_path }}" # /etc/iiab + timeout: "{{ download_timeout }}" - name: Symlink {{ doc_root }}/common/assets/map-catalog.json -> /etc/iiab/map-catalog.json file: @@ -47,16 +50,10 @@ path: "{{ vector_map_path }}/test-page/assets/map-catalog.json" state: link -- name: Symlink {{ vector_map_path }}/maplist/assets/regions.json -> /etc/iiab/regions.json - file: - src: /etc/iiab/regions.json - path: "{{ vector_map_path }}/maplist/assets/regions.json" - state: link -# At this point, fetches from github.com/georgejhunt/maps from test branch - name: Download OpenLayers test page stuff (JavaScript bundle etc) from {{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/test-page/build/* to {{ vector_map_path }}/test-page/ -- for test page http://box/osm-vector-maps/installer/ get_url: - url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/test-page/build/{{ item }}" # https://raw.githubusercontent.com/iiab/maps / master + url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/test-page/build/{{ item }}" dest: "{{ vector_map_path }}/test-page/" timeout: "{{ download_timeout }}" with_items: @@ -64,7 +61,6 @@ - index.html - name: Download OpenLayers viewer page stuff (JavaScript bundle etc) from {{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/build/* to {{ vector_map_path }}/viewer/ -# At this point, fetches from github.com/iiab/maps from {{ maps_branch }} branch get_url: url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/build/{{ item }}" dest: "{{ vector_map_path }}/viewer/" @@ -85,30 +81,32 @@ - searchapi.php - tileserver.php -- name: Download 34MB {{ map_catalog_url }}/planet_z0-z6_2019.mbtiles to {{ vector_map_path }}/installer/ -- for map installer + +- name: Download 48MB {{ maps_assets_url }}/{{ installer_planet }} to {{ vector_map_path }}/installer/ -- for map installer get_url: - url: "{{ map_catalog_url }}/planet_z0-z6_2019.mbtiles" + url: "{{ maps_assets_url }}/{{ installer_planet }}" # e.g. planet_z0-z6_2020.mbtiles dest: "{{ vector_map_path }}/installer/" timeout: "{{ download_timeout }}" -- name: Symlink {{ vector_map_path }}/installer/detail.mbtiles -> {{ vector_map_path }}/installer/planet_z0-z6_2019.mbtiles +- name: Symlink {{ vector_map_path }}/installer/detail.mbtiles -> {{ vector_map_path }}/installer/{{ installer_planet }} file: - src: "{{ vector_map_path }}/installer/planet_z0-z6_2019.mbtiles" + src: "{{ vector_map_path }}/installer/{{ installer_planet }}" path: "{{ vector_map_path }}/installer/detail.mbtiles" state: link -- name: Symlink {{ vector_map_path }}/viewer/tiles/planet_z0-z6_2019.mbtiles -> {{ vector_map_path }}/installer/planet_z0-z6_2019.mbtiles +- name: Symlink {{ vector_map_path }}/viewer/tiles/{{ installer_planet }} -> {{ vector_map_path }}/installer/{{ installer_planet }} file: - src: "{{ vector_map_path }}/installer/planet_z0-z6_2019.mbtiles" - path: "{{ vector_map_path }}/viewer/tiles/planet_z0-z6_2019.mbtiles" + src: "{{ vector_map_path }}/installer/{{ installer_planet }}" + path: "{{ vector_map_path }}/viewer/tiles/{{ installer_planet }}" state: link -- name: Download abbreviated satellite images from {{ map_catalog_url }}/satellite_z0-z6_v3.mbtiles to {{ vector_map_path }}/viewer/tiles/ +- name: Download 25MB {{ maps_assets_url }}/{{ installer_satellite }} to {{ vector_map_path }}/viewer/tiles/ -- basic satellite photos get_url: - url: "{{ map_catalog_url }}/satellite_z0-z6_v3.mbtiles" + url: "{{ maps_assets_url }}/{{ installer_satellite }}" # e.g. satellite_z0-z6_2020.mbtiles dest: "{{ vector_map_path }}/viewer/tiles/" timeout: "{{ download_timeout }}" + - name: Download {index.html, installer-bundle.js} from {{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/installer/build/* to {{ vector_map_path }}/installer/ -- for map installer get_url: url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/installer/build/{{ item }}" @@ -129,7 +127,6 @@ - installer-functions.js - tileserver.php -# the following was changed to grab from the iiab/maps repo - name: Download 15 common assets from {{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/assets/* to {{ vector_map_path }}/viewer/assets/ -- for the general purpose map viewer get_url: url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/assets/{{ item }}" @@ -139,7 +136,7 @@ - bboxes.geojson - center.png - countries.json - - fonts.css + # - fonts.css - ol-layerswitcher.css - ol-contextmenu.css - pin_drop.png @@ -166,15 +163,19 @@ state: link force: yes -- name: Copy fonts (16 files) to {{ doc_root }}/common/fonts/ for the general purpose map viewer (root:root, 0644 by default) + +- name: Copy noto-sans fonts (15 files) to {{ doc_root }}/common/fonts/ for the general purpose map viewer (root:root, 0644 by default) copy: src: "{{ item }}" dest: "{{ doc_root }}/common/fonts/" - # mode: 0644 - # owner: root - # group: root with_fileglob: - - fonts/* + - fonts/noto-sans* + +- name: Copy fonts.css to {{ vector_map_path }}/viewer/assets/ + copy: + src: fonts/fonts.css + dest: "{{ vector_map_path }}/viewer/assets/" + - name: Force Download redirect {{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/installer-index.redirect to test page {{ vector_map_path }}/maplist/index.html get_url: @@ -183,16 +184,6 @@ force: yes timeout: "{{ download_timeout }}" -- name: "Install packages for map installation: python3-geojson, python3-pil, python3-wget, php{{ php_version }}-sqlite3 (can also be installed by www_base/tasks/php-stem.yml)" - package: - state: present - name: - - python3-geojson - - python3-pil - - python3-wget - #- php{{ php_version }}-common # Auto-installed as an apt dependency. REGARDLESS: php{{ php_version }}-common superset php{{ php_version }}-cli is auto-installed by php{{ php_version }}-fpm in nginx/tasks/install.yml - - php{{ php_version }}-sqlite3 - - name: Copy 6 scripts to /usr/bin, for downloading tiles (0755) get_url: url: "{{ osm_repo_url }}/{{ maps_branch }}/osm-source/pages/viewer/scripts/{{ item }}" @@ -210,6 +201,17 @@ # RECORD OSM Vector Maps AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'osm_vector_maps_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: osm-vector-maps + option: osm_vector_maps_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'osm_vector_maps_installed: True'" set_fact: osm_vector_maps_installed: True diff --git a/roles/osm-vector-maps/tasks/main.yml b/roles/osm-vector-maps/tasks/main.yml index a16cfcd34..388c594d6 100644 --- a/roles/osm-vector-maps/tasks/main.yml +++ b/roles/osm-vector-maps/tasks/main.yml @@ -11,28 +11,34 @@ quiet: yes -- name: Install OSM Vector Maps if 'osm_vector_maps_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: osm_vector_maps_installed is undefined - +- block: -- name: Enable/Disable/Reload NGINX for OSM, if nginx_enabled - include_tasks: nginx.yml - #when: nginx_enabled # NGINX is mandatory starting with IIAB 7.2 + - name: Install OSM Vector Maps if 'osm_vector_maps_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: osm_vector_maps_installed is undefined + - name: Enable/Disable/Reload NGINX for OSM, if nginx_enabled + include_tasks: nginx.yml -- name: Add 'osm-vector-maps' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: osm-vector-maps - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: OSM Vector Maps - - option: description - value: '"OpenStreetMap is like Google Maps but better, for schools especially, as it works offline and avoids all the advertising. Download detailed ''vector maps'' for an entire continent, or the entire world! Also includes 10+ zoom levels of satellite imagery!"' - - option: osm_vector_maps_install - value: "{{ osm_vector_maps_install }}" - - option: osm_vector_maps_enabled - value: "{{ osm_vector_maps_enabled }}" + - name: Add 'osm-vector-maps' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: osm-vector-maps + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: OSM Vector Maps + - option: description + value: '"OpenStreetMap is like Google Maps but better, for schools especially, as it works offline and avoids all the advertising. Download detailed ''vector maps'' for an entire continent, or the entire world! Also includes 10+ zoom levels of satellite imagery!"' + - option: osm_vector_maps_install + value: "{{ osm_vector_maps_install }}" + - option: osm_vector_maps_enabled + value: "{{ osm_vector_maps_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/pbx/README.adoc b/roles/pbx/README.adoc index b63d33412..99791114e 100644 --- a/roles/pbx/README.adoc +++ b/roles/pbx/README.adoc @@ -4,6 +4,13 @@ https://internet-in-a-box.org[Internet-in-a-Box (IIAB)] can install https://asterisk.org/[Asterisk] and https://freepbx.org/[FreePBX] for Voice over IP (VoIP) calls using regular Android and iPhone softphone (SIP) apps β€” e.g. for low-cost and rural telephony. +As of December 2024, IIAB supports https://www.asterisk.org/asterisk-news/asterisk-22-0-0-now-available/[Asterisk 22] and https://sangomakb.atlassian.net/wiki/spaces/FP/pages/222101505/FreePBX+17[FreePBX 17] (https://www.freepbx.org/freepbx-17-is-now-ga/[announcement]). A https://github.com/iiab/iiab/wiki/IIAB-Platforms#operating-systems[modern OS with PHP 8.x] is required (https://github.com/iiab/iiab/pull/3675[PR #3675]). + +//// +*PHP 7.4 is unfortunately REQUIRED (https://github.com/iiab/iiab/pull/2899[PR #2899]) and PHP 8.x does not yet work (https://github.com/iiab/iiab/issues/3556[#3556], https://github.com/iiab/iiab/pull/3675[#3675]) — sadly this remains true as of 2024-01-13 with https://www.freepbx.org/freepbx-17-beta-release-and-debian-future/[FreePBX 17 BETA], and may remain true until https://github.com/FreePBX/framework/tree/release/17.0[FreePBX 17] is eventually released — so if you really must try to force an install onto dangerously EOL'd (end-of-life as of November 2022) PHP 7.4, consider an older OS like https://github.com/iiab/iiab/wiki/IIAB-Platforms#operating-systems[Ubuntu 20.04, Debian 11 "Bullseye", or 64-bit Raspberry Pi OS versions based on "Bullseye"] (https://github.com/iiab/iiab/pull/3523[PR #3523]). RECAP: IIAB does _NOT_ support such dangerous/older OS's!* +//// + +//// As of August 2021, IIAB installs https://wiki.asterisk.org/wiki/display/AST/Asterisk+18+Documentation[Asterisk 18] and https://www.freepbx.org/freepbx-16-beta-is-here/[FreePBX 16 Beta], as required by the latest PHP 7.4 Linux OS's (https://github.com/iiab/iiab/pull/2899[PR #2899]). Please consider installing this on https://github.com/iiab/iiab/wiki/IIAB-Platforms#operating-systems[Ubuntu 20.04+, Debian 11 β€” or the imminent Raspberry Pi OS 11 "Bullseye"]. _PLEASE UNDERSTAND THIS MEANS THAT: IIAB no longer supports FreePBX 15 (Linux with PHP < 7.4, e.g. Raspberry Pi OS 10 "Buster"). Thank you for your understanding, as we look to the future together!_ @@ -11,7 +18,7 @@ _PLEASE UNDERSTAND THIS MEANS THAT: IIAB no longer supports FreePBX 15 (Linux wi _Upcoming:_ IIAB will consider supporting Asterisk 19, on or around its 2021-09-28 expected release date (https://github.com/iiab/iiab/issues/2934[#2934]). _Historical:_ Back in February 2019, IIAB had installed Asterisk 16 and FreePBX 15, e.g. for Ubuntu 18.04, Debian 9 "Stretch" and experimentally, Raspberry Pi (https://github.com/iiab/iiab/issues/1467[#1467]). - +//// == What Asterisk & FreePBX do @@ -23,39 +30,47 @@ https://en.wikipedia.org/wiki/FreePBX[FreePBX] is a web-based open source GUI (g == Install it -. As you begin installing Internet-in-a-Box (IIAB) from http://download.iiab.io[download.iiab.io], it will prompt you: +. As you begin installing Internet-in-a-Box (IIAB) from https://download.iiab.io[download.iiab.io], it will prompt you: + ---- Edit /etc/iiab/local_vars.yml to customize your Internet-in-a-Box? [Y/n] ---- + -Accept the challenge! Make sure your IIAB configuration file (http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F[/etc/iiab/local_vars.yml]) contains: +Accept the challenge! Make sure your IIAB configuration file (https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F[/etc/iiab/local_vars.yml]) contains: + ---- pbx_install: True pbx_enabled: True ---- + -FreePBX can be used with either or both web servers, NGINX on port 80 (as is new) and/or Apache on port 83 (as is traditional). +FreePBX can be used with either or both web servers β€” NGINX on port 80 (http://box/freepbx) and/or using the old approach with Apache on port 83 (http://box:83/freepbx). + -If you don't want Apache installed on your IIAB, and you prefer NGINX's shorter URL (http://box/freepbx), optionally set this line in your http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F[/etc/iiab/local_vars.yml] prior to installing IIAB: +If you still want the older Apache approach, set this line in your https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F[/etc/iiab/local_vars.yml] prior to installing IIAB: + ---- -pbx_use_apache: False +pbx_use_apache: True ---- + -Or, if you want to use FreePBX with Apache alone (http://box:83/freepbx), optionally set this line in your /etc/iiab/local_vars.yml: +If you want to disable to new NGINX approach, set this line in your /etc/iiab/local_vars.yml: + ---- pbx_use_nginx: False ---- + -If using PBX intensively, please adjust `/etc/php/X.Y/apache2/php.ini`, `/etc/php/X.Y/cli/php.ini` and/or `/etc/php/X.Y/nginx/php.ini` (where `X.Y` is typically 7.4) as outlined within https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L88-L131[/opt/iiab/iiab/roles/www_options/tasks/main.yml] — some of which happens automatically if you also set: +If using PBX intensively, please adjust `/etc/php/X.Y/apache2/php.ini`, `/etc/php/X.Y/cli/php.ini` and/or `/etc/php/X.Y/nginx/php.ini` (where `X.Y` is typically 7.4) as outlined within link:../www_options/tasks/main.yml#L86-L129[/opt/iiab/iiab/roles/www_options/tasks/main.yml] — some of which happens automatically if you also set: + ---- nginx_high_php_limits: True ---- + +//// +As of April 2023 (https://github.com/iiab/iiab/pull/3523[PR #3523]) IIAB will patch Asterisk automatically (https://github.com/asterisk/asterisk/pull/32[PR asterisk/asterisk#32]) so it can be run experimentally on Raspberry Pi, so long as you keep this default settings: ++ +---- +asterisk_rpi_patch: True +---- ++ +//// Optionally, you may want to enable https://github.com/wdoekes/asterisk-chan-dongle[chan_dongle], which is a channel driver for Huawei UMTS cards (e.g. 3G USB dongles) allowing regular voice calls over GSM mobile networks. You will need to configure a dongle post-install, for it to be recognized properly: + ---- @@ -145,6 +160,26 @@ image::files/linphone_setup.jpg[width='33%'] image::files/linphone_connected.jpg[width='33%'] * _If you've created more than one extension, make a call to another extension!_ If you've not yet made more than one extension, try calling an arbitrary extension, or try calling your own extension (your own phone number). ++ +Due to Linphone's inability for phones to ring when the screen is locked, you can alternatively use a softphone (SIP) app on your smartphone or laptop called Wave Lite. In this example we will use the [https://wiki.zenitel.com/wiki/Grandstream_Wave_Lite_mobile_app], on an Android phone. After you open the app, follow these steps: + +** Connect your smartphone or laptop to the *Internet in a Box* WiFi hotspot +** Go to Account Settings +** Add new account +** Select *SIP ACCOUNT* + +*** *Account name* is your name, e.g. John Doe +*** *Sip Server* is your IIAB server's IP address +*** *SIP User ID* is your extension number, e.g. 301 +*** *SIP Authentification ID* is your extension number, e.g. 301 +*** *Password* is the same as above *Secret* +*** *Confirm by clicking tick symbol βœ“ (top right) ++ +image::files/wave_sip settings.png[width='33%'] + +** If the connection is successful, you will see a green circle next to your name [John Doe]. ++ +image::files/Wave_sip_phone_connected.png[width='33%'] ** You should see activity in the *FreePBX Statistics* applet at http://box/freebx (or http://box:83/freebx) > *Dashboard* ** Connection details may also be seen in the Asterisk logs at: `/var/logs/asterisk/full` @@ -233,6 +268,7 @@ sudo fwconsole reload * Exit the Asterisk CLI, and try Linux commands like: + ---- +asterisk -rx "core show version" asterisk -rx "pjsip show endpoints" asterisk -rx "cdr show status" ---- @@ -279,33 +315,31 @@ image::files/password_change.jpg[] == Known Issues -Please also check the "Known Issues" at the bottom of https://github.com/iiab/iiab/wiki#our-evolution[IIAB's latest release notes]. +Please also check the "Known Issues" at the bottom of https://github.com/iiab/iiab/wiki#past-releases[IIAB's latest release notes]. -_If there's a bug or serious problem with IIAB, please do https://internet-in-a-box.org/pages/contributing.html[make contact] and post an issue here: https://github.com/iiab/iiab/issues_ +_If there's a bug or serious problem with IIAB, please do https://internet-in-a-box.org/contributing.html[make contact] and post an issue here: https://github.com/iiab/iiab/issues_ -. As of 2021-11-05, FreePBX 16 needed 2 lines to be manually patched in order to work with the new Asterisk 19 (https://github.com/iiab/iiab/issues/2934#issuecomment-962137815[#2934]). -+ -As of 2021-11-06, these 2 lines are live-patched (automatically) by IIAB when installing FreePBX (https://github.com/iiab/iiab/pull/3019[PR #3019]). We hope that this workaround becomes unnecessary in coming weeks, thanks to subsequent https://github.com/FreePBX/framework/tags[FreePBX 16 point releases]. +. Please see Asterisk's Security Advisories: https://www.asterisk.org/downloads/security-advisories/ . Apache's `/var/lib/php/asterisk_sessions/` directory might also be needed for NGINX? + -If not, the https://github.com/iiab/iiab/blob/master/roles/pbx/tasks/freepbx.yml#L151-L163[configuration of /var/lib/php/asterisk_sessions/] might be made conditional upon `when: not pbx_use_apache` +If not, the link:tasks/freepbx.yml#L175-L187[configuration of /var/lib/php/asterisk_sessions/] might be made conditional upon `when: not pbx_use_apache` -. The https://github.com/iiab/iiab/blob/master/roles/pbx/tasks/freepbx.yml#L208-L211[installation of /etc/odbc.ini] for CDR (Call Detail Records) database `asteriskcdrdb` might benefit from compiling the ODBC driver for aarch64, per http://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html ? +. The link:tasks/freepbx.yml#L214-L221[installation of /etc/odbc.ini] for CDR (Call Detail Records) database `asteriskcdrdb` might benefit from compiling the ODBC driver for aarch64, per https://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html ? + See the output of `asterisk -rx "cdr show status"` as mentioned at https://github.com/iiab/iiab/pull/2938#issuecomment-898693126[#2938] and https://github.com/iiab/iiab/pull/2942[PR #2942]. . Raspberry Pi Zero W Warning + -Node.js applications like Asterisk/FreePBX, Node-RED and Sugarizer won't work on Raspberry Pi Zero W (ARMv6) if you installed Node.js while on RPi 3, 3 B+ (ARMv7) or RPi 4 (ARMv8). If necessary, run `apt remove nodejs` or `apt purge nodejs` then `rm /etc/apt/sources.list.d/nodesource.list; apt update` then (https://nodered.org/docs/hardware/raspberrypi#swapping-sd-cards[attempt!]) to https://github.com/iiab/iiab/blob/master/roles/nodejs/tasks/main.yml[install Node.js] _on the Raspberry Pi Zero W itself_ (a better approach than "cd /opt/iiab/iiab; ./runrole nodejs" is to try `apt install nodejs` or try installing the tar file mentioned at https://github.com/iiab/iiab/issues/2082#issuecomment-569344617[#2082]). You might also need `apt install npm`. Whatever versions of Node.js and npm you install, make sure `/etc/iiab/iiab_state.yml` contains the line `nodejs_installed: True` (add it if nec!) Finally, proceed to install Asterisk/FreePBX, Node-RED and/or Sugarizer. https://github.com/iiab/iiab/issues/1799[#1799] +Node.js applications like Asterisk/FreePBX, Node-RED and Sugarizer won't work on Raspberry Pi Zero W (ARMv6) if you installed Node.js while on RPi 3, 3 B+ (ARMv7) or RPi 4 (ARMv8). If necessary, run `apt remove nodejs` or `apt purge nodejs` then `rm /etc/apt/sources.list.d/nodesource.list; apt update` then (https://nodered.org/docs/hardware/raspberrypi#swapping-sd-cards[attempt!]) to link:../nodejs/tasks/main.yml[install Node.js] _on the Raspberry Pi Zero W itself_ (a better approach than "cd /opt/iiab/iiab; ./runrole nodejs" is to try `apt install nodejs` or try installing the tar file mentioned at https://github.com/iiab/iiab/issues/2082#issuecomment-569344617[#2082]). You might also need `apt install npm`. Whatever versions of Node.js and npm you install, make sure `/etc/iiab/iiab_state.yml` contains the line `nodejs_installed: True` (add it if nec!) Finally, proceed to install Asterisk/FreePBX, Node-RED and/or Sugarizer. https://github.com/iiab/iiab/issues/1799[#1799] //// == Raspberry Pi Known Issues -As of 2019-02-14, "systemctl restart freepbx" failed more than 50% of the time when run on a http://wiki.laptop.org/go/IIAB/FAQ#What_services_.28IIAB_apps.29_are_suggested_during_installation.3F[LARGE-sized] install of IIAB 6.7 on RPi 3 or RPi 3 B+. +As of 2019-02-14, "systemctl restart freepbx" failed more than 50% of the time when run on a https://wiki.iiab.io/go/FAQ#What_services_.28IIAB_apps.29_are_suggested_during_installation%3F[LARGE-sized] install of IIAB 6.7 on RPi 3 or RPi 3 B+. -It is possible that FreePBX restarts much more reliably when run on a SMALL-sized install of IIAB? Please http://wiki.laptop.org/go/IIAB/FAQ#What_are_the_best_places_for_community_support.3F[contact us] if you can assist here in any way: https://github.com/iiab/iiab/issues/1493[#1493] +It is possible that FreePBX restarts much more reliably when run on a SMALL-sized install of IIAB? Please https://wiki.iiab.io/go/FAQ#What_are_the_best_places_for_community_support%3F[contact us] if you can assist here in any way: https://github.com/iiab/iiab/issues/1493[#1493] //// @@ -316,7 +350,17 @@ In February 2019, this https://github.com/iiab/iiab/tree/master/roles/pbx[roles/ In August 2021 it was overhauled, with thanks to these 3 sources especially: * "Official" recipe: https://wiki.freepbx.org/display/FOP/Installing+FreePBX+16+on+Debian+10.9 -* Comprehensive & recent recipe for Raspberry Pi: http://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html +* Comprehensive & recent recipe for Raspberry Pi: https://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html * Popular but dated recipe: https://computingforgeeks.com/how-to-install-asterisk-16-with-freepbx-15-on-ubuntu-debian/ +In May 2022, installation of FreePBX was made more resilient in https://github.com/iiab/iiab/pull/3229[PR #3229] thanks to: + +* Ron Raikes' routine to install FreePBX from GitHub: https://community.freepbx.org/t/asterisk-19-1-0-and-freepbx-install/81029/15 + +In 2024, see also the official: + +* https://sangomakb.atlassian.net/wiki/spaces/FP/pages/222101505/FreePBX+17[FreePBX 17] Installation Script (for Debian 12): https://github.com/FreePBX/sng_freepbx_debian_install +* FreePBX 17 Installation: https://sangomakb.atlassian.net/wiki/spaces/FP/pages/230326391/FreePBX+17+Installation +* Step By Step Debian 12 Installation: https://sangomakb.atlassian.net/wiki/spaces/FP/pages/295403538/Step+By+Step+Debian+12+Installation + Thank you to _ALL_ who've contributed β€” including Lemuel D'Souza, Jerry Vonau, Adam Holt and Anish Mangal! diff --git a/roles/pbx/README.rst.unused b/roles/pbx/README.rst.unused index 19371b11e..867b7e876 100644 --- a/roles/pbx/README.rst.unused +++ b/roles/pbx/README.rst.unused @@ -33,7 +33,7 @@ FreePBX is a web-based open source GUI (graphical user interface) that controls Using It -------- -Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: +Prior to installing IIAB, make sure your `/etc/iiab/local_vars.yml `_ contains:: pbx_install: True pbx_enabled: True @@ -159,9 +159,9 @@ Some useful asterisk commands and information Raspberry Pi Known Issues ------------------------- -|ss| As of 2019-02-14, "systemctl restart freepbx" failed more than 50% of the time when run on a `BIG-sized `_ install of IIAB 6.7 on RPi 3 or RPi 3 B+. +|ss| As of 2019-02-14, "systemctl restart freepbx" failed more than 50% of the time when run on a `BIG-sized `_ install of IIAB 6.7 on RPi 3 or RPi 3 B+. -It is possible that FreePBX restarts much more reliably when run on a MIN-sized install of IIAB? Please `contact us `_ if you can assist here in any way: `#1493 `_ |se| +It is possible that FreePBX restarts much more reliably when run on a MIN-sized install of IIAB? Please `contact us `_ if you can assist here in any way: `#1493 `_ |se| Raspberry Pi Zero W Warning --------------------------- diff --git a/roles/pbx/defaults/main.yml b/roles/pbx/defaults/main.yml index 3767f690e..647ad700d 100644 --- a/roles/pbx/defaults/main.yml +++ b/roles/pbx/defaults/main.yml @@ -1,13 +1,19 @@ # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# 2019: Worked on Ubuntu 18.04, Debian 9 w/ Node.js 10.x, and seemingly RPi 3+. +# +# 2022-05-25: PHP 7.4 REQUIRED -- PLEASE READ: +# https://github.com/iiab/iiab/tree/master/roles/pbx#readme # 2021-08-03: Attempts FreePBX 16 Beta -- as required w/ PHP 7.4 OS's for #2897 +# 2019: Worked on Ubuntu 18.04, Debian 9 w/ Node.js 10.x, and seemingly RPi 3+. # pbx_install: False # pbx_enabled: False -# pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +# pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also # pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +# asterisk_rpi_patch: True + # asterisk_chan_dongle: False # pbx_signaling_ports_chan_sip: 5160:5161 @@ -18,12 +24,15 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -asterisk_url: http://downloads.asterisk.org/pub/telephony/asterisk -asterisk_src_file: asterisk-19-current.tar.gz + +asterisk_url: https://downloads.asterisk.org/pub/telephony/asterisk +asterisk_src_file: asterisk-22-current.tar.gz asterisk_src_dir: "{{ iiab_base }}/asterisk" # /opt/iiab -freepbx_url: http://mirror.freepbx.org/modules/packages/freepbx/7.4 -freepbx_src_file: freepbx-16.0-latest.tgz # Beta as of 2021-06-21 but looking great! Does NOT support PHP < 7.4 (you've been warned!) Please review https://github.com/iiab/iiab/blob/master/roles/pbx/README.rst +# freepbx_url: https://mirror.freepbx.org/modules/packages/freepbx/7.4 +# freepbx_src_file: freepbx-16.0-latest.tgz # 2022-05-25 #3228: Filename has become bogus (as it's not really the latest!) Manually unpacking the latest .tar.gz for FreePBX 16.x from https://github.com/FreePBX/framework/tags to /opt/iiab/freepbx can work if absolutely nec. +freepbx_git_url: https://github.com/FreePBX/framework +freepbx_git_branch: release/17.0 # STILL IN FLUX AS OF FEB 2024: https://github.com/FreePBX/framework/tree/release/17.0 freepbx_src_dir: "{{ iiab_base }}/freepbx" freepbx_install_dir: /var/www/html/freepbx diff --git a/roles/pbx/files/Wave_sip_phone_connected.png b/roles/pbx/files/Wave_sip_phone_connected.png new file mode 100644 index 000000000..88d85b1cd Binary files /dev/null and b/roles/pbx/files/Wave_sip_phone_connected.png differ diff --git a/roles/pbx/files/install_prereq.diff b/roles/pbx/files/install_prereq.diff new file mode 100644 index 000000000..0428b339a --- /dev/null +++ b/roles/pbx/files/install_prereq.diff @@ -0,0 +1,17 @@ +--- install_prereq.orig 2023-04-01 01:41:56.859545082 -0500 ++++ install_prereq 2023-04-01 01:44:28.744269701 -0500 +@@ -193,8 +193,13 @@ + tocheck="${tocheck} ^${pack}$ ~P^${pack}$" + done + pkgs=$(aptitude -F '%c %p' search ${tocheck} 2>/dev/null | awk '/^p/{print $2}') ++ arch=$(uname -m) + if [ ${#pkgs} -ne 0 ]; then +- echo $pkgs | sed -r -e "s/ ?[^ :]+:i386//g" ++ if [ "$arch" = "x86_64" ]; then ++ echo $pkgs | sed -r -e "s/ ?[^ :]+:i386//g" ++ elif [ "$arch" = "aarch64" ]; then ++ echo $pkgs | sed -r -e "s/ ?[^ :]+:armhf//g" ++ fi + fi + } + diff --git a/roles/pbx/files/wave_sip settings.png b/roles/pbx/files/wave_sip settings.png new file mode 100644 index 000000000..f5a75e4b3 Binary files /dev/null and b/roles/pbx/files/wave_sip settings.png differ diff --git a/roles/pbx/tasks/apache.yml b/roles/pbx/tasks/apache.yml index 5462a5ca5..dd05b7dc9 100644 --- a/roles/pbx/tasks/apache.yml +++ b/roles/pbx/tasks/apache.yml @@ -39,3 +39,14 @@ dest: /etc/{{ apache_service }}/sites-available/freepbx.conf # apache2 owner: "{{ apache_user }}" # www-data group: "{{ apache_user }}" + + +- name: "Set 'apache_installed: True'" + set_fact: + apache_installed: True + +- name: "Add 'apache_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^apache_installed' + line: 'apache_installed: True' diff --git a/roles/pbx/tasks/asterisk.yml b/roles/pbx/tasks/asterisk.yml index 56ece2541..1721d69d2 100644 --- a/roles/pbx/tasks/asterisk.yml +++ b/roles/pbx/tasks/asterisk.yml @@ -1,5 +1,5 @@ -# 2021-08-16 README.adoc, with screenshots: -# https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# 2022-05-25 README.adoc, with screenshots: +# https://github.com/iiab/iiab/tree/master/roles/pbx#readme # 2021-08-05: Asterisk's own install_prereq (below) handles essentially all of these @@ -40,8 +40,6 @@ unarchive: src: "{{ downloads_dir }}/{{ asterisk_src_file }}" dest: "{{ asterisk_src_dir }}" - # owner: root - # group: root extra_opts: [--strip-components=1] creates: "{{ asterisk_src_dir }}/Makefile" @@ -55,7 +53,14 @@ # name: aptitude # state: latest -- name: Asterisk - Run 'install_prereq install' for dependencies - CAN TAKE 5 MIN OR LONGER! +# https://github.com/iiab/iiab/issues/3489 +- name: "Asterisk - Apply patch to {{ asterisk_src_dir }}/contrib/scripts/install_prereq for Raspberry Pi (#3489) if 'asterisk_rpi_patch: True'" + ansible.posix.patch: + src: install_prereq.diff + dest: "{{ asterisk_src_dir }}/contrib/scripts/install_prereq" + when: asterisk_rpi_patch + +- name: Asterisk - Run 'install_prereq install' for dependencies - CAN TAKE 2-5 MIN OR LONGER! shell: export DEBIAN_FRONTEND=noninteractive && ./contrib/scripts/install_prereq install args: chdir: "{{ asterisk_src_dir }}" @@ -78,8 +83,8 @@ creates: menuselect.makeopts - name: Asterisk - Do a bit of menuselect configuration - command: menuselect/menuselect --enable app_macro --enable format_mp3 menuselect.makeopts - # 2021-08-06: Let's standardize (ABOVE) if 6 others (BELOW) aren't needed? + command: menuselect/menuselect --enable format_mp3 menuselect.makeopts + # 2021-08-06 & 2023-11-19: Let's standardize (ABOVE) if 7 others (BELOW) aren't needed? # command: > # menuselect/menuselect --enable app_macro --enable format_mp3 # --enable CORE-SOUNDS-EN-WAV --enable CORE-SOUNDS-EN-G722 @@ -88,13 +93,13 @@ args: chdir: "{{ asterisk_src_dir }}" -- name: Asterisk - Run 'make' - CAN TAKE 8-30 MIN OR LONGER! +- name: Asterisk - Run 'make' - CAN TAKE 4-30 MIN OR LONGER! command: make args: chdir: "{{ asterisk_src_dir }}" creates: defaults.h -- name: Asterisk - Run 'make install' - CAN TAKE 2 MIN OR LONGER! +- name: Asterisk - Run 'make install' - CAN TAKE 1-2 MIN W/ SLOW DISKS? command: make install args: chdir: "{{ asterisk_src_dir }}" @@ -181,3 +186,14 @@ path: /etc/asterisk/asterisk.conf regexp: 'rungroup =' line: 'rungroup = asterisk' + + +- name: "Set 'asterisk_installed: True'" + set_fact: + asterisk_installed: True + +- name: "Add 'asterisk_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^asterisk_installed' + line: 'asterisk_installed: True' diff --git a/roles/pbx/tasks/chan_dongle.yml b/roles/pbx/tasks/chan_dongle.yml index a9fbfcf25..b7b5c5691 100644 --- a/roles/pbx/tasks/chan_dongle.yml +++ b/roles/pbx/tasks/chan_dongle.yml @@ -1,4 +1,4 @@ -# RPi: http://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html +# RPi: https://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html - name: chan_dongle - Download {{ chan_dongle_url }}/{{ chan_dongle_src_file }} to {{ downloads_dir }} get_url: diff --git a/roles/pbx/tasks/enable-or-disable.yml b/roles/pbx/tasks/enable-or-disable.yml index 2abc11405..6b1639a37 100644 --- a/roles/pbx/tasks/enable-or-disable.yml +++ b/roles/pbx/tasks/enable-or-disable.yml @@ -1,43 +1,42 @@ - name: JUST 1 SETTING TO TURN ON/OFF FOR APACHE - whereas NGINX below has 4... meta: noop -- name: EITHER - Create symlink /etc/{{ apache_service }}/sites-enabled/freepbx.conf to enable Apache's http://box:{{ pbx_http_port }}/freepbx - if pbx_use_apache and pbx_enabled # http://box:83/freepbx +- name: EITHER - Create symlink /etc/{{ apache_service }}/sites-enabled/freepbx.conf to enable Apache's http://box:{{ pbx_http_port }}/freepbx - if apache_installed is defined and pbx_use_apache and pbx_enabled # http://box:83/freepbx command: a2ensite freepbx.conf - when: pbx_use_apache and pbx_enabled + when: apache_installed is defined and pbx_use_apache and pbx_enabled -- name: OR ELSE - Delete symlink /etc/{{ apache_service }}/sites-enabled/freepbx.conf to disable Apache's http://box:{{ pbx_http_port }}/freepbx - if not (pbx_use_apache and pbx_enabled) +- name: OR ELSE - Delete symlink /etc/{{ apache_service }}/sites-enabled/freepbx.conf to disable Apache's http://box:{{ pbx_http_port }}/freepbx - if not (apache_installed is defined and pbx_use_apache and pbx_enabled) file: # As 'a2dissite freepbx.conf' might not be installed path: /etc/{{ apache_service }}/sites-enabled/freepbx.conf # apache2 state: absent - when: not (pbx_use_apache and pbx_enabled) + when: not (apache_installed is defined and pbx_use_apache and pbx_enabled) - name: "ENACT ABOVE SETTING FOR APACHE - 'pbx_use_apache: False' might arise later, so best ALWAYS run..." meta: noop -- name: EITHER - Restart & Enable '{{ apache_service }}' systemd service - if pbx_use_apache and pbx_enabled +- name: EITHER - Restart & Enable '{{ apache_service }}' systemd service - if apache_installed is defined and pbx_use_apache and pbx_enabled systemd: daemon_reload: yes name: "{{ apache_service }}" # apache2 state: restarted enabled: yes - when: pbx_use_apache and pbx_enabled - ignore_errors: yes # In case Apache not installed + when: apache_installed is defined and pbx_use_apache and pbx_enabled -- name: OR ELSE - Stop & Disable '{{ apache_service }}' systemd service - if not (pbx_use_apache and pbx_enabled) +- name: OR ELSE - Stop & Disable '{{ apache_service }}' systemd service - if not (apache_installed is defined and pbx_use_apache and pbx_enabled) systemd: daemon_reload: yes name: "{{ apache_service }}" state: stopped enabled: no - when: not (pbx_use_apache and pbx_enabled) - ignore_errors: yes # In case Apache not installed + when: not (apache_installed is defined and pbx_use_apache and pbx_enabled) + ignore_errors: yes # If Apache not installed, HIGHLIGHT IN RED FOR IMPLEMENTER/OPERATOR - name: Open-or-Close Asterix ports (including Apache port {{ pbx_http_port }}) in iptables firewall, depending on pbx_enabled [{{ pbx_enabled }}] in local_vars.yml - in support of './runrole pbx' command: /usr/bin/iiab-gen-iptables - ignore_errors: yes # iptables installed in 2-common, but iiab-gen-tables may not be set up until roles/network runs later - - + when: iiab_stage|int == 9 and network_enabled +# iptables installed in 1-prep via roles/network/tasks/install.yml, but +# iiab-gen-tables may not be set up, until/if roles/network runs later. - block: diff --git a/roles/pbx/tasks/freepbx.yml b/roles/pbx/tasks/freepbx.yml index 8e4497618..1bba7773c 100644 --- a/roles/pbx/tasks/freepbx.yml +++ b/roles/pbx/tasks/freepbx.yml @@ -1,5 +1,5 @@ -# 2021-08-16 README.adoc, with screenshots: -# https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# 2022-05-25 README.adoc, with screenshots: +# https://github.com/iiab/iiab/tree/master/roles/pbx#readme # 2021-08-04: Non-native systemd service 'asterisk.service' (redirects via @@ -11,6 +11,9 @@ # 2021-08-12: Let's try to track the "official" init.d / update-rc.d # instructions ('update-rc.d -f asterisk remove') but using systemd instead, # to be more future-proof? +# 2023-04-02: Disagreement remains the same as 2 years ago: +# @jvonau wants to stop service asterisk (from the asterisk install). +# @holta prefers we track Asterisk/FreePBX community's mainline/consensus. - name: "FreePBX - Disable 'asterisk' systemd service, giving FreePBX full control during boot - similar to officially recommended 'update-rc.d -f asterisk remove' at: https://wiki.freepbx.org/display/FOP/Installing+FreePBX+16+on+Debian+10.9" systemd: daemon_reload: yes @@ -62,51 +65,70 @@ # state: present # when: php_version is version('8.0', '<') +- name: "FreePBX - Run roles/www_options/tasks/php-settings.yml with 'nginx_high_php_limits: False' by default" + include_tasks: roles/www_options/tasks/php-settings.yml + when: php_settings_done is undefined + - name: FreePBX - Install and configure Apache - if pbx_use_apache include_tasks: apache.yml - when: pbx_use_apache + when: pbx_use_apache and apache_installed is undefined -- name: FreePBX - Download {{ freepbx_url }}/{{ freepbx_src_file }} to {{ downloads_dir }} - get_url: - url: "{{ freepbx_url }}/{{ freepbx_src_file }}" - dest: "{{ downloads_dir }}" # e.g. /opt/iiab/downloads/freepbx-16.0-latest.tgz - timeout: "{{ download_timeout }}" -- name: FreePBX - Check for {{ downloads_dir }}/{{ freepbx_src_file }} - stat: - path: "{{ downloads_dir }}/{{ freepbx_src_file }}" - register: freepbx_src +# - name: FreePBX - Download {{ freepbx_url }}/{{ freepbx_src_file }} to {{ downloads_dir }} +# get_url: +# url: "{{ freepbx_url }}/{{ freepbx_src_file }}" +# dest: "{{ downloads_dir }}" # e.g. /opt/iiab/downloads/freepbx-16.0-latest.tgz +# timeout: "{{ download_timeout }}" -- name: FreePBX - FAIL (force Ansible to exit) IF {{ downloads_dir }}/{{ freepbx_src_file }} doesn't exist - fail: - msg: "{{ downloads_dir }}/{{ freepbx_src_file }} is REQUIRED to install FreePBX." - when: not freepbx_src.stat.exists +# - name: FreePBX - Check for {{ downloads_dir }}/{{ freepbx_src_file }} +# stat: +# path: "{{ downloads_dir }}/{{ freepbx_src_file }}" +# register: freepbx_src -- name: FreePBX - Create source dir {{ freepbx_src_dir }} - file: - path: "{{ freepbx_src_dir }}" # /opt/iiab/freepbx - state: directory +# - name: FreePBX - FAIL (force Ansible to exit) IF {{ downloads_dir }}/{{ freepbx_src_file }} doesn't exist +# fail: +# msg: "{{ downloads_dir }}/{{ freepbx_src_file }} is REQUIRED to install FreePBX." +# when: not freepbx_src.stat.exists -- name: FreePBX - Extract to source dir (root:root) - unarchive: - src: "{{ downloads_dir }}/{{ freepbx_src_file }}" - dest: "{{ freepbx_src_dir }}" - owner: root - group: root - extra_opts: [--strip-components=1] - creates: "{{ freepbx_src_dir }}/install" +# - name: FreePBX - Create source dir {{ freepbx_src_dir }} +# file: +# path: "{{ freepbx_src_dir }}" # /opt/iiab/freepbx +# state: directory -- name: "FreePBX - 2021-11-06: TEMPORARILY force FreePBX 16 to work with Asterisk 19 - patch /opt/iiab/freepbx/install.php" - replace: - path: /opt/iiab/freepbx/install.php - regexp: 'version_compare\(\$astversion, "19", "ge"\)\) \{$' - replace: 'version_compare($astversion, "20", "ge")) {' +# - name: FreePBX - Extract to source dir (root:root) +# unarchive: +# src: "{{ downloads_dir }}/{{ freepbx_src_file }}" +# dest: "{{ freepbx_src_dir }}" +# owner: root +# group: root +# extra_opts: [--strip-components=1] +# creates: "{{ freepbx_src_dir }}/install" -- name: "FreePBX - 2021-11-06: TEMPORARILY force FreePBX 16 to work with Asterisk 19 - patch /opt/iiab/freepbx/installlib/installcommand.class.php" - replace: - path: /opt/iiab/freepbx/installlib/installcommand.class.php - regexp: 'version_compare\(\$matches\[1\], "19", "ge"\)\) \{$' - replace: 'version_compare($matches[1], "20", "ge")) {' +- name: FreePBX - git clone {{ freepbx_git_url }} -b {{ freepbx_git_branch }} --depth 1 {{ freepbx_src_dir }} (force) + git: + repo: "{{ freepbx_git_url }}" # https://github.com/FreePBX/framework + dest: "{{ freepbx_src_dir }}" # /opt/iiab/freepbx + version: "{{ freepbx_git_branch }}" # e.g. release/16.0 + depth: 1 + force: yes + + +# No longer needed since approx 2022-01-31 / 2022-02-14, as confirmed by: +# https://github.com/FreePBX/framework/blob/release/16.0/install.php#L27 +# https://github.com/FreePBX/framework/blob/release/16.0/installlib/installcommand.class.php#L300 +# https://community.freepbx.org/t/asterisk-19-working-with-freepbx16/80965/14 +# +# - name: "FreePBX - 2021-11-06: TEMPORARILY force FreePBX 16 to work with Asterisk 19 - patch /opt/iiab/freepbx/install.php" +# replace: +# path: /opt/iiab/freepbx/install.php +# regexp: 'version_compare\(\$astversion, "19", "ge"\)\) \{$' +# replace: 'version_compare($astversion, "20", "ge")) {' +# +# - name: "FreePBX - 2021-11-06: TEMPORARILY force FreePBX 16 to work with Asterisk 19 - patch /opt/iiab/freepbx/installlib/installcommand.class.php" +# replace: +# path: /opt/iiab/freepbx/installlib/installcommand.class.php +# regexp: 'version_compare\(\$matches\[1\], "19", "ge"\)\) \{$' +# replace: 'version_compare($matches[1], "20", "ge")) {' # 2021-08-04: FreePBX 16 no longer needs this FreePBX 15 patch # - name: FreePBX - Patch FreePBX source - IIAB Bug 1685 @@ -136,7 +158,6 @@ # login_user: root # login_password: "{{ mysql_root_password }}" host: "{{ (asterisk_db_host == 'localhost') | ternary('localhost', ansible_default_ipv4.address) }}" - state: present - name: FreePBX - Add MySQL db ({{ asterisk_db_dbname }}) mysql_db: @@ -146,7 +167,6 @@ login_host: "{{ asterisk_db_host }}" login_user: "{{ asterisk_db_user }}" login_password: "{{ asterisk_db_password }}" - state: present - name: FreePBX - Add CDR MySQL db ({{ asterisk_db_cdrdbname }}) mysql_db: @@ -156,7 +176,6 @@ login_host: "{{ asterisk_db_host }}" login_user: "{{ asterisk_db_user }}" login_password: "{{ asterisk_db_password }}" - state: present # 2021-08-16: DOES NGINX NEED THE NEXT 2 STANZAS? (If not, should 'when: pbx_use_apache' be added?) @@ -175,17 +194,17 @@ - name: "FreePBX - Populate /etc/asterisk/freepbx_chown.conf to prevent 'fwconsole chown' takeover of /var/lib/php/sessions" # And possibly later /etc/freepbx.conf, /var/log/asterisk/freepbx.log, /var/spool/asterisk/cache blockinfile: - content: | + path: /etc/asterisk/freepbx_chown.conf + block: | [blacklist] directory = /var/lib/php/sessions marker: "; {mark} ANSIBLE MANAGED BLOCK" - dest: /etc/asterisk/freepbx_chown.conf owner: asterisk group: asterisk create: yes -- name: FreePBX - git clone https://github.com/mariadb-corporation/mariadb-connector-odbc to /usr/src/mariadb-connector-odbc +- name: FreePBX - git clone https://github.com/mariadb-corporation/mariadb-connector-odbc --depth 1 /usr/src/mariadb-connector-odbc (force) git: repo: https://github.com/mariadb-corporation/mariadb-connector-odbc dest: /usr/src/mariadb-connector-odbc @@ -198,7 +217,7 @@ args: creates: /usr/local/lib/mariadb/libmaodbc.so -# http://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html +# https://mghadam.blogspot.com/2021/03/install-asterisk-18-freepbx-15-on.html - name: FreePBX - Install /etc/odbc.ini, /etc/odbcinst.ini from template (root:root, 0644 by default) template: src: "{{ item.src }}" @@ -213,15 +232,48 @@ dest: /etc/asterisk/cdr_mysql.conf -- name: FreePBX - 2-step install - won't run if {{ freepbx_install_dir }} already exists - CAN TAKE 3-12 MIN OR LONGER! - command: "{{ item }}" +# 2023-05-21: Asterisk is in fact normally OFF at this point (shouldn't matter!) +# - name: FreePBX - Spawn 'nohup ./start_asterisk start' in {{ freepbx_src_dir }} +# command: nohup ./start_asterisk start +# args: +# chdir: "{{ freepbx_src_dir }}" + +# 2023-06-21: Interim use of 'nohup' didn't quite solve ansible 2.15.x +# regression ansible/ansible#80863, which led to PR's #3588 and #3604. +- name: FreePBX - INTERIM USE OF 'systemctl start asterisk' TIL ANSIBLE FIXES 2.15.x REGRESSION ansible/ansible#80863 -- AS EVEN 'nohup ./start_asterisk start' DOESN'T WORK WITH 2.15.0 AND 2.15.1 + systemd: + name: asterisk + state: started + #enabled: yes + +# 2023-06-21: Commands to try, to see if Asterisk has started & stabilized? +# pidof asterisk +# /usr/sbin/asterisk -rx 'core show version' +# journalctl -eu asterisk + +- name: FreePBX - WAIT 5 SECONDS TO SIMULATE './start_asterisk start' (REQUIRED DUE TO ABOVE ANSIBLE BUG) THEN... install FreePBX to {{ freepbx_install_dir }} - FAST W/ GITHUB (OR freepbx-16.0-latest.tgz CAN TAKE 3-12 MIN OR LONGER!) + shell: sleep 5 && ./install -n --webroot {{ freepbx_install_dir }} --dbuser {{ asterisk_db_user }} --dbpass {{ asterisk_db_password }} args: chdir: "{{ freepbx_src_dir }}" - creates: "{{ freepbx_install_dir }}" # /var/www/html/freepbx - with_items: - - ./start_asterisk start - - ./install -n --webroot {{ freepbx_install_dir }} --dbuser {{ asterisk_db_user }} --dbpass {{ asterisk_db_password }} - # - ./install -n --webroot {{ freepbx_install_dir }} --dbuser {{ asterisk_db_user }} --dbpass {{ asterisk_db_password }} --dbname {{ asterisk_db_dbname }} --cdrdbname {{ asterisk_db_cdrdbname }} + #creates: "{{ freepbx_install_dir }}" # /var/www/html/freepbx + ignore_errors: yes # 2024-02-25: UGLY / TEMPORARY WORKAROUND #1 OF 2, to bypass "You have successfully installed FreePBX" w/ exit code 1 -- https://github.com/iiab/iiab/pull/3675#issuecomment-1890590227 + + +# 2022-05-25 BACKGROUND: https://github.com/iiab/iiab/pull/3229#issuecomment-1138061460 +- name: FreePBX - Revert the above just-installed FreePBX 'framework' module by a few weeks-or-so from GitHub's bleeding edge, to a more official version (which can help to install the ~15 modules below!) + command: fwconsole ma downloadinstall framework + +# 2024-02-25: UGLY / TEMPORARY WORKAROUND #2 OF 2, to bypass... 'In DialplanHooks.class.php line 163: Undefined array key "DialplanHooks"' -- https://github.com/iiab/iiab/pull/3675#issuecomment-1890590227 +## ERROR IF RUN BELOW: "Unable to connect to remote asterisk" +#- name: FreePBX - Run 'fwconsole reload' - as an additional precaution, per Ron Raikes @ https://community.freepbx.org/t/asterisk-19-1-0-and-freepbx-install/81029/15 +# command: fwconsole reload + +# DEFAULT MODULE LIST AUG 2021: https://github.com/iiab/iiab/pull/2916#issuecomment-894601522 +# YIELDS 2 MORE AS OF MAY 2022: https://github.com/iiab/iiab/pull/3229#issuecomment-1138566339 +# NOTHING CHANGED (?) FEB 2024: https://github.com/iiab/iiab/pull/3675#issuecomment-1963081323 +- name: FreePBX - Download + Install 15 additional FreePBX default modules (of about 70 total) as if we were installing freepbx-17.0-latest.tgz - THIS CAN TAKE SEVERAL MIN! + command: fwconsole ma downloadinstall callrecording cdr conferences core customappsreg dashboard featurecodeadmin infoservices logfiles music pm2 recordings sipsettings soundlang voicemail + - name: FreePBX - Run 'fwconsole stop', 'killall -9 safe_asterisk' to stop both main Asterisk processes - this avoids "Unable to run Pre-Asterisk hooks, because Asterisk is already running" in 'journalctl -u freepbx' logs command: "{{ item }}" @@ -259,9 +311,10 @@ src: freepbx.service dest: /etc/systemd/system/ -# Default module list https://github.com/iiab/iiab/pull/2916#issuecomment-894601522 -- name: FreePBX - Run 'fwconsole ma upgradeall' on installed FreePBX modules, e.g. 16 default modules (of about 70 total) - CAN TAKE 1 MIN OR LONGER! - command: fwconsole ma upgradeall + +# 2022-05-25: Replaced by 'fwconsole ma downloadinstall' commands above +# - name: FreePBX - Run 'fwconsole ma upgradeall' on installed FreePBX modules, e.g. 16 default modules (of about 70 total) - CAN TAKE 1 MIN OR LONGER! +# command: fwconsole ma upgradeall # - name: FreePBX - Add "$amp_conf['CHECKREFERER'] = false;" to /etc/freepbx.conf #2931 - if pbx_use_nginx" # lineinfile: diff --git a/roles/pbx/tasks/install.yml b/roles/pbx/tasks/install.yml index eb3163fe4..5c49dfa14 100644 --- a/roles/pbx/tasks/install.yml +++ b/roles/pbx/tasks/install.yml @@ -1,4 +1,4 @@ -- name: "ONLY PHP 7.4 IS SUPPORTED AS OF AUG 2021 -- PLEASE READ: https://github.com/iiab/iiab/tree/master/roles/pbx/#pbx-readme" +- name: "ONLY PHP 7.4 IS SUPPORTED AS OF MAY 2022 -- PLEASE READ: https://github.com/iiab/iiab/tree/master/roles/pbx#readme" meta: noop @@ -22,6 +22,26 @@ # when: nodejs_version != "12.x" +- name: "Set 'mysql_install: True' and 'mysql_enabled: True'" + set_fact: + mysql_install: True + mysql_enabled: True + +- name: MYSQL - run 'mysql' role (attempt to install & enable MySQL / MariaDB) + include_role: + name: mysql + +- name: FAIL (STOP THE INSTALL) IF 'mysql_installed is undefined' + fail: + msg: "PBX install cannot proceed, as MySQL / MariaDB is not installed." + when: mysql_installed is undefined + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 2021-08-09: Moved to roles/pbx/tasks/apache.yml # - name: "Set 'apache_install: True' and 'apache_enabled: True'" @@ -36,6 +56,7 @@ - name: Install Asterisk include_tasks: asterisk.yml + when: asterisk_installed is undefined - name: Install FreePBX include_tasks: freepbx.yml @@ -43,6 +64,17 @@ # RECORD PBX AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'pbx_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: pbx + option: pbx_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'pbx_installed: True'" set_fact: pbx_installed: True diff --git a/roles/pbx/tasks/main.yml b/roles/pbx/tasks/main.yml index 508691965..669f05277 100644 --- a/roles/pbx/tasks/main.yml +++ b/roles/pbx/tasks/main.yml @@ -19,29 +19,48 @@ quiet: yes -- name: Install PBX if pbx_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: pbx_installed is undefined +- block: -- name: Install & Enable chan_dongle for Huawei USB modems - if asterisk_chan_dongle - include_tasks: chan_dongle.yml - when: asterisk_chan_dongle + - name: If PHP >= 8 is detected, loudly warn that FreePBX does not support PHP 8+ (as of April 2023) + fail: # FORCE IT RED, allowing adventurous/testing people to proceed at their own risk! + msg: 'FreePBX DOES NOT SUPPORT PHP 8+ AS OF APRIL 2023. YOU ARE PROCEEDING ENTIRELY AT YOUR OWN RISK.' + when: php_version is version('8.0', '>=') + ignore_errors: yes -- include_tasks: enable-or-disable.yml + - name: Install PBX if pbx_installed is not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: pbx_installed is undefined + + - name: Install & Enable chan_dongle for Huawei USB modems - if asterisk_chan_dongle + include_tasks: chan_dongle.yml + when: asterisk_chan_dongle + + - include_tasks: enable-or-disable.yml -- name: Add 'pbx' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: pbx - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: PBX - - option: description - value: '"Full-featured PBX for rural telephony etc, that can integrate with GSM (mobile phone) networks. Based on Asterisk (Voice over IP, SIP telephone numbers) and FreePBX (web-based GUI to administer it)."' - - option: pbx_install - value: "{{ pbx_install }}" - - option: pbx_enabled - value: "{{ pbx_enabled }}" + - name: Add 'pbx' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: pbx + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: PBX + - option: description + value: '"Full-featured PBX for rural telephony etc, that can integrate with GSM (mobile phone) networks. Based on Asterisk (Voice over IP, SIP telephone numbers) and FreePBX (web-based GUI to administer it)."' + - option: pbx_install + value: "{{ pbx_install }}" + - option: pbx_enabled + value: "{{ pbx_enabled }}" + - option: pbx_use_apache + value: "{{ pbx_use_apache }}" + - option: pbx_use_nginx + value: "{{ pbx_use_nginx }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/phpmyadmin/README.md b/roles/phpmyadmin/README.md index a742f8c9d..379812957 100644 --- a/roles/phpmyadmin/README.md +++ b/roles/phpmyadmin/README.md @@ -8,7 +8,7 @@ 2. phpMyAdmin, because it is a browser-based HTML PHP application, is limited in what it can do, and what it can access β€” until the "root" user creates users and access privileges, as mentioned above. (HTML servers always run with very low privileges) #### Installing phpMyAdmin -1. First, a user will need to set `phpmyadmin_install: True` and `phpmyadmin_enabled: True` in [/etc/iiab/local_vars.yml](http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F) +1. First, a user will need to set `phpmyadmin_install: True` and `phpmyadmin_enabled: True` in [/etc/iiab/local_vars.yml](http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F) 2. Then install IIAB. Or if IIAB is already installed, run: ``` cd /opt/iiab/iiab diff --git a/roles/phpmyadmin/defaults/main.yml b/roles/phpmyadmin/defaults/main.yml index f9977c71e..b898ae5bd 100644 --- a/roles/phpmyadmin/defaults/main.yml +++ b/roles/phpmyadmin/defaults/main.yml @@ -4,7 +4,7 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -phpmyadmin_version: 5.1.1 +phpmyadmin_version: 5.2.1 phpmyadmin_name: "phpMyAdmin-{{ phpmyadmin_version }}-all-languages" phpmyadmin_dl_url: "https://files.phpmyadmin.net/phpMyAdmin/{{ phpmyadmin_version }}/{{ phpmyadmin_name }}.tar.xz" phpmyadmin_name_zip: "{{ phpmyadmin_version }}/{{ phpmyadmin_name }}.tar.xz" diff --git a/roles/phpmyadmin/tasks/install.yml b/roles/phpmyadmin/tasks/install.yml index eaec8af82..7d510de69 100644 --- a/roles/phpmyadmin/tasks/install.yml +++ b/roles/phpmyadmin/tasks/install.yml @@ -1,9 +1,13 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Download {{ phpmyadmin_dl_url }} to {{ downloads_dir }} get_url: url: "{{ phpmyadmin_dl_url }}" # e.g. https://files.phpmyadmin.net/phpMyAdmin/5.0.4/phpMyAdmin-5.0.4-all-languages.zip dest: "{{ downloads_dir }}" # /opt/iiab/downloads timeout: "{{ download_timeout }}" - when: internet_available - name: Does {{ downloads_dir }}/{{ phpmyadmin_name_zip }} exist? stat: @@ -46,8 +50,20 @@ # # recurse: yes # # state: directory + # RECORD phpMyAdmin AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'phpmyadmin_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: phpmyadmin + option: phpmyadmin_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'phpmyadmin_installed: True'" set_fact: phpmyadmin_installed: True diff --git a/roles/phpmyadmin/tasks/main.yml b/roles/phpmyadmin/tasks/main.yml index 55339f268..b4f04646d 100644 --- a/roles/phpmyadmin/tasks/main.yml +++ b/roles/phpmyadmin/tasks/main.yml @@ -19,29 +19,36 @@ quiet: yes -- name: "INCOMPLETE WITHOUT APACHE AS OF 2021-07-06: Install phpMyAdmin if 'phpmyadmin_installed' not defined, e.g. in {{ iiab_state_file }}" # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: phpmyadmin_installed is undefined +- block: + - name: "INCOMPLETE WITHOUT APACHE AS OF 2021-07-06: Install phpMyAdmin if 'phpmyadmin_installed' not defined, e.g. in {{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: phpmyadmin_installed is undefined -- name: INCOMPLETE WITHOUT APACHE AS OF 2021-07-06 - include_tasks: enable-or-disable.yml + - name: INCOMPLETE WITHOUT APACHE AS OF 2021-07-06 + include_tasks: enable-or-disable.yml + - name: Add 'phpmyadmin' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: phpmyadmin + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: phpMyAdmin + - option: description + value: '"phpMyAdmin is an interface with a MySQL database written in PHP, and available to administer the database engine locally or across the network."' + - option: phpmyadmin_install + value: "{{ phpmyadmin_install }}" + - option: phpmyadmin_enabled + value: "{{ phpmyadmin_enabled }}" + - option: path + value: /opt/phpmyadmin -- name: Add 'phpmyadmin' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: phpmyadmin - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: phpMyAdmin - - option: description - value: '"phpMyAdmin is an interface with a MySQL database written in PHP, and available to administer the database engine locally or across the network."' - - option: phpmyadmin_install - value: "{{ phpmyadmin_install }}" - - option: phpmyadmin_enabled - value: "{{ phpmyadmin_enabled }}" - - option: path - value: /opt/phpmyadmin + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/postgresql/tasks/enable-or-disable.yml b/roles/postgresql/tasks/enable-or-disable.yml new file mode 100644 index 000000000..e9deb96d9 --- /dev/null +++ b/roles/postgresql/tasks/enable-or-disable.yml @@ -0,0 +1,14 @@ +- name: Enable & Start 'postgresql-iiab' systemd service, if postgresql_enabled + systemd: + name: postgresql-iiab + daemon_reload: yes + enabled: yes + state: started + when: postgresql_enabled + +- name: Disable & Stop 'postgresql-iiab' systemd service, if not postgresql_enabled + systemd: + name: postgresql-iiab + enabled: no + state: stopped + when: not postgresql_enabled diff --git a/roles/postgresql/tasks/install.yml b/roles/postgresql/tasks/install.yml index 3fa1a95d0..ce14600c5 100644 --- a/roles/postgresql/tasks/install.yml +++ b/roles/postgresql/tasks/install.yml @@ -1,18 +1,34 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: 'Install packages: postgresql, postgresql-client' package: name: - postgresql - postgresql-client - - python3-psycopg2 # For Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml + #- python3-psycopg2 # For Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml state: present +- name: pip install 'psycopg' (NEW Psycopg 3) into venv /usr/local/ansible -- for Ansible modules {postgresql_db, postgresql_user} in Ansible collection community.postgresql -- used in moodle/tasks/install.yml + pip: + name: psycopg + virtualenv: /usr/local/ansible + extra_args: "--upgrade --no-cache-dir --prefer-binary" # 2023-10-01: Lifesaver when recent wheels (e.g. piwheels.org) are inevitably not yet built! SEE #3560 + +- name: Run shell command "pg_config --version" to extract MAJOR version number -- strip off MINOR/PATCH version number(s) + shell: pg_config --version | sed 's/^[^0-9]*//; s/[^0-9].*//' + register: pg_config_version + +- name: 'Dynamically set Ansible var "postgresql_version: {{ pg_config_version.stdout }}"' + set_fact: + postgresql_version: "{{ pg_config_version.stdout }}" + - name: Install /etc/systemd/system/postgresql-iiab.service from template (0644 by default) template: src: postgresql-iiab.service dest: /etc/systemd/system/postgresql-iiab.service - # owner: root - # group: root - # mode: '0644' - name: Create PostgreSQL data dir /library/pgsql-iiab, owned by postgres:postgres (0700) file: @@ -85,6 +101,17 @@ # RECORD PostgreSQL AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'postgresql_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: postgresql + option: postgresql_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'postgresql_installed: True'" set_fact: postgresql_installed: True diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml index 2043e2427..8d7070ea8 100644 --- a/roles/postgresql/tasks/main.yml +++ b/roles/postgresql/tasks/main.yml @@ -26,39 +26,33 @@ var: postgresql_installed -- name: Install PostgreSQL if 'postgresql_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: postgresql_installed is undefined +- block: + - name: Install PostgreSQL if 'postgresql_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: postgresql_installed is undefined -- name: Enable & Start 'postgresql-iiab' systemd service, if postgresql_enabled - systemd: - name: postgresql-iiab - daemon_reload: yes - enabled: yes - state: started - when: postgresql_enabled + - include_tasks: enable-or-disable.yml -- name: Disable & Stop 'postgresql-iiab' systemd service, if not postgresql_enabled - systemd: - name: postgresql-iiab - enabled: no - state: stopped - when: not postgresql_enabled + - name: Add 'postgresql' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: postgresql + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: PostgreSQL + - option: description + value: '"PostgreSQL is a powerful, open source object-relational database system."' + - option: postgresql_install + value: "{{ postgresql_install }}" + - option: postgresql_enabled + value: "{{ postgresql_enabled }}" + rescue: -- name: Add 'postgresql' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab_state.yml - section: postgresql - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: PostgreSQL - - option: description - value: '"PostgreSQL is a powerful, open source object-relational database system."' - - option: postgresql_install - value: "{{ postgresql_install }}" - - option: postgresql_enabled - value: "{{ postgresql_enabled }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/pylibs/tasks/main.yml b/roles/pylibs/tasks/main.yml index f7ffa0f1d..9283c44f3 100644 --- a/roles/pylibs/tasks/main.yml +++ b/roles/pylibs/tasks/main.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Install iiab lib files template: src: "{{ item.src }}" @@ -13,6 +18,17 @@ # RECORD pylibs AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'pylibs_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: pylibs + option: pylibs_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'pylibs_installed: True'" set_fact: pylibs_installed: True diff --git a/roles/pylibs/templates/iiab_lib.py b/roles/pylibs/templates/iiab_lib.py index 84dee97e3..13044c0c2 100644 --- a/roles/pylibs/templates/iiab_lib.py +++ b/roles/pylibs/templates/iiab_lib.py @@ -6,6 +6,7 @@ import os import json import subprocess import shlex +import re import xml.etree.ElementTree as ET import iiab.iiab_const as CONST @@ -46,11 +47,17 @@ def get_zim_list(path): if filename in CONST.old_zim_map: # handle old names that don't parse perma_ref = CONST.old_zim_map[filename] else: - ulpos = filename.rfind("_") - # but old gutenberg and some other names are not canonical - if filename.rfind("-") < 0: # non-canonical name - ulpos = filename[:ulpos].rfind("_") - perma_ref = filename[:ulpos] + # handle various zim name patterns: + # 1. canonical zim ending in _YYYY-MM + # as of 10/16/2024 it looks like all Kiwix zims fit this pattern + # 2. otherwise assume no versioning and perma_ref = filename + + match = re.search("_[0-5][0-9][0-5][0-9]-[0-5][0-9]$", filename) + if match: + perma_ref = filename[: match.span()[0]] + else: + perma_ref = filename + zim_info['file_name'] = filename zim_versions[perma_ref] = zim_info # if there are multiples, last should win return files_processed, zim_versions @@ -85,8 +92,9 @@ def read_library_xml(lib_xml_file, kiwix_exclude_attr=["favicon"]): # duplicated attributes[attr] = child.attrib[attr] # copy if not id or in exclusion list zims_installed[zim_id] = attributes path_to_id_map[child.attrib['path']] = zim_id - except IOError: + except: # though I try how can I carry on zims_installed = {} + path_to_id_map = {} return zims_installed, path_to_id_map def rem_libr_xml(zim_id, kiwix_library_xml): diff --git a/roles/remoteit/README.md b/roles/remoteit/README.md index b7ea389d6..910f55409 100644 --- a/roles/remoteit/README.md +++ b/roles/remoteit/README.md @@ -1,29 +1,73 @@ # Remote support of an Internet-in-a-Box using https://remote.it -Remote.it can be a great way to remotely support an Internet-in-a-Box (IIAB). +Remote.it can be a [great way](https://docs.remote.it/introduction/get-started/readme) to remotely support an Internet-in-a-Box (IIAB). -For other approaches, please see http://FAQ.IIAB.IO -> "How can I remotely manage my Internet-in-a-Box?" +As of [2024](https://remote.it/pricing/), 5 IIAB devices can be managed for free (their personal / non-commercial plan) and larger numbers for $10+/month. + +For other approaches, please see [FAQ.IIAB.IO](https://wiki.iiab.io/go/FAQ) -> "How can I remotely manage my Internet-in-a-Box?" ## Getting Started -### Create a remote.it account +### Create a remote.it account + consider its desktop application -1. Go to the [https://remote.it](https://remote.it) website and sign up for an account. -2. OPTIONAL: Download [remote.it's desktop application](https://remote.it/download/) e.g. for Windows, macOS or Linux. +1. Browse to [https://remote.it](https://remote.it) (Web Portal) and sign up for an account. -### Install remote.it onto an IIAB +2. Consider downloading and installing the remote.it [desktop application](https://remote.it/download/) (e.g. for Windows, macOS or Linux) on your own laptop/computer. Their https://remote.it Web Portal and [mobile apps](https://docs.remote.it/introduction/get-started/readme#installation-packages) are also sometimes sufficient, but less functional. -1. Set `remoteit_install` and `remoteit_enabled` to `True` in your IIAB's [/etc/iiab/local_vars.yml](http://wiki.laptop.org/go/IIAB/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it.3F) + 2023-07-26 WARNING: IIAB no longer installs the `/usr/bin/remoteit` [command-line interface (CLI)](https://docs.remote.it/software/cli), as it can [no longer coexist](https://github.com/iiab/iiab/blob/9d27ff04184fc971b0a8737ba0d14b69d433a5ad/roles/remoteit/tasks/install.yml#L116-L132) with the core `remoteit` Device Package. Whereas in the past the remote.it CLI had offered [a few more features](https://support.remote.it/hc/en-us/articles/4412786750861-Install-the-remoteit-agent-on-your-device): "The Desktop and [CLI](https://docs.remote.it/software/cli) can [each] support both peer to peer connections and proxy connections [whereas] the Web Portal and API can only support proxy connections" according to https://docs.remote.it/software/device-package/usage -2. Install and enable it (remote.it) on your IIAB, by running: + +### OPTION #1: Generate a remote.it claim code for your IIAB + register it + authorize services/ports + + +Prerequisite: Find any IIAB with `remoteit_installed: True` in `/etc/iiab/iiab_state.yml` (this is the default!) This means that the remote.it [Device Package](https://docs.remote.it/software/device-package) is already installed on your IIAB, most important. + +1. Run `sudo iiab-remoteit` to enable remote.it on your IIAB: + + - Hit [Enter] (repeatedly if necessary, to accept all defaults) to quickly generate a claim code for your IIAB. + + The claim code must be used [within 24 hours](https://docs.remote.it/device-package/installation#2.-update-your-package-manager-and-install) (Step 2., below). + + Just FYI a copy is also put in: `/etc/remoteit/config.json` + + - EXCEPTION #1: If a remote.it license key happens to be found in `/etc/iiab/local_vars.yml` or `/etc/remoteit/registration`, that will be tried first (prior to, and instead of generating a claim code). + + *If the license key works, you will not get a claim code (as the IIAB device auto-registers to your remote.it account) so jump to Step 5. in OPTION #2.* + + - EXCEPTION #2: If you have an existing `/etc/remoteit/config.json` you will be given the option to try that (e.g. if you already registered the IIAB device to your remote.it account). + + *Verify that after `sudo iiab-remoteit` completes, by jumping to Step 5. in OPTION #2.* + + + + -3. To obtain this IIAB's 8-character remote.it claim code, allowing you to make a remote connection to this IIAB, run: + Or if necessary reinstall the latest, by running: + + ``` + cd /opt/iiab/iiab + sudo ./runrole --reinstall remoteit + ``` --> + + + + + +2. Submit the claim code within the remote.it [desktop application](https://remote.it/download/) on your own laptop/computer. Or if you prefer, do that by logging into their Web Portal at: https://remote.it + + Either way, click on the '+' icon to enter the remote.it claim code (to register the IIAB device to your remote.it account) as shown in this [screenshot](https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device). + +3. Authorize services/ports (e.g. SSH, HTTP, etc) for your IIAB device, as shown in these [screenshots](https://docs.remote.it/software/device-package/installation#4.-set-up-services-on-your-device), and you're all done! + + SUMMARY: One or more [remote.it "Services"](https://support.remote.it/hc/en-us/articles/360060992631-Services) need to be authorized (registered) to allow remote access to your IIAB device. + + EXAMPLES: Add an SSH Service on port 22 and/or add an HTTP Service on port 80 ([screenshot guide](https://support.remote.it/hc/en-us/articles/360058603991-Configuring-remoteit-Services-on-devices-with-remote-it-Desktop)). + +### OPTION #2: Paste your remote.it license key to IIAB + enable it + authorize services/ports + +1. Copy your remote.it account _license key_ from their Desktop Application (https://remote.it/download/) or from their Web Portal (https://remote.it) — as shown in this [screenshot](https://docs.remote.it/oem-and-bulk-provisioning/registration-into-a-users-account#3.-user-receives-the-device-and-registers-his-account). + + Paste it into your IIAB's [/etc/iiab/local_vars.yml](https://wiki.iiab.io/go/FAQ#What_is_local_vars.yml_and_how_do_I_customize_it%3F) as in this example: + + ``` + remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 ``` -4. After you've installed the https://remote.it client software onto a separate computer or device (e.g. your own laptop) click on the '+' icon, then enter the remote.it claim code (for the IIAB that you need to connect to). + _FYI to protect your credential, the above line will promptly be redacted (removed) from your /etc/iiab/local_vars.yml β€” after the key is copied to_ `/etc/remoteit/registration` _in Step 3. or 4. below._ - As shown in the screenshot here: https://docs.remote.it/device-package/installation#3.-claim-and-register-the-device +2. Also set `remoteit_enabled: True` in /etc/iiab/local_vars.yml -### Usage Summary + (And verify that `remoteit_install: True` is set.) -1. Log into the https://remote.it Web Portal, or open its desktop application. -2. Add Devices (e.g. your IIAB). -3. Understand that each Device will need to contain one or more remote.it Services. - - Add a remote.it Service (e.g. HTTP and/or others) to your Device:
https://support.remote.it/hc/en-us/articles/360050732092-Add-a-remote-it-Service-to-your-Device +3. If your [IIAB software](https://download.iiab.io/) is _not yet installed,_ do that e.g. by running `sudo iiab` and following any on-screen instructions — until "INTERNET-IN-A-BOX (IIAB) SOFTWARE INSTALL IS COMPLETE" eventually appears on screen. -Summary of remote.it Services: https://support.remote.it/hc/en-us/articles/360060992631-Services + When that's complete, skip to Step 5. -For more info, please see remote.it's [Getting Started pages](https://support.remote.it/hc/en-us/categories/360003417511-Getting-Started). +4. If your IIAB software is _already installed,_ make sure your IIAB is online. -## Advanced + Now register the IIAB device to your remote.it account, by running `sudo iiab-remoteit` (this also enables remote.it on your IIAB). -For "auto-registration" of remote.it, and other more advanced configuration options, please review: + Or, if you prefer the legacy approach, run: + + ``` + cd /opt/iiab/iiab + sudo ./runrole remoteit + ``` + + The legacy approach can also reinstall the (latest) remote.it Device Package on your IIAB, if you instead run: + + ``` + cd /opt/iiab/iiab + sudo ./runrole --reinstall remoteit + ``` + +5. Log in to https://remote.it or its [desktop application](https://remote.it/download/) on your own computer/laptop. + + In the ["Devices" section on the left](https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device), check that your IIAB is now present (i.e. registered to your account). + +6. Authorize services/ports (e.g. SSH, HTTP, etc) for your IIAB device, as shown in these [screenshots](https://docs.remote.it/software/device-package/installation#4.-set-up-services-on-your-device), and you're all done! + + SUMMARY: One or more [remote.it "Services"](https://support.remote.it/hc/en-us/articles/360060992631-Services) need to be authorized (registered) to allow remote access to your IIAB device. + + EXAMPLES: Add an SSH Service on port 22 and/or add an HTTP Service on port 80 ([screenshot guide](https://support.remote.it/hc/en-us/articles/360058603991-Configuring-remoteit-Services-on-devices-with-remote-it-Desktop)). + +### How to I disable remote.it on my IIAB? + +1. Run `sudo iiab-remoteit-off` + +2. If you also want to completely remove all remote.it software and its settings, run: + + ``` + sudo apt purge "remoteit*" + sudo rm /usr/bin/remoteit + ``` + +## Docs + + - https://docs.remote.it + - ~https://docs.remote.it/developer-tools/cli-usage~ + - https://docs.remote.it/oem-and-bulk-provisioning/registration-into-a-users-account - https://support.remote.it -- https://support.remote.it/hc/en-us/articles/360044424612-1-Create-an-Auto-Registration -- https://support.remote.it/hc/en-us/articles/360044424672-1-Device-Setup-for-Auto-Bulk-Registration + - https://support.remote.it/hc/en-us/categories/360003417511-Getting-Started + - https://support.remote.it/hc/en-us/articles/360061228252-Oops-I-cloned-an-SD-card- + - https://support.remote.it/hc/en-us/articles/4404156674445-Subscriptions-and-Licensing + - https://support.remote.it/hc/en-us/articles/360041590951-Why-does-the-address-time-out- + - https://support.remote.it/hc/en-us/articles/360047705691-Desktop-Application-Release-Notes + - https://support.remote.it/hc/en-us/articles/4492289672973-Two-ways-of-using-remote-it-Connections + - https://support.remote.it/hc/en-us/articles/4422773654669-Streamlined-installation-for-Linux-and-Raspberry-Pi-platforms + - https://support.remote.it/hc/en-us/articles/360051668711-Updating-the-remoteit-or-connectd-packages-using-a-remote-it-SSH-connection + +- https://remote.it/resources/ + - https://remote.it/resources/blog/managing-device-access-with-remote-it/ +- https://remote.it/legal/ + - https://remote.it/legal/fair-use-policy/ ## Known Issues -- 2021-10-27: This needs to be enhanced rather urgently, so remote.it also works when IIAB is installed on Raspberry Pi OS 11 (Bullseye), Ubuntu, Mint and Debian: [#3006](https://github.com/iiab/iiab/issues/3006) -- 2021-10-29: The above OS issues should be resolved by [PR #3007](https://github.com/iiab/iiab/pull/3007), [PR #3009](https://github.com/iiab/iiab/pull/3009) and [PR #3010](https://github.com/iiab/iiab/pull/3010) — but this needs final testing! (Initial testing occurred on [1] 32-bit Raspberry Pi OS Lite on Raspberry Pi 4 and [2] Ubuntu Server 20.04 on x86_64 VM.) +- 2021-10-27: This needs to be enhanced rather urgently, so remote.it also works when IIAB is installed on Raspberry Pi OS 11 (Bullseye), Ubuntu, Mint and Debian: [#3006](https://github.com/iiab/iiab/issues/3006) +- 2021-10-29: The above OS issues should be resolved by [PR #3007](https://github.com/iiab/iiab/pull/3007), [PR #3009](https://github.com/iiab/iiab/pull/3009) and [PR #3010](https://github.com/iiab/iiab/pull/3010) — but this needs final testing! (Initial testing occurred on [1] 32-bit Raspberry Pi OS Lite on Raspberry Pi 4 and [2] Ubuntu Server 20.04 on x86_64 VM.) diff --git a/roles/remoteit/defaults/main.yml b/roles/remoteit/defaults/main.yml index 09e3a9de9..0011567bd 100644 --- a/roles/remoteit/defaults/main.yml +++ b/roles/remoteit/defaults/main.yml @@ -6,31 +6,64 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -remoteit_version: 4.13.6 -# See https://docs.remote.it/device-package/installation to refine URL below: -device_suffixes: - armv6: armhf.rpi - armv6l: armhf.rpi - armv7: armhf.rpi - armv7l: armhf.rpi - armv8: arm64.rpi - aarch64: arm64 - x86_64: amd64 -remoteit_device_suffix: "{{ device_suffixes[ansible_architecture] | default('unknown') }}" -remoteit_deb: remoteit-{{ remoteit_version }}.{{ remoteit_device_suffix }}.deb -remoteit_device_url: https://downloads.remote.it/remoteit/v{{ remoteit_version }}/{{ remoteit_deb }} -# Example... https://downloads.remote.it/remoteit/v4.13.5/remoteit-4.13.5.armhf.rpi.deb +# # 2022-03-31: https://remote.it/download/ offered 4 relevant "Device Packages" +# # 1) Raspberry Pi (ARM) = armhf.rpi +# # 2) Raspberry Pi (ARM64) = arm64.rpi +# # 3) Debian Linux (ARM64) = arm64 +# # 4) Debian Linux (x86_64) = amd64 -# See https://docs.remote.it/cli/overview to refine URL below: -cli_suffixes: - armv6: armv6 - armv6l: armv6 - armv7: armv7 - armv7l: armv7 - armv8: arm64 - aarch64: arm64 - x86_64: amd64 -remoteit_cli_suffix: "{{ cli_suffixes[ansible_architecture] | default('unknown') }}" -remoteit_cli_url: https://downloads.remote.it/cli/latest/remoteit_linux_{{ remoteit_cli_suffix }} -# Example... https://downloads.remote.it/cli/latest/remoteit_linux_armv7 +# # See https://docs.remote.it/software/device-package/installation to refine URL below: +# device_suffixes: +# armv6: armhf.rpi +# armv6l: armhf.rpi +# armv7: armhf.rpi +# armv7l: armhf.rpi +# armv8: arm64.rpi +# aarch64: arm64 +# x86_64: amd64 +# remoteit_device_suffix: "{{ device_suffixes[ansible_architecture] | default('unknown') }}" +# remoteit_device_url: https://downloads.remote.it/remoteit/latest/remoteit.{{ remoteit_device_suffix }}.deb + +# # 2022-03-31: Use "latest" above, instead of ever-changing version below +# # remoteit_version: 4.14.1 +# # remoteit_deb: remoteit-{{ remoteit_version }}.{{ remoteit_device_suffix }}.deb +# # remoteit_device_url: https://downloads.remote.it/remoteit/v{{ remoteit_version }}/{{ remoteit_deb }} +# # # Example... https://downloads.remote.it/remoteit/v4.14.1/remoteit-4.14.1.armhf.rpi.deb + + +# 2022-10-09: https://remote.it/download/ offers 4 relevant "CLI" installs: +# 1) Debian Linux (ARM v6) OR Raspberry Pi (ARM) = armv6 -> arm-v6 +# 2) Debian Linux (ARM v7) = armv7 -> arm-v7 +# 3) Debian Linux (ARM64) OR Raspberry Pi (ARM64) = arm64 -> aarch64 +# 4) Debian Linux (x86_64) = x86_64 + +# SEE https://www.remote.it/download-list +# https://www.remote.it/download-list?products=cli to refine arch/URL below +# BUT https://docs.remote.it/software/cli/overview can be useful OR stale :/ +# +# 2023-07-26: Remote.It CLI can no longer coexist with their "Device Package" +# SEE remoteit/tasks/install.yml Line ~121. +# remoteit_arch_dict: +# armv6: arm-v6 +# armv6l: arm-v6 +# armv7: arm-v7 +# armv7l: arm-v7 +# armv8: aarch64 +# aarch64: aarch64 +# x86_64: x86_64 +# remoteit_arch: "{{ remoteit_arch_dict[ansible_machine] | default('unknown') }}" # A bit safer than ansible_architecture (see kiwix/defaults/main.yml) +# remoteit_cli_url: https://downloads.remote.it/cli/latest/remoteit.{{ remoteit_arch }}-linux + + +# OPTION #1: Run 'sudo iiab-remoteit' after IIAB is installed. + +# OPTION #2: Pre-populate your remote.it account "license key" (a.k.a. +# R3_REGISTRATION_CODE) in /etc/iiab/local_vars.yml -- e.g. prior to installing +# IIAB -- by using a line like: +# +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 +# +# BACKGROUND: You can obtain a license key at https://remote.it or by using +# their Desktop Application (https://remote.it/download/) as shown here: +# https://docs.remote.it/oem-and-bulk-provisioning/registration-into-a-users-account#3.-user-receives-the-device-and-registers-his-account diff --git a/roles/remoteit/tasks/enable-or-disable.yml b/roles/remoteit/tasks/enable-or-disable.yml index 2e1ddb36f..0023e0b17 100644 --- a/roles/remoteit/tasks/enable-or-disable.yml +++ b/roles/remoteit/tasks/enable-or-disable.yml @@ -1,28 +1,83 @@ -- name: Enable & (Re)Start remote.it's connectd daemon which calls home - systemd: - name: connectd - daemon_reload: yes - enabled: yes - state: restarted +# Passwords and license keys in /etc/iiab/local_vars.yml are not a healthy +# precedent :/ (Going forward let's try to keep credentials in their own apps) + +- name: Copy OPTIONAL remoteit_license_key, e.g. from /etc/iiab/local_vars.yml to /etc/remoteit/registration, if remoteit_license_key is defined + # shell: echo {{ remoteit_license_key }} > /etc/remoteit/registration + template: + src: registration.j2 + dest: /etc/remoteit/registration + when: remoteit_license_key is defined + +- name: Redact OPTIONAL remoteit_license_key from /etc/iiab/local_vars.yml, if remoteit_license_key is defined + # shell: sed -i '/^remoteit_license_key:/d' {{ iiab_local_vars_file }} + lineinfile: + path: "{{ iiab_local_vars_file }}" + regexp: '^remoteit_license_key:.*' + state: absent + when: remoteit_license_key is defined + + +- name: Does empty file /etc/remoteit/registration exist? + stat: + path: /etc/remoteit/registration + register: remoteit_reg + +- name: Remove empty file /etc/remoteit/registration if remoteit_enabled, so claim code can be generated + file: + path: /etc/remoteit/registration + state: absent + when: remoteit_enabled and remoteit_reg.stat.exists and remoteit_reg.stat.size == 0 + + +# 2022-10-09: refresh.sh is equivalent to their old connectd "parent" systemd +# service, that they removed from 4.15.2 device packages on 2022-09-07. +# (Either way, the job below never deletes /etc/remoteit/registration) + +- name: 'Run /usr/share/remoteit/refresh.sh to put a claim code in /etc/remoteit/config.json (if you don''t already have a license key in /etc/remoteit/registration) -- FYI this should spawn 2 "child" services/daemons: schannel & e.g. remoteit@80:00:01:7F:7E:00:56:36.service' + command: /usr/share/remoteit/refresh.sh when: remoteit_enabled +# - name: Enable & Restart remote.it "parent" service connectd, which exits after spawning 2 "child" services/daemons below +# systemd: +# name: connectd +# daemon_reload: yes +# enabled: yes +# state: restarted +# when: remoteit_enabled -- name: Disable & Stop remote.it's connectd daemon +# 2022-10-09: refresh.sh (above) now takes care of this too +# - name: Enable remote.it daemon schannel ("Remote tcp command service") -- try to avoid contention with connectd which auto-spawns it as nec (just above) +# systemd: +# name: schannel +# enabled: yes +# state: started +# when: remoteit_enabled + + +- name: Disable & Stop remote.it service schannel systemd: - name: connectd + name: schannel enabled: no state: stopped + ignore_errors: yes # 2023-06-12: Let's make these rare-but-unavoidable errors RED very intentionally, as below. Thanks to @neomatrixcode for surfacing this GitHub Actions problem, likely arising from inbound ICMP being blocked during remote.it install and/or above refresh.sh setup: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#cloud-hosts-used-by-github-hosted-runners when: not remoteit_enabled -- name: Identify remoteit service (connector) unit file name, including uuid - shell: ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit # e.g. remoteit@80:00:01:7F:7E:00:56:36.service - register: remoteit_service +- name: Stop & Disable "Remote tcp connection services" remoteit@* found in /etc/systemd/system/multi-user.target.wants/ e.g. remoteit@80:00:01:7F:7E:00:56:36.service + shell: | + systemctl stop $(ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@*) + systemctl disable $(ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@*) ignore_errors: yes + when: not remoteit_enabled -- name: "Disable & Stop remoteit service: {{ remoteit_service.stdout }}" - systemd: - name: "{{ remoteit_service.stdout }}" - enabled: no - state: stopped - when: not remoteit_enabled and remoteit_service.stdout != "" - ignore_errors: yes +# - name: Identify remoteit "Remote tcp connection service" unit file name, including uuid, e.g. remoteit@80:00:01:7F:7E:00:56:36.service +# shell: ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@ +# register: remoteit_service +# ignore_errors: yes + +# - name: "Disable & Stop the actual service: {{ remoteit_service.stdout }}" +# systemd: +# name: "{{ remoteit_service.stdout }}" +# enabled: no +# state: stopped +# when: not remoteit_enabled and remoteit_service.stdout != "" +# ignore_errors: yes diff --git a/roles/remoteit/tasks/install.yml b/roles/remoteit/tasks/install.yml index b0156663f..8d8874f2e 100644 --- a/roles/remoteit/tasks/install.yml +++ b/roles/remoteit/tasks/install.yml @@ -1,47 +1,149 @@ -- name: Fail if architecture remoteit_device_suffix == "unknown" - fail: - msg: "Could not find a remote.it device apt package for CPU architecture \"{{ ansible_architecture }}\"" - when: remoteit_device_suffix == "unknown" +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 -- name: mkdir {{ downloads_dir }} # As roles/2-common/tasks/fl.yml has not run yet - file: - path: "{{ downloads_dir }}" # /opt/iiab/downloads - state: directory -- name: Download {{ remoteit_device_url }} (device) for arch {{ remoteit_device_suffix }} into {{ downloads_dir }}/ - get_url: - url: "{{ remoteit_device_url }}" - dest: "{{ downloads_dir }}/" - force: yes - timeout: "{{ download_timeout }}" +# - name: Fail if architecture remoteit_device_suffix == "unknown" +# fail: +# msg: "Could not find a remote.it Device Package (.deb) for CPU architecture \"{{ ansible_architecture }}\"" +# when: remoteit_device_suffix == "unknown" -- name: Uninstall previously installed 'remoteit*' device apt package(s) +# - name: mkdir {{ downloads_dir }} # As roles/2-common/tasks/fl.yml has not run yet +# file: +# path: "{{ downloads_dir }}" # /opt/iiab/downloads +# state: directory + +# - name: Download {{ remoteit_device_url }} (Device Package) for arch {{ remoteit_device_suffix }} into {{ downloads_dir }}/ +# get_url: +# url: "{{ remoteit_device_url }}" +# dest: "{{ downloads_dir }}/" +# force: yes +# timeout: "{{ download_timeout }}" + +# 2022-04-03: Unfort still necessary, as their install_agent.sh below uses apt +# with 'install -y' instead of '-y reinstall' or '-y --reinstall install' +# FWIW: Some remoteit.*.deb installers also work with '-y --allow-downgrades install' +# (e.g. *.amd64.deb) but others (e.g. both *.rpi.deb) do not. +- name: Purge previously installed 'remoteit*' Device Package(s) apt: name: remoteit* state: absent + purge: yes ignore_errors: yes -- name: Install device apt package {{ downloads_dir }}/{{ remoteit_deb }} - apt: - deb: "{{ downloads_dir }}/{{ remoteit_deb }}" - state: present + +# Speeds things up a bit, deferring online claim code generation if not nec: +# https://docs.remote.it/oem-and-bulk-provisioning/registration-into-a-users-account + +# - name: "'mkdir /etc/remoteit' e.g. if your 'remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6' exists in /etc/iiab/local_vars.yml" +# file: +# state: directory +# path: /etc/remoteit +# when: remoteit_license_key is defined + +# - name: "'touch /etc/remoteit/registration' e.g. if your 'remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6' exists in /etc/iiab/local_vars.yml" +# file: +# state: touch +# path: /etc/remoteit/registration +# when: remoteit_license_key is defined + +- name: "'mkdir /etc/remoteit'" + file: + state: directory + path: /etc/remoteit + +- name: "'touch /etc/remoteit/registration' (might contain a remoteit_license_key) to prevent generation of claim code below; also speeding things up a bit" + file: + state: touch + path: /etc/remoteit/registration -- name: Fail if architecture remoteit_cli_suffix == "unknown" - fail: - msg: "Could not find a remote.it CLI binary for CPU architecture \"{{ ansible_architecture }}\"" - when: remoteit_cli_suffix == "unknown" +# - name: "Install Device Package: {{ downloads_dir }}/{{ remoteit_deb }}" +# apt: +# deb: "{{ downloads_dir }}/{{ remoteit_deb }}" -- name: Download {{ remoteit_cli_url }} (CLI) for arch {{ remoteit_cli_suffix }} to /usr/bin/remoteit (755) - get_url: - url: "{{ remoteit_cli_url }}" - dest: /usr/bin/remoteit +# - name: "Install Device Package: {{ remoteit_device_url }}" +# apt: +# deb: "{{ remoteit_device_url }}" + +# 2022-04-29: https://downloads.remote.it/remoteit/install_agent.sh refuses to +# install on Mint as "ID_LIKE=ubuntu" in /etc/os-release is lowercase. So we +# add a tag with the word 'Ubuntu' containing an uppercase 'U' as a workaround. +# (This hack can later be removed, if remote.it adjusts install_agent.sh above) +- name: If Linux Mint, add "IIAB_LIKE=Ubuntu" to /etc/os-release to force install of remote.it + # shell: echo "IIAB_LIKE=Ubuntu" >> /etc/os-release + lineinfile: + path: /etc/os-release + line: IIAB_LIKE=Ubuntu + when: is_linuxmint + +# - name: Install remote.it Device Package for your CPU/OS, using https://downloads.remote.it/remoteit/install_agent.sh -- this puts a claim code in /etc/remoteit/config.json which is valid for 24h +- name: Install remote.it Device Package for your CPU/OS, using https://downloads.remote.it/remoteit/install_agent.sh + shell: curl -L https://downloads.remote.it/remoteit/install_agent.sh | sh + +# 2022-06-29: Ansible misinterprets "IIAB_LIKE=Ubuntu" (interpreting the entire +# OS as Ubuntu instead of Mint, on later Ansible runs) so let's remove line now. +- name: If Linux Mint, remove above "IIAB_LIKE=Ubuntu" from /etc/os-release (for Ansible's sloppy OS recognition logic) + lineinfile: + path: /etc/os-release + line: IIAB_LIKE=Ubuntu + state: absent + when: is_linuxmint + + +# 2022-10-09: Let's keep the file (empty or not!) If it exists with size zero +# bytes, enable-or-disable.yml or /usr/bin/iiab-remoteit delete it later as nec. +# - name: "'rm /etc/remoteit/registration' (empty file used just above)" +# file: +# state: absent +# path: /etc/remoteit/registration +# ignore_errors: yes # In case a future version of install_agent.sh deletes it for us + + +- name: Install /usr/bin/iiab-remoteit from template -- so IIAB operators can quickly enable remote.it AND generate a new remote.it claim code (in /etc/remoteit/config.json) -- optionally downloading + installing the very latest Device Package (like the 2 steps above) + template: + src: iiab-remoteit + dest: /usr/bin + mode: 0755 + +- name: Install /usr/bin/iiab-remoteit-off from template -- so IIAB operators can quickly turn off AND disable remote.it services on this IIAB + template: + src: iiab-remoteit-off + dest: /usr/bin mode: 0755 - force: yes - timeout: "{{ download_timeout }}" -# RECORD remoteit AS INSTALLED +# 2023-07-26: Remote.It CLI used to coexist fine with their "Device Package" +# e.g. it worked with remoteit apt package 4.17.12 in Q2 2023. +# But no longer--with remoteit apt package 4.18.4 (in Q3 2023) which fails to +# install with error: "Device Package cannot coexist with Remote.It CLI" +# +# - name: Fail if architecture remoteit_arch == "unknown" +# fail: +# msg: "Could not find a remote.it CLI binary for CPU architecture \"{{ ansible_architecture }}\"" +# when: remoteit_arch == "unknown" +# +# - name: Download OPTIONAL {{ remoteit_cli_url }} (CLI) to /usr/bin/remoteit (755) +# get_url: +# url: "{{ remoteit_cli_url }}" # e.g. https://downloads.remote.it/cli/latest/remoteit.{{ remoteit_arch }}-linux +# dest: /usr/bin/remoteit +# mode: 0755 +# force: yes +# timeout: "{{ download_timeout }}" + + +# RECORD remote.it AS INSTALLED + +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'remoteit_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: remoteit + option: remoteit_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" - name: "Set 'remoteit_installed: True'" set_fact: diff --git a/roles/remoteit/tasks/main.yml b/roles/remoteit/tasks/main.yml index bc5be64a2..197010c3b 100644 --- a/roles/remoteit/tasks/main.yml +++ b/roles/remoteit/tasks/main.yml @@ -11,26 +11,39 @@ quiet: yes -- name: Install remoteit if 'remoteit_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: remoteit_installed is undefined +- block: + - name: Install remoteit if 'remoteit_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: remoteit_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + # - name: Extract claim code from /etc/remoteit/config.json if it exists + # shell: grep claim /etc/remoteit/config.json | rev | cut -d\" -f2 | rev + # register: remoteit_claim_code -- name: Add 'remoteit' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: remoteit - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: remote.it - - option: description - value: '"https://remote.it can help you remotely maintain an IIAB. Some benefits include: crossing multiple NATs/firewalls using a single TCP port, without requiring router port forwarding, and reducing your network''s vulnerability."' - - option: remoteit_install - value: "{{ remoteit_install }}" - - option: remoteit_enabled - value: "{{ remoteit_enabled }}" + - name: Add 'remoteit' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: remoteit + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: remote.it + - option: description + value: '"https://remote.it can help you remotely maintain an IIAB. Some benefits include: crossing multiple NATs/firewalls using a single TCP port, without requiring router port forwarding, and reducing your network''s vulnerability."' + - option: remoteit_install + value: "{{ remoteit_install }}" + - option: remoteit_enabled + value: "{{ remoteit_enabled }}" + # - option: remoteit_claim_code + # value: "{{ remoteit_claim_code.stdout }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/remoteit/templates/iiab-remoteit b/roles/remoteit/templates/iiab-remoteit new file mode 100755 index 000000000..e4f8097b0 --- /dev/null +++ b/roles/remoteit/templates/iiab-remoteit @@ -0,0 +1,185 @@ +#!/bin/bash -e + +# 'remoteit' Device Package AND /usr/bin/remoteit CLI already installed by: +# https://github.com/iiab/iiab/blob/master/roles/remoteit/tasks/install.yml + +# http://FAQ.IIAB.IO -> "How can I remotely manage my Internet-in-a-Box?" + +iiab_var_value() { + v1=$(grep "^$1:\s" /opt/iiab/iiab/vars/default_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + v2=$(grep "^$1:\s" /etc/iiab/local_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + [[ $v2 != "" ]] && echo $v2 || echo $v1 # [ "$v2" ] ALSO WORKS +} + +echo -e "\nLet's enable https://remote.it to help you remotely manage this IIAB:\n" + +echo -e "https://github.com/iiab/iiab/blob/master/roles/remoteit/README.md\n" + +# If someone manually deleted the dir, that blocks generation of claim code, +# and also license key extraction from /etc/iiab/local_vars.yml just below. +[ ! -d /etc/remoteit ] && + mkdir /etc/remoteit + +# Passwords and license keys in /etc/iiab/local_vars.yml are not a healthy +# precedent :/ (Going forward let's try to keep such fully in their own apps.) +KEY1=$(iiab_var_value remoteit_license_key) +if [[ $KEY1 != "" ]]; then + if [ -s /etc/remoteit/registration ]; then # Non-zero size + KEY2=$(cat /etc/remoteit/registration) + if [[ $KEY1 != $KEY2 ]]; then + mv /etc/remoteit/registration /etc/remoteit/registration.$(date +%F_%T_%Z) + echo -e "Old /etc/remoteit/registration moved aside.\n" + fi + fi + echo $KEY1 > /etc/remoteit/registration + echo -e "Copied remoteit_license_key value to /etc/remoteit/registration" + + sed -i '/^remoteit_license_key:/d' /etc/iiab/local_vars.yml + echo -e "Removed remoteit_license_key line from /etc/iiab/local_vars.yml\n" +fi + +# /etc/remoteit/registration consequences summarized on lines 114-119 +if [ -s /etc/remoteit/registration ]; then # Non-zero size + cp -p /etc/remoteit/registration /tmp/etc.remoteit.registration + echo -e "License key $(cat /etc/remoteit/registration) will be attempted." + echo -e "It's backed up from /etc/remoteit/registration to /tmp, in case of purge.\n" +elif [ -f /etc/remoteit/registration ]; then # Zero size, e.g. due to touch + rm /etc/remoteit/registration + echo -e "Empty /etc/remoteit/registration deleted, so claim code can be generated.\n" +fi + +echo -e "\nThis IIAB must be online to begin!" + +if [ -f /etc/remoteit/config.json ]; then + echo -en "\n\e[1mFor fresh registration let's remove /etc/remoteit/config.json, Ok? [Y/n]\e[0m " + read -n 1 -r ans < /dev/tty # Prompt for a single character + echo; echo + + if [[ $ans =~ ^[nN]$ ]]; then # Nearly the same as Lines 140-185 + echo -e "Let's try to enable remote.it, with your existing /etc/remoteit/config.json...\n" + + /usr/share/remoteit/refresh.sh # Just like connectd systemd service + # prior to 4.15.2 (its new remoteit-refresh.service is insufficient, as + # it's not installed initially, by their curl script install_agent.sh) + + if grep -q '^remoteit_enabled:' /etc/iiab/local_vars.yml; then + sed -i "s/^remoteit_enabled:.*/remoteit_enabled: True/" /etc/iiab/local_vars.yml + else + echo "remoteit_enabled: True" >> /etc/iiab/local_vars.yml + fi + + echo -e "\e[1m\nYou can now check for this IIAB device in your https://remote.it account." + echo -e "(e.g. if you already registered it to your remote.it account in the past!)\e[0m\n" + + echo -e "\e[1m1) Log in to https://remote.it or its Desktop Application on your own PC:\e[0m" + echo -e " https://remote.it/download/\n" + + echo -e '\e[1m2) In the "Devices" section on the left, check that your IIAB is now present:\e[0m' + echo -e " https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device\n" + + echo -e "\e[1m3) Authorize services/ports (e.g. SSH, HTTP, etc) for your IIAB device:\e[0m" + echo -e " https://docs.remote.it/software/device-package/installation#4.-set-up-services-on-your-device\n" + + exit 0 + fi +fi + +echo -en "\e[1m\nOptionally purge + install latest remote.it Device Package? [y/N]\e[0m " +read -n 1 -r ans < /dev/tty # Prompt for a single character +echo; echo + +if [[ $ans =~ ^[yY]$ ]]; then + # Full apt path avoids problematic /usr/local/bin/apt on Linux Mint + /usr/bin/apt -y purge "remoteit*" || true + + # Why the brutal purge? Even 'apt -y reinstall remoteit.*.deb' is stronger + # than 'install -y' in install_agent.sh, but still sometimes insufficient! + # https://github.com/iiab/iiab/blob/master/roles/remoteit/tasks/install.yml#L18-L21 + + if [ -f /tmp/etc.remoteit.registration ]; then + # apt purge should rmdir /etc/remoteit but might be sloppy in future? + [ ! -d /etc/remoteit ] && + mkdir /etc/remoteit + + cp -p /tmp/etc.remoteit.registration /etc/remoteit/registration + fi + + # apt install & enable "latest" remote.it Device Package for your CPU/OS + curl -L https://downloads.remote.it/remoteit/install_agent.sh | sh +else + # 2022-04-07: Stop/Delete/Start sequence follows official suggestions here: + # https://support.remote.it/hc/en-us/articles/360061228252-Oops-I-cloned-an-SD-card- + # https://docs.remote.it/oem-and-bulk-provisioning/registration-into-a-users-account + # + # FYI if /etc/remoteit/config.json DOESN'T EXIST: + # + # 1) If /etc/remoteit/registration exists and is EMPTY, bouncing connectd... DOESN'T CREATE /etc/remoteit/config.json + # 2) If /etc/remoteit/registration DOESN'T EXIST, bouncing connectd... CREATES /etc/remoteit/config.json WITH a claim code + WITHOUT an SSH service. + # 3) If /etc/remoteit/registration contains an INVALID license key, bouncing connectd CREATES /etc/remoteit/config.json WITH a claim code + WITHOUT an SSH service. + # 4) If /etc/remoteit/registration contains a VALID license key, bouncing connectd... CREATES /etc/remoteit/config.json WITHOUT a claim code + WITH an SSH service. + # + # FYI if /etc/remoteit/config.json EXISTS, bouncing connectd will update + # config.json's internal "timestamp" without changing anything else, + # regardless whether /etc/remoteit/registration exists and what it contains, + # and regardless whether /etc/remoteit/config.json contains a claim code. + + echo -e "In a few seconds, both services {schannel, remoteit@...} should be enabled!\n" + + #if [ ! -f /etc/remoteit/registration ] && [ -f /etc/remoteit/config.json ]; then + if [ -f /etc/remoteit/config.json ]; then + # echo -en "\n\e[1mMove /etc/remoteit/config.json, so registration can begin? [Y/n]\e[0m " + # read ans < /dev/tty # Strips outer whitespace, whether we like it or not! + # echo + # [[ $ans = "n" ]] || [[ $ans = "N" ]] && exit 1 + mv /etc/remoteit/config.json /etc/remoteit/config.json.$(date +%F_%T_%Z) + #echo -e "/etc/remoteit/config.json moved aside, so claim code can be generated.\n" + #echo -e "/etc/remoteit/config.json moved aside, so device registration can begin.\n" + echo -e "/etc/remoteit/config.json moved aside, for fresh device registration.\n" + fi + + /usr/share/remoteit/refresh.sh # Registration logic (use license key or + # generate claim code) then kickstart 2 "child" services below. In the + # past, we bounced the connectd service which did the same, and we enabled + # services {connectd, schannel} like enable-or-disable.yml used to do too. + + # schannel.service - Remote tcp command service + # remoteit@80:00:01:7F:7E:00:56:36.service - Remote tcp connection service + + # Both above appear a few seconds after refresh.sh is run, MANUAL NOT NEC: + # systemctl enable $(ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@*) + + # FYI systemd service names like remoteit@80:00:01:7F:7E:00:56:36.service + # change, e.g. when a new claim code is generated, and more arise when the + # IIAB device is registered to a remote.it account (#3166), etc. +fi + +if grep -q '^remoteit_enabled:' /etc/iiab/local_vars.yml; then + sed -i "s/^remoteit_enabled:.*/remoteit_enabled: True/" /etc/iiab/local_vars.yml +else + echo "remoteit_enabled: True" >> /etc/iiab/local_vars.yml +fi + +if grep -q claim /etc/remoteit/config.json; then + claim_code=$(grep claim /etc/remoteit/config.json | rev | cut -d\" -f2 | rev) + echo -e "\nYour new claim code is \e[44;1m${claim_code}\e[0m -- YOUR NEXT STEPS ARE...\n" + + echo -e "\e[1m1) Log in to https://remote.it or its Desktop Application on your own PC:\e[0m" + echo -e " https://remote.it/download/\n" + + echo -e "\e[1m2) Use the above 8-character claim code WITHIN 24H as shown here:\e[0m" + echo -e " https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device\n" + + echo -e "\e[1m3) Authorize services/ports (e.g. SSH, HTTP, etc) for your IIAB device:\e[0m" + echo -e " https://docs.remote.it/software/device-package/installation#4.-set-up-services-on-your-device\n" +else + echo -e "\nLicense key (if valid!) hopefully worked -- YOUR NEXT STEPS ARE...\n" + + echo -e "\e[1m1) Log in to https://remote.it or its Desktop Application on your own PC:\e[0m" + echo -e " https://remote.it/download/\n" + + echo -e '\e[1m2) In the "Devices" section on the left, check that your IIAB is now present:\e[0m' + echo -e " https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device\n" + + echo -e "\e[1m3) Authorize services/ports (e.g. SSH, HTTP, etc) for your IIAB device:\e[0m" + echo -e " https://docs.remote.it/software/device-package/installation#4.-set-up-services-on-your-device\n" +fi diff --git a/roles/remoteit/templates/iiab-remoteit-off b/roles/remoteit/templates/iiab-remoteit-off new file mode 100755 index 000000000..8cd9b1b1b --- /dev/null +++ b/roles/remoteit/templates/iiab-remoteit-off @@ -0,0 +1,33 @@ +#!/bin/bash -xe + +# Run 'sudo iiab-remoteit-off' to disable remote.it on this IIAB. GENERAL TIPS: +# http://FAQ.IIAB.IO -> "How can I remotely manage my Internet-in-a-Box?" + +# GUIDE: https://github.com/iiab/iiab/blob/master/roles/remoteit/README.md + +# FYI 'remoteit' Device Package AND /usr/bin/remoteit CLI are installed by: +# https://github.com/iiab/iiab/blob/master/roles/remoteit/tasks/install.yml + +if grep -q '^remoteit_enabled:' /etc/iiab/local_vars.yml; then + sed -i "s/^remoteit_enabled:.*/remoteit_enabled: False/" /etc/iiab/local_vars.yml +else + echo "remoteit_enabled: False" >> /etc/iiab/local_vars.yml +fi + +# 3 sections below should be equivalent to -- and much faster than: +# https://github.com/iiab/iiab/tree/master/roles/remoteit/tasks/enable-or-disable.yml + +# remote.it "parent" service no longer part of Device Package 4.15.2 on 2022-09-07 +#systemctl stop connectd +#systemctl disable connectd + +# "Remote tcp command service" +systemctl stop schannel +systemctl disable schannel + +# "Remote tcp connection service" (typically 1-3 of these) +systemctl stop $(ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@*) || true +systemctl disable $(ls /etc/systemd/system/multi-user.target.wants/ | grep remoteit@*) || true +# These systemd service names e.g. remoteit@80:00:01:7F:7E:00:56:36.service +# change, e.g. when a new claim code is generated, and more arise when the +# IIAB device is registered to a remote.it account (#3166), etc. diff --git a/roles/remoteit/templates/iiab-remoteit.old b/roles/remoteit/templates/iiab-remoteit.old new file mode 100755 index 000000000..79163e81a --- /dev/null +++ b/roles/remoteit/templates/iiab-remoteit.old @@ -0,0 +1,51 @@ +#!/bin/bash -e + +# Run 'sudo iiab-remoteit' to (re)install & enable remote.it -- GENERAL TIPS: +# http://FAQ.IIAB.IO -> "How can I remotely manage my Internet-in-a-Box?" + +# /usr/bin/remoteit CLI is already be installed by: +# https://github.com/iiab/iiab/blob/master/roles/remoteit/tasks/install.yml + +echo -e "\nhttps://remote.it can help you remotely manage this IIAB:" +echo -e "https://github.com/iiab/iiab/blob/master/roles/remoteit/README.md\n" + +echo -en "\e[1mInstall remote.it Device Package after purging all prior versions? [Y/n]\e[0m " +read ans < /dev/tty # Strips outer whitespace, whether we like it or not! +echo +[ "$ans" = "n" ] || [ "$ans" = "N" ] && exit 1 + +if grep -q '^remoteit_install:' /etc/iiab/local_vars.yml; then + sed -i "s/^remoteit_install:.*/remoteit_install: True/" /etc/iiab/local_vars.yml +else + echo "remoteit_install: True" >> /etc/iiab/local_vars.yml +fi + +if grep -q '^remoteit_enabled:' /etc/iiab/local_vars.yml; then + sed -i "s/^remoteit_enabled:.*/remoteit_enabled: True/" /etc/iiab/local_vars.yml +else + echo "remoteit_enabled: True" >> /etc/iiab/local_vars.yml +fi + +# 2022-04-02: Full Path Avoids problematic /usr/local/bin/apt on Linux Mint +/usr/bin/apt -y purge remoteit* + +# Why the brutal purge? Even 'apt -y reinstall remoteit.*.deb' is much stronger +# than 'install -y' in install_agent.sh below, but still insufficient. Maybe in +# future years their /usr/bin/remoteit CLI might seed a new claim code when nec? + +# apt install & enable "latest" remote.it Device Package for your CPU/OS +curl -L https://downloads.remote.it/remoteit/install_agent.sh | sh + +if grep -q '^remoteit_installed:' /etc/iiab/iiab_state.yml; then + sed -i "s/^remoteit_installed:.*/remoteit_installed: True/" /etc/iiab/iiab_state.yml +else + echo "remoteit_installed: True" >> /etc/iiab/iiab_state.yml +fi + +echo -e "\e[44;1mNEXT STEPS...\e[0m\n" + +echo -e "\e[1m1) Install the remote.it Desktop Application on your own laptop/computer:" +echo -e " https://remote.it/download/\n" + +echo -e "2) Use the above 8-character claim code within 24h as shown here:" +echo -e " https://docs.remote.it/software/device-package/installation#3.-claim-and-register-the-device\e[0m\n" diff --git a/roles/remoteit/templates/registration.j2 b/roles/remoteit/templates/registration.j2 new file mode 100644 index 000000000..774abae03 --- /dev/null +++ b/roles/remoteit/templates/registration.j2 @@ -0,0 +1 @@ +{{ remoteit_license_key }} diff --git a/roles/samba/README.rst b/roles/samba/README.rst index 2f65310d0..197448760 100644 --- a/roles/samba/README.rst +++ b/roles/samba/README.rst @@ -3,7 +3,7 @@ Samba README Do you want your Internet-in-a-Box (IIAB) to act as a file server for your classroom or school? -If `Samba `_ is installed and enabled as part of your IIAB's `/etc/iiab/local_vars.yml `_, your IIAB server can advertise a shared "public" folder, available to Windows PC's and laptops on your network. +If `Samba `_ is installed and enabled as part of your IIAB's `/etc/iiab/local_vars.yml `_, your IIAB server can advertise a shared "public" folder, available to Windows PC's and laptops on your network. Default Permissions ------------------- @@ -22,4 +22,4 @@ Security Please review the default `/etc/samba/smb.conf `_ file, and revise it appropriately. -Please also review your overall `IIAB Security `_. +Please also review your overall `IIAB Security `_. diff --git a/roles/samba/tasks/install.yml b/roles/samba/tasks/install.yml index 5dfb5f5f3..1ebc623ed 100644 --- a/roles/samba/tasks/install.yml +++ b/roles/samba/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Create smb user: {{ smbuser }}" user: name: "{{ smbuser }}" @@ -13,12 +18,13 @@ state: directory # Install and configure samba server (requires ports 137, 138, 139, 445 open). -- name: "Install 4 packages: samba, samba-client, samba-common, cifs-client" +- name: "Install 4 packages: samba, samba-common, smbclient, cifs-client" package: name: - samba - - samba-client + #- samba-client # 2022-04-13: Virtual package fails to install w/ ansible-core 2.13.0b0 - samba-common + - smbclient - cifs-utils state: present @@ -30,6 +36,17 @@ # RECORD Samba AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'samba_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: samba + option: samba_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'samba_installed: True'" set_fact: samba_installed: True diff --git a/roles/samba/tasks/main.yml b/roles/samba/tasks/main.yml index 801d725f4..12d06f2d4 100755 --- a/roles/samba/tasks/main.yml +++ b/roles/samba/tasks/main.yml @@ -19,26 +19,33 @@ quiet: yes -- name: Install Samba if 'samba_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: samba_installed is undefined +- block: + - name: Install Samba if 'samba_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: samba_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'samba' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: samba + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Samba + - option: description + value: '"Samba is a Microsoft-compatible network file system that re-implements SMB/CIFS (Common Internet File System)."' + - option: samba_install + value: "{{ samba_install }}" + - option: samba_enabled + value: "{{ samba_enabled }}" -- name: Add 'samba' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: samba - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Samba - - option: description - value: '"Samba is a Microsoft-compatible network file system that re-implements SMB/CIFS (Common Internet File System)."' - - option: samba_install - value: "{{ samba_install }}" - - option: samba_enabled - value: "{{ samba_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/samba/templates/smb.conf.j2 b/roles/samba/templates/smb.conf.j2 index acfc004a7..9b60050d8 100755 --- a/roles/samba/templates/smb.conf.j2 +++ b/roles/samba/templates/smb.conf.j2 @@ -4,10 +4,10 @@ # # The Official Samba 3.2.x HOWTO and Reference Guide contains step-by-step # guides for installing, configuring, and using Samba: -# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf +# https://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf # # The Samba-3 by Example guide has working examples for smb.conf. This guide is -# generated daily: http://www.samba.org/samba/docs/Samba-Guide.pdf +# generated daily: https://www.samba.org/samba/docs/Samba-Guide.pdf # # In this file, lines starting with a semicolon (;) or a hash (#) are # comments and are ignored. This file uses hashes to denote commentary and @@ -92,7 +92,12 @@ ; netbios name = MYSERVER ; interfaces = lo eth0 192.168.12.2/24 192.168.13.2/24 + +{% if network_172 %} hosts allow = 127. 172.18. +{% else %} + hosts allow = 127. 10.10.10. +{% endif %} ; max protocol = SMB2 diff --git a/roles/sshd/defaults/main.yml b/roles/sshd/defaults/main.yml new file mode 100644 index 000000000..83a3cf36a --- /dev/null +++ b/roles/sshd/defaults/main.yml @@ -0,0 +1,10 @@ +# sshd_install: True +# sshd_enabled: True + +# sshd_port: 22 # Not fully functional. SEE: roles/sshd/tasks/install.yml + +# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml +# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! + +sshd_package: openssh-server +sshd_service: ssh diff --git a/roles/sshd/tasks/install.yml b/roles/sshd/tasks/install.yml index 0be48232d..b5b3271bc 100644 --- a/roles/sshd/tasks/install.yml +++ b/roles/sshd/tasks/install.yml @@ -1,14 +1,20 @@ # TODO: # -# 1) Implement sshd_port IF it's truly needed? Mentioned here as of 2020-09-24: +# 1) Implement sshd_port IF it's truly needed? Mentioned here as of 2022-12-27: # -# vars/default_vars.yml Line 212 -# roles/sshd/tasks/main.yml Lines 41-42 +# vars/default_vars.yml Line 226 +# roles/sshd/tasks/install.yml Lines 45-46 # roles/network/tasks/avahi.yml Line 46 -# roles/network/templates/gateway/iiab-gen-iptables Line 49 & 135 +# roles/network/templates/gateway/iiab-gen-iptables Line 71 & 153 # # 2) Use Ansible handler to reload ssh? + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Install ssh daemon using package: {{ sshd_package }}" package: name: "{{ sshd_package }}" @@ -20,7 +26,6 @@ regexp: '^PermitRootLogin' line: 'PermitRootLogin without-password' state: present - #when: sshd_enabled - name: mkdir /root/.ssh file: @@ -29,7 +34,6 @@ owner: root group: root mode: '0700' - #when: sshd_enabled - name: Install dummy root keys as placeholder copy: @@ -39,11 +43,21 @@ group: root mode: '0600' force: no - #when: sshd_enabled # RECORD sshd AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'sshd_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: sshd + option: sshd_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'sshd_installed: True'" set_fact: sshd_installed: True diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml index dccb4cd10..d6104353f 100644 --- a/roles/sshd/tasks/main.yml +++ b/roles/sshd/tasks/main.yml @@ -34,13 +34,13 @@ option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: - - option: name - value: sshd - - option: description - value: '"Secure Shell daemon (typically implemented by openssh-server) for remote login using the ''ssh'' low-level protocol."' - - option: sshd_install - value: "{{ sshd_install }}" - - option: sshd_enabled - value: "{{ sshd_enabled }}" - - option: sshd_port - value: "{{ sshd_port }}" + - option: name + value: sshd + - option: description + value: '"Secure Shell daemon (typically implemented by openssh-server) for remote login using the ''ssh'' low-level protocol."' + - option: sshd_install + value: "{{ sshd_install }}" + - option: sshd_enabled + value: "{{ sshd_enabled }}" + - option: sshd_port + value: "{{ sshd_port }}" diff --git a/roles/sugarizer/defaults/main.yml b/roles/sugarizer/defaults/main.yml index 4ddd4a706..ad5e48843 100644 --- a/roles/sugarizer/defaults/main.yml +++ b/roles/sugarizer/defaults/main.yml @@ -9,11 +9,11 @@ # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! -sugarizer_dir_version: sugarizer-1.5.0 # WAS: sugarizer-1.0, sugarizer-master, sugarizer-1.1.0, sugarizer-1.2.0, sugarizer-1.3.0, sugarizer-1.4.0 -sugarizer_git_version: v1.5.0 # WAS: v1.0.1, master, v1.1.0, v1.2.0, v1.3.0, v1.4.0 +sugarizer_dir_version: sugarizer-1.8.0 # WAS: sugarizer-1.0, sugarizer-master, sugarizer-1.1.0, sugarizer-1.2.0, sugarizer-1.3.0, sugarizer-1.4.0, sugarizer-1.5.0, sugarizer-1.6.0, sugarizer-1.7.0 +sugarizer_git_version: v1.8.0 # WAS: v1.0.1, master, v1.1.0, v1.2.0, v1.3.0, v1.4.0, v1.5.0, v1.6.0, v1.7.0 # PLEASE HELP MONITOR https://github.com/llaske/sugarizer/releases -sugarizer_server_dir_version: sugarizer-server-1.4.0 # WAS: sugarizer-server-1.0, sugarizer-server-master, sugarizer-server-dev, sugarizer-server-1.1.0, sugarizer-server-1.1.1, sugarizer-server-1.2.0, sugarizer-server-1.3.0 -sugarizer_server_git_version: v1.4.0 # WAS: v1.0.1, master, dev, f27bf6acd56aba6d99116ef471ca713b0f0dfed3, v1.1.0, v1.1.1, v1.2.0, v1.3.0 +sugarizer_server_dir_version: sugarizer-server-1.5.0 # WAS: sugarizer-server-1.0, sugarizer-server-master, sugarizer-server-dev, sugarizer-server-1.1.0, sugarizer-server-1.1.1, sugarizer-server-1.2.0, sugarizer-server-1.3.0, sugarizer-server-1.4.0 +sugarizer_server_git_version: v1.5.0 # WAS: v1.0.1, master, dev, f27bf6acd56aba6d99116ef471ca713b0f0dfed3, v1.1.0, v1.1.1, v1.2.0, v1.3.0, v1.4.0 # PLEASE HELP MONITOR https://github.com/llaske/sugarizer-server/commits/dev # AND https://github.com/llaske/sugarizer-server/releases diff --git a/roles/sugarizer/tasks/install.yml b/roles/sugarizer/tasks/install.yml index bf0e37252..c37b4c6de 100644 --- a/roles/sugarizer/tasks/install.yml +++ b/roles/sugarizer/tasks/install.yml @@ -27,9 +27,14 @@ # when: nodejs_version != "12.x" +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 2. DOWNLOAD+LINK /opt/iiab/sugarizer -- name: Clone llaske/sugarizer ({{ sugarizer_git_version }} branch/version) from GitHub to /opt/iiab/{{ sugarizer_dir_version }} (DOWNLOADS ~717 MB) +- name: Clone llaske/sugarizer ({{ sugarizer_git_version }} branch/version) from GitHub to /opt/iiab/{{ sugarizer_dir_version }} (DOWNLOADS ~748 MB) git: repo: https://github.com/llaske/sugarizer dest: "{{ iiab_base }}/{{ sugarizer_dir_version }}" @@ -46,7 +51,7 @@ # 3. DOWNLOAD+LINK /opt/iiab/sugarizer-server -# 2018-07-11: http://download.iiab.io/packages/sugarizer-server-1.0.tar.gz +# 2018-07-11: https://download.iiab.io/packages/sugarizer-server-1.0.tar.gz # was flawed, as documented at: # https://github.com/iiab/iiab/pull/814#issuecomment-404211098 # Versions of MongoDB, npm (& Node.js ?) matter! Sugarizer 1.0 Context: @@ -61,7 +66,7 @@ # CLARIF: during repeat runs of "./runrole sugarizer", this git sync shows # "changed" (whereas above git sync shows "ok"). Reason: "npm install" # (below) modifies /opt/iiab/sugarizer-server/node_modules -- name: Clone llaske/sugarizer-server ({{ sugarizer_server_git_version }} branch/version) from GitHub to /opt/iiab/{{ sugarizer_server_dir_version }} (~9 MB initially, ~193+ MB later) +- name: Clone llaske/sugarizer-server ({{ sugarizer_server_git_version }} branch/version) from GitHub to /opt/iiab/{{ sugarizer_server_dir_version }} (~16 MB initially, ~227+ MB later) git: repo: https://github.com/llaske/sugarizer-server dest: "{{ iiab_base }}/{{ sugarizer_server_dir_version }}" @@ -159,7 +164,7 @@ # WITH FUTURE UPGRADES BEYOND SUGARIZER 1.1?! # # SOME BACKGROUND -- WHY WE'RE AUTO-EDITING sugarizer-server'S CONFIG FILES: -# http://github.com/iiab/iiab/pull/1430#issuecomment-459129378 +# https://github.com/iiab/iiab/pull/1430#issuecomment-459129378 # sugarizer_port is set to 8089 in /opt/iiab/iiab/vars/default_vars.yml # If you need to change this, edit /etc/iiab/local_vars.yml prior to installing @@ -232,6 +237,17 @@ # 6. RECORD Sugarizer AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'sugarizer_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: sugarizer + option: sugarizer_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'sugarizer_installed: True'" set_fact: sugarizer_installed: True diff --git a/roles/sugarizer/tasks/main.yml b/roles/sugarizer/tasks/main.yml index e1e6b825b..d0c2ac55a 100644 --- a/roles/sugarizer/tasks/main.yml +++ b/roles/sugarizer/tasks/main.yml @@ -19,39 +19,53 @@ quiet: yes -# 3 stanzas moved up from install.yml, so Debian-or-any-OS-where-MongoDB-fails -# still finish their "LARGE-sized" IIAB install: (WITH LOUD RED WARNINGS!) +- block: -- name: "Set 'mongodb_install: True'" - set_fact: - mongodb_install: True + # 3 stanzas moved up from install.yml, so Debian-or-any-OS-where-MongoDB-fails + # still finish their "LARGE-sized" IIAB install: (WITH LOUD RED WARNINGS!) -- name: 'CAUTION: IF ''mongodb.service'' IS STOPPED FOR ANY REASON, IT WILL IMMEDIATELY CAUSE SUGARIZER TO FAIL ("502 Bad Gateway") !' - debug: - msg: "/etc/systemd/system/sugarizer.service Line 4 'Requires=mongodb.service' tries to auto-start MongoDB every time Sugarizer starts. IIAB (roles/mongodb/tasks/enable-or-disable.yml) tries its best to keep Ansible var 'mongodb_enabled' in sync with its systemd equivalent, i.e. the output of 'systemctl is-enabled mongodb' (as of 2020-10-29 both are typically disabled, unless other apps/services/operators choose to use MongoDB)." + - name: "Set 'mongodb_install: True'" + set_fact: + mongodb_install: True -- name: MONGODB - run 'mongodb' role (attempt to install MongoDB) - include_role: - name: mongodb + - name: 'CAUTION: IF ''mongodb.service'' IS STOPPED FOR ANY REASON, IT WILL IMMEDIATELY CAUSE SUGARIZER TO FAIL ("502 Bad Gateway") !' + debug: + msg: "/etc/systemd/system/sugarizer.service Line 4 'Requires=mongodb.service' tries to auto-start MongoDB every time Sugarizer starts. IIAB (roles/mongodb/tasks/enable-or-disable.yml) tries its best to keep Ansible var 'mongodb_enabled' in sync with its systemd equivalent, i.e. the output of 'systemctl is-enabled mongodb' (as of 2020-10-29 both are typically disabled, unless other apps/services/operators choose to use MongoDB)." + + - name: MONGODB - run 'mongodb' role (attempt to install MongoDB) + include_role: + name: mongodb -- name: EXIT 'sugarizer' ROLE & CONTINUE, IF 'mongodb_installed is undefined' - fail: # FORCE IT RED THIS ONCE! - msg: MongoDB INSTALLATION FAILED, perhaps because your OS is Debian 10 on aarch64? Nevertheless IIAB will continue (consider this a warning!) - when: mongodb_installed is undefined - ignore_errors: yes + # - name: EXIT 'sugarizer' ROLE & CONTINUE, IF 'mongodb_installed is undefined' + # fail: # FORCE IT RED THIS ONCE! + # msg: MongoDB INSTALLATION FAILED, perhaps because MongoDB doesn't yet support Ubuntu 22.04 with libssl3? Nevertheless IIAB will continue (consider this a warning!) + # when: mongodb_installed is undefined + # ignore_errors: yes # RESCUE (BELOW) NOW HANDLES THIS -# ELSE... + - name: Verify that mongodb_installed is defined + fail: + msg: MongoDB INSTALLATION FAILED, perhaps because MongoDB doesn't yet support Ubuntu 22.04 with libssl3? #3190 + when: mongodb_installed is undefined -- name: Install/Enable/Disable/Record Sugarizer (main2.yml) IF 'mongodb_installed is defined' - include_tasks: main2.yml - when: mongodb_installed is defined + # ELSE... -# THE block: APPROACH BELOW WORKS JUST LIKE main2.yml ABOVE. -# BUT IT VISUALLY POLLUTES: MANY BLUE "skipping:" MESSAGES IN ANSIBLE'S OUTPUT. + - name: Install/Enable/Disable/Record Sugarizer (main2.yml) IF 'mongodb_installed is defined' + include_tasks: main2.yml + when: mongodb_installed is defined -# - block: # ENTIRE BLOCK CONDITIONED ON 'when: mongodb_installed is defined' -# -# [MOVED TO main2.yml] -# -# when: mongodb_installed is defined # CONDITION FOR ENTIRE ABOVE block: + # THE block: APPROACH BELOW WORKS JUST LIKE main2.yml ABOVE. + # BUT IT VISUALLY POLLUTES: MANY BLUE "skipping:" MESSAGES IN ANSIBLE'S OUTPUT. + + # - block: # ENTIRE BLOCK CONDITIONED ON 'when: mongodb_installed is defined' + # + # [MOVED TO main2.yml] + # + # when: mongodb_installed is defined # CONDITION FOR ENTIRE ABOVE block: + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/sugarizer/tasks/main2.yml b/roles/sugarizer/tasks/main2.yml index 88aa786f8..5a719e233 100644 --- a/roles/sugarizer/tasks/main2.yml +++ b/roles/sugarizer/tasks/main2.yml @@ -3,8 +3,7 @@ when: sugarizer_installed is undefined -- name: Enable/Disable/Restart NGINX - include_tasks: enable-or-disable.yml +- include_tasks: enable-or-disable.yml - name: Add 'sugarizer' variable values to {{ iiab_ini_file }} diff --git a/roles/tailscale/tasks/install.yml b/roles/tailscale/tasks/install.yml new file mode 100644 index 000000000..97e939a84 --- /dev/null +++ b/roles/tailscale/tasks/install.yml @@ -0,0 +1,113 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: "Set up apt source (jammy) in /etc/apt/sources.list.d/tailscale.list and its key /usr/share/keyrings/tailscale-archive-keyring.gpg, to install Tailscale" + shell: | + curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg > /usr/share/keyrings/tailscale-archive-keyring.gpg + curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list > /etc/apt/sources.list.d/tailscale.list + +- name: "Install packages: jq, sudo, tailscale" + package: + name: + #- ncat # Newer versions of NMap do not include NCat, WAS needed to announce openvpn_handle (if Debian > 9 or Ubuntu > 18) + #- nmap + - jq # JSON parser used by /usr/bin/iiab-support == /usr/bin/iiab-vpn + - sudo # (1) Should be installed prior to installing IIAB, (2) Can also be installed by 1-prep here, (3) Is definitely installed by 1-prep's roles/iiab-admin/tasks/sudo-prereqs.yml, (4) Used to be installed by roles/2-common/tasks/packages.yml (but that's too late!) + - tailscale + update_cache: yes + +- name: Set up tab completion for 'tailscale' at the command-line + shell: mkdir -p /etc/bash_completion.d && tailscale completion bash > /etc/bash_completion.d/tailscale + +- name: "Install ssh public keys for remote support (only runs if 'tailscale_install: True')" + lineinfile: + line: "{{ item.pubkey }}" + regexp: "{{ item.regexp }}" + path: /root/.ssh/authorized_keys + with_items: + - regexp: "LvCSAAcfYIdZPR4ePVpVUZ/IbkGjpQSoRMa5HuVjMO3cZNR27ptqjNjq2husJOyhMFCOBTzo4thioGyTpBr4u3s=$" # Tim Moody + pubkey: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAhlQIh8ZPx4awdM0O6QNcPbx3qIZ39FHjF2YJ2SX3z7iLnYiz03Ek6Bux9P4HvaVAqlApiz2I68Vq8TfU2s/+LvCSAAcfYIdZPR4ePVpVUZ/IbkGjpQSoRMa5HuVjMO3cZNR27ptqjNjq2husJOyhMFCOBTzo4thioGyTpBr4u3s=" + - regexp: "tUM4hl009fbXY4Yy3bAadWL1CquVrZmKfBBWhyhz8zLD6TQ== ghunt@ip-192-168-123-123.ec2.internal$" + pubkey: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxAmjU7VojyK+0Pjp2p8CCGTNBtE565A/L8IVbAT8MIucRE9LN1g5LjGnOHUShFJpwuTR1JLX2r9EDRMsf9MmyTgUAnuyP005giWVHXLPtjyjTzbsJ1DEtXRytulmF+GlCOaqPWNde6EOmReqPHbmjIQpRZ/Sc8hziS4jVSQuBA9EhaBmZ62CPqK33mPJvnpwMtdd6nHXAcXsZhStd3NhVDm27+B3sHI6mr2w7ExdBXE5DKiZL2po8n2y4hJYZreJopbjcQmv4oWdDWvPu5I92xDgYCsqcE7zSrv1um+tUM4hl009fbXY4Yy3bAadWL1CquVrZmKfBBWhyhz8zLD6TQ== ghunt@ip-192-168-123-123.ec2.internal" + - regexp: "heOMXXNU6skxdPh2fcHh0bzQcaCSQ== holt@crank$" + pubkey: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEApHPly+EA1M4bispl3AulTLjyYCjcJzh6s779K3epDkqh600a+fHsdIiddWCAfIonRq+9MJyOiaNQ+WYLOuajI1IiFZWFt45xDAiyCUnyuT+ytAX+IA3TgTwgTZPfzDOzI8rDRV9Sgl+LZLfPno7T3qxcGx2l51bRk+koRK+Txpph//M3jGvsFmTKhjvfxgEIUmMH9SkASxEdyqASr0+/+uLR92MnT+8CT1pOYYoJyZp9Lta5eGqJvbEmd3Dn7MXqD3vXE57o4rBJ0bR3q5LK59WVNxNQbulJ9z5V7aTJ4AbBFQWxm0fH0gBx+heOMXXNU6skxdPh2fcHh0bzQcaCSQ== holt@crank" + +# CLARIF: plus signs (+) in public keys cause duplicate key additions (above) +# and failure during removal (below) as "+" has a special meaning as +# interpreted in a Python regexp, as implemented by Ansible's lineinfile module: +# https://docs.python.org/2/library/re.html + +# WORKAROUND: the tail end of each public key (after the last plus sign) is +# being used (instead of the full key) as an abbreviated regexp for now. +# A backslash in front of each plus sign (+) would also work. + +# - name: Remove those ssh public keys, if not tailscale_enabled +# lineinfile: +# regexp: "{{ item }}" +# path: /root/.ssh/authorized_keys +# state: absent +# with_items: +# - "LvCSAAcfYIdZPR4ePVpVUZ/IbkGjpQSoRMa5HuVjMO3cZNR27ptqjNjq2husJOyhMFCOBTzo4thioGyTpBr4u3s=$" +# - "tUM4hl009fbXY4Yy3bAadWL1CquVrZmKfBBWhyhz8zLD6TQ== ghunt@ip-192-168-123-123.ec2.internal$" +# - "heOMXXNU6skxdPh2fcHh0bzQcaCSQ== holt@crank$" +# when: not tailscale_enabled + +- name: Install /usr/bin/iiab-vpn & /usr/bin/iiab-vpn-off (BACKS UP FILES IF CHANGED) + template: + src: "{{ item }}" + dest: /usr/bin/ + mode: '0755' + backup: yes + with_items: + - iiab-vpn + - iiab-vpn-off + +- name: Symlink /usr/bin/iiab-vpn-on -> /usr/bin/iiab-vpn + file: + src: /usr/bin/iiab-vpn + path: /usr/bin/iiab-vpn-on + state: link + +- name: Symlink /usr/bin/iiab-support -> /usr/bin/iiab-vpn + file: + src: /usr/bin/iiab-vpn + path: /usr/bin/iiab-support + state: link + +- name: Symlink /usr/bin/iiab-support-on -> /usr/bin/iiab-vpn + file: + src: /usr/bin/iiab-vpn + path: /usr/bin/iiab-support-on + state: link + +- name: Symlink /usr/bin/iiab-support-off -> /usr/bin/iiab-vpn-off + file: + src: /usr/bin/iiab-vpn-off + path: /usr/bin/iiab-support-off + state: link + + +# RECORD Tailscale AS INSTALLED + +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'tailscale_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: tailscale + option: tailscale_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + +- name: "Set 'tailscale_installed: True'" + set_fact: + tailscale_installed: True + +- name: "Add 'tailscale_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^tailscale_installed' + line: 'tailscale_installed: True' diff --git a/roles/tailscale/tasks/main.yml b/roles/tailscale/tasks/main.yml new file mode 100644 index 000000000..fc8af13e5 --- /dev/null +++ b/roles/tailscale/tasks/main.yml @@ -0,0 +1,47 @@ +# http://FAQ.IIAB.IO -> "How can I remotely manage my Internet-in-a-Box?" + + +# "How do i fail a task in Ansible if the variable contains a boolean value? +# I want to perform input validation for Ansible playbooks" +# https://stackoverflow.com/questions/46664127/how-do-i-fail-a-task-in-ansible-if-the-variable-contains-a-boolean-value-i-want/46667499#46667499 + +# We assume 0-init/tasks/validate_vars.yml has DEFINITELY been run, so no need +# to re-check whether vars are defined here. As Ansible vars cannot be unset: +# https://serverfault.com/questions/856729/how-to-destroy-delete-unset-a-variable-value-in-ansible + +- name: Assert that "tailscale_install is sameas true" (boolean not string etc) + assert: + that: tailscale_install is sameas true + fail_msg: "PLEASE SET 'tailscale_install: True' e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + +- name: Assert that "tailscale_enabled | type_debug == 'bool'" (boolean not string etc) + assert: + that: tailscale_enabled | type_debug == 'bool' + fail_msg: "PLEASE GIVE VARIABLE 'tailscale_enabled' A PROPER (UNQUOTED) ANSIBLE BOOLEAN VALUE e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + + +- name: Install Tailscale if 'tailscale_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: tailscale_installed is undefined + + +#- include_tasks: enable-or-disable.yml + + +- name: Add 'tailscale' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: tailscale + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Tailscale (VPN) + - option: description + value: '"Tailscale enables live/remote support by connecting machines anywhere on the Internet, using a software-defined mesh virtual private network (VPN), and optional web-based management service."' + - option: tailscale_install + value: "{{ tailscale_install }}" + - option: tailscale_enabled + value: "{{ tailscale_enabled }}" diff --git a/roles/tailscale/templates/iiab-vpn b/roles/tailscale/templates/iiab-vpn new file mode 100755 index 000000000..77e8c13be --- /dev/null +++ b/roles/tailscale/templates/iiab-vpn @@ -0,0 +1,71 @@ +#!/bin/bash + +# USEFUL DOCS: +# https://tailscale.com/kb/1080/cli#status +# https://headscale.net/stable/usage/connect/android/ +# https://headscale.net/stable/usage/connect/apple/ +# https://headscale.net/stable/usage/connect/windows/ + +VPN_URL=https://iiab.net +VPN_KEY="$1" + +# if tailscale status > /dev/null; then # MANY IMPERFECT TESTS OF TAILNET CONNECTIVITY: tailscale0 CAN lose its IP address, as shown by 'ip a' and 'hostname -I' (testing 'systemctl is-active tailscaled' is likely no better!) Unclear if 'tailscale status --json | jq -r .Self.Online' is much better? Maybe explore 'tailscale debug --help' and 'tailscale debug prefs' for a cleaner/authoritative verdict? Or use + display string output of 'systemctl show tailscaled --property=StatusText' e.g. 'StatusText=Connected; iiab; 100.64.0.4' ? (OR JUST DON'T WORRY ABOUT IT, AS THE ~3 'tailscale up' COMMANDS BELOW ARE MORE PROACTIVE... AND APPEAR FAST + SAFE!) +# echo -e "\n\033[1;33mAlready connected to VPN!?\033[0m" +# else +# [NEST ~20 LINES OF IF STATEMENTS FURTHER BELOW?] + +# Check that current profile key still exists in /var/lib/tailscale/tailscaled.state ? (As 'tailscale logout' wipes it!) In the end, these are 3 lousy tests... +# if [ -f /var/lib/tailscale/tailscaled.state ] && [[ $(grep -c $(jq -r '."_current-profile"' /var/lib/tailscale/tailscaled.state) /var/lib/tailscale/tailscaled.state) > 1 ]]; then +# if ! [[ $(tailscale status | tr '[:upper:]' '[:lower:]') =~ "logged out" ]]; then +# if [[ $(tailscale status --json | jq -r .CurrentTailnet.Name) = "iiab.community" ]]; then + +# UX Optimization: {iiab-vpn, iiab-support} can be run WITHOUT key *IF* .BackendState is "Stopped" or "Running" *AND* .ControlURL is $VPN_URL (avoid their default, https://controlplane.tailscale.com !) +if [[ $(tailscale status --json | jq -r .BackendState) != "NeedsLogin" && $(tailscale debug prefs | jq -r .ControlURL) = $VPN_URL ]]; then + if ! tailscale up --login-server "$VPN_URL" --timeout 8s; then # (Re-)passing $VPN_URL is overkill on this line, but can't hurt! + echo -e "\n\033[41;1mERROR $?: Failed to connect to VPN\033[0m\n" + exit 1 + fi +elif [ -z $VPN_KEY ]; then + echo -e "\n\033[1;33mVPN key required!\033[0m\n\nEmail holt@unleashkids.org to explain your need?\n" + exit 1 +else + if ! tailscale up --login-server "$VPN_URL" --auth-key "$VPN_KEY" --timeout 8s; then + echo -e "\n\033[41;1mERROR $?: Failed to connect to VPN, so let's try --force-reauth\033[0m\n" + # If 'tailscale up' just above fails w/ exit code 1 ~= "can't change --login-server without --force-reauth" (i.e. if switching login server, e.g. to/from their default (https://controlplane.tailscale.com) -- SEE ALSO: 'tailscale switch -h' and https://tailscale.com/blog/fast-user-switching) then more "brute force" is attempted below... + # https://github.com/tailscale/tailscale/issues/3849 "Please warn that --force-reauth immediately disconnects" (brute force, only as a last resort!) + # https://github.com/tailscale/tailscale/issues/4854 "Tailscale CLI has poor UX with expiring keys" (long-term node keys thankfully mitigate this!) + if ! tailscale up --login-server "$VPN_URL" --auth-key "$VPN_KEY" --force-reauth --timeout 8s; then + echo -e "\n\033[41;1mERROR $?: Failed to connect to VPN, even with --force-reauth\033[0m\n" + exit 1 + fi + fi +fi + +# jq 1.7 (2023-09-05) on new OS's also allows new syntax... jq -r .Node.Tags.[] +# Can also work: tailscale whois --json $(tailscale ip -1) | jq -r .Node.Tags[]) +echo -e "\n\033[44;37mCheck that VPN ($(tailscale status --json | jq -r .Self.Tags[])) is now live:\033[0m\n" +echo -e " hostname -I" +echo -e " tailscale ip" +echo -e " tailscale status" +echo -e " tailscale whois $(tailscale ip -1)" +echo -e " tailscale whois --json $(tailscale ip -1) | jq .Node.Endpoints,.Node.Hostinfo" +echo -e " tailscale ping --verbose [IP or HOSTNAME]" +echo -e " tailscale status --json | jq" +echo -e " systemctl status tailscaled\n" +echo -e "\033[4mTo disconnect from VPN:\033[0m\n" +echo -e " tailscale down\n" +echo -e "\033[4mTo permanently log out of VPN:\033[0m\n" +echo -e " tailscale logout\n" + +# More useful table of IPs/usernames/etc than 'tailscale status' +#echo -e "\033[44;37mVPN peers: (rightmost column = online/offline)\033[0m\n" +#tailscale status --json | jq -r '.Self,.Peer[] | .Tags[] + " " + .TailscaleIPs[] + " " + .HostName + " " + .DNSName + " " + .OS + " " + .Relay + " " + (.Online|tostring)' | sort -V | column -t +#echo -e '\033[44;37mVPN peers: ("true" in 6th column means online)\033[0m\n' +echo -e '\033[44;37mVPN peers: (6th column = online/offline)\033[0m\n' +# (try .Tags[] catch "-") is safer than (.Tags[]? // "-") according to: https://stackoverflow.com/questions/54794749/jq-error-at-stdin0-cannot-iterate-over-null-null +tailscale status --json | jq -r '.Self,.Peer[] | (try .Tags[] catch "-") + " " + .TailscaleIPs[] + " " + .HostName + " " + .DNSName + " " + (if .Relay == "" then "-" else .Relay end) + " XXX" + (.Online|tostring) + "XXX " + .OS' | sort -V | column -t | \ + while read l; do + line=$(echo "$l" | sed 's/ XXXtrueXXX /\\033[0;32m βœ…\\033[0m/ ; s/ XXXfalseXXX /\\033[0;31m ❌ \\033[0m/') + echo -e "$line" $(tailscale whois --json $(echo $line | cut -d' ' -f2) | jq -r '.Node.Hostinfo | .Distro + " " + .DistroVersion + " " + .DeviceModel'); + done +echo diff --git a/roles/tailscale/templates/iiab-vpn-off b/roles/tailscale/templates/iiab-vpn-off new file mode 100755 index 000000000..75ea5c0f3 --- /dev/null +++ b/roles/tailscale/templates/iiab-vpn-off @@ -0,0 +1,7 @@ +#!/bin/bash + +tailscale down + +echo -e "\n\e[44;1mDisconnecting from VPN...\e[0m\n" +echo -e "\e[4mTo permanently log out of VPN:\e[0m\n" # Expires machine node key, from /var/lib/tailscale/tailscaled.state +echo -e " tailscale logout\n" # ...as seen by 'tailscale status --json' (related: 'tailscale debug prefs') diff --git a/roles/transmission/README.rst b/roles/transmission/README.rst index 2de521963..a851fe591 100644 --- a/roles/transmission/README.rst +++ b/roles/transmission/README.rst @@ -15,20 +15,25 @@ Transmission README Transmission is a set of lightweight BitTorrent clients (in GUI, CLI and daemon form). All these incarnations feature a very simple and intuitive interface, on top on an efficient, cross-platform backend: https://transmissionbt.com -Transmission is intended to download KA Lite content to Internet-in-a-Box (IIAB) from places like http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ β€” and also to seed content, assisting others. +Transmission is intended to download content like KA Lite to Internet-in-a-Box (IIAB), from places like https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ β€” and also to seed content, assisting others. For example, once KA Lite videos and thumbnails are confirmed downloaded, copy them (carefully!) from ``/library/transmission`` into ``/library/ka-lite/content`` as outlined by "KA Lite Administration: What tips & tricks exist?" at http://FAQ.IIAB.IO -Caution -------- +Transmission 4.x Preview (Optional) +----------------------------------- -Usage of Transmission consumes significant Internet data and system resources. -Caveat emptor! (That's Latin for "Buyer Beware") +2023-12-31: To make the `latest Transmission features `_ available to you, Internet-in-a-Box can compile the very latest (above and beyond `Transmission 4.x+ official releases `_). Just note this can take most of an hour, and is not without risk! + +If you decide you want this, set ``transmission_compile_latest: True`` in `/etc/iiab/local_vars.yml `_ prior to installing Transmission, as explained below. + +NOTE: Later in 2024, fast auto-installation of `Transmission 4.1+ `_ should once again hopefully become mainline (`#5585 `_, `PR #5866 `_) just as in recent years with Transmission 3.0 (originally from May, 2020). + +.. Transmission can consume significant Internet data and system resources. Caveat emptor! (That's Latin for "Buyer Beware") Using It -------- -Install Transmission by setting 'transmission_install' and 'transmission_enabled' to True in `/etc/iiab/local_vars.yml `_ β€” carefully choosing language(s) for KA Lite videos you want to download β€” and then install IIAB. Or, if IIAB is already installed, run as root:: +Install Transmission by setting ``transmission_install: True`` and ``transmission_enabled: True`` in `/etc/iiab/local_vars.yml `_ β€” carefully choosing language(s) for KA Lite videos you want to download β€” and then install IIAB. Or, if IIAB is already installed, run as root:: cd /opt/iiab/iiab ./runrole transmission @@ -38,7 +43,9 @@ Log in to Transmission's web interface http://box:9091 using administrative acco Username: Admin Password: changeme -If you prefer the command-line, you can instead run `transmission-remote `_ commands. +Change the above password by editing ``rpc-password`` in ``/etc/transmission-daemon/settings.json`` (your plaintext will be hashed to conceal it, the next time Transmission is started). + +Finally if you prefer the command-line, you can instead run `transmission-remote `_ commands. Configuration ------------- @@ -64,9 +71,9 @@ After saving your changes in 'settings.json', restart Transmission by running:: Adding Torrents --------------- -Transmission can facilitate provisioning content onto your IIAB, e.g. by adding thousands of KA Lite videos from places like: http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +Transmission can facilitate provisioning content onto your IIAB, e.g. by adding thousands of KA Lite videos from places like: https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ -Please read the lettered instructions (A, B, C, D) in `/etc/iiab/local_vars.yml `_ and 'KA Lite Administration: What tips & tricks exist?' at http://FAQ.IIAB.IO outlining how to use Transmission to download and then install KA Lite content. +Please read the lettered instructions (A, B, C, D) in `/etc/iiab/local_vars.yml `_ and 'KA Lite Administration: What tips & tricks exist?' at http://FAQ.IIAB.IO outlining how to use Transmission to download and then install KA Lite content. You can also download other torrents using Transmission's web interface, or by typing `transmission-remote `_ at the command-line:: @@ -79,6 +86,8 @@ Known Issues * Random Ports: Currently it is not possible to use random ports in the range 49152-65535, as it's difficult to open multiple ports in IIAB's `iptables-based firewall `_. +* transmission-daemon (4.0.6 or 4.1-dev) install onto Ubuntu 24.04 or 24.10, but (1) its systemd service times out (fails to start) (2) rebooting kinda helps, but service then crashes on 1st visit to http://box:9091 `#3756 `_ + Troubleshooting --------------- @@ -101,19 +110,36 @@ More advanced configuration and status are in directory ``/var/lib/transmission- stats.json torrents/ -These are further explained in https://github.com/transmission/transmission/wiki/Configuration-Files (to align with the above, apt package transmission-daemon sets user debian-transmission's home directory to ``/var/lib/transmission-daemon`` in /etc/passwd). +These are further explained in |ss| https://github.com/transmission/transmission/wiki/Configuration-Files |se| (to align with the above, apt package transmission-daemon sets user debian-transmission's home directory to ``/var/lib/transmission-daemon`` in /etc/passwd). + +Docs +---- + +As of June 2023, these docs appear to be the most up-to-date: + +- https://github.com/transmission/transmission/tree/main/docs + - https://github.com/transmission/transmission/blob/main/docs/Building-Transmission.md + - https://github.com/transmission/transmission/blob/main/docs/Configuration-Files.md + - https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md + - https://github.com/transmission/transmission/blob/main/docs/Headless-Usage.md + - https://github.com/transmission/transmission/blob/main/docs/rpc-spec.md + - https://transmission-rpc.readthedocs.io +- https://cli-ck.io/transmission-cli-user-guide/ (2016 but still useful) + - https://github.com/transmission/transmission#command-line-interface-notes ("``transmission-cli`` is deprecated and exists primarily to support older hardware dependent upon it. In almost all instances, ``transmission-remote`` should be used instead.") +- https://wiki.archlinux.org/title/transmission (updated regularly) +- https://trac.transmissionbt.com/wiki (2006-2019) Logging ------- -To turn on logging and/or record the Process ID (PID), follow these instructions: https://pawelrychlicki.pl/Home/Details/59/transmission-daemon-doesnt-create-a-log-file-nor-a-pid-file-ubuntu-server-1804 +Increase logging by changing transmission-daemon's ``--log-level=error`` to ``--log-level=debug`` in ``/lib/systemd/system/transmission-daemon.service`` -This gives permissions to user ``debian-transmission`` β€” if you use these 3 lines in ``/lib/systemd/system/transmission-daemon.service`` : +(Options are: ``critical``, ``error``, ``warn``, ``info``, ``debug`` or ``trace``) -:: +Then run:: - RuntimeDirectory=transmission-daemon - LogsDirectory=transmission-daemon - ExecStart=/usr/bin/transmission-daemon -f --log-error --log-debug --logfile /var/log/transmission-daemon/transmission.log --pid-file /run/transmission-daemon/transmission.pid + systemctl daemon-reload + systemctl restart transmission-daemon + journalctl -eu transmission-daemon Noting that one should not normally edit files in ``/lib`` or ``/usr/lib`` β€” systemd has a command for customizing unit files: ``systemctl edit --full transmission-daemon.service`` diff --git a/roles/transmission/defaults/main.yml b/roles/transmission/defaults/main.yml index 380ea6048..ab6c3211b 100644 --- a/roles/transmission/defaults/main.yml +++ b/roles/transmission/defaults/main.yml @@ -1,6 +1,7 @@ # Transmission is a BitTorrent downloader for large Content Packs etc # transmission_install: False # transmission_enabled: False +# transmission_compile_latest: False # transmission_username: Admin # transmission_password: changeme @@ -12,11 +13,11 @@ # Monitor downloads at http://box:9091 or http://box:9091/transmission using Admin/changeme # transmission_http_port: 9091 # transmission_url: /transmission/ -# transmission_whitelist: 127.0.0.1,::1,192.168.*.*,172.18.96.*,10.8.0.* +# transmission_whitelist: 127.0.0.1,::1,192.168.*.*,10.10.10.*,172.18.96.*,10.8.0.* # transmission_whitelist_enabled: "false" # LOWERCASE STRING for settings.json # transmission_peer_port: 51413 -# Provision Transmission with torrent(s) from http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# Provision Transmission with torrent(s) from https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ # transmission_provision: True # transmission_kalite_version: 0.17 diff --git a/roles/transmission/tasks/enable-or-disable.yml b/roles/transmission/tasks/enable-or-disable.yml index 8804c5b17..c62a2edda 100644 --- a/roles/transmission/tasks/enable-or-disable.yml +++ b/roles/transmission/tasks/enable-or-disable.yml @@ -14,7 +14,7 @@ /usr/bin/transmission-remote --start-paused -n {{ transmission_username }}:{{ transmission_password }} - -a http://pantry.learningequality.org/downloads/ka-lite/{{ transmission_kalite_version }}/content/ka-lite-0.17-resized-videos-{{ item }}.torrent + -a https://pantry.learningequality.org/downloads/ka-lite/{{ transmission_kalite_version }}/content/ka-lite-0.17-resized-videos-{{ item }}.torrent with_items: "{{ transmission_kalite_languages }}" when: transmission_enabled and transmission_provision and transmission_kalite_languages is defined and transmission_kalite_languages is not none # '!= None' also works (i.e. to avoid var value 'null', with type 'NoneType') ignore_errors: yes diff --git a/roles/transmission/tasks/install.yml b/roles/transmission/tasks/install.yml index 015116b82..ae3c8cd72 100644 --- a/roles/transmission/tasks/install.yml +++ b/roles/transmission/tasks/install.yml @@ -1,3 +1,8 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: "Install BitTorrent packages: transmission-daemon, transmission-cli" package: name: @@ -5,13 +10,59 @@ - transmission-cli state: present + +- block: + + - name: "TRY TO COMPILE & INSTALL very latest Transmission, installing ~5 binaries in /usr/local/bin to take precedence over above ~6 binaries in /usr/bin (attempt surgery on systemd unit file from apt install above!)" + meta: noop + + # https://github.com/transmission/transmission/blob/main/docs/Building-Transmission.md#on-unix + # https://github.com/transmission/transmission/issues/5362 tips thanks to @tearfur + - name: apt install build-essential cmake libcurl4-openssl-dev libssl-dev libsystemd-dev # git python3 + package: + name: + - build-essential + - cmake + - libcurl4-openssl-dev + - libssl-dev + - libsystemd-dev + state: present + + - name: Git clone https://github.com/transmission/transmission to /opt/iiab/transmission + git: + repo: https://github.com/transmission/transmission + dest: /opt/iiab/transmission + #version: 4.0.x # Otherwise default branch 'main' + depth: 1 + force: yes + + # https://github.com/transmission/transmission/blob/main/docs/Building-Transmission.md#building-transmission-from-git-first-time + - name: Compile, install & remove detritus (CAN TAKE 60+ MINUTES ON RASPBERRY PI 4!) + shell: | + cd /opt/iiab/transmission + git submodule update --init --recursive + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + make + make install + cd + rm -rf /opt/iiab/transmission # 2023-06-12: Frees up 1.1 GB on 32-bit RasPiOS. Frees up 1.6 GB on 64-bit RasPiOS. + + - name: Attempt surgery on /lib/systemd/system/transmission-daemon.service (1) changing --log-error to --log-level=error (2) changing /usr/bin/transmission* to /usr/local/bin/transmission* + shell: | + sed -i 's/--log-error/--log-level=error/' /lib/systemd/system/transmission-daemon.service # --log-error deprecated since ~2020 + sed -i 's#/usr/bin/transmission#/usr/local/bin/transmission#' /lib/systemd/system/transmission-daemon.service # daemon_reload handled by enable-or-disable.yml + + when: transmission_compile_latest + + - name: Create download dir {{ transmission_download_dir }}, owned by {{ transmission_user }}:{{ transmission_group }} file: state: directory path: "{{ transmission_download_dir }}" # /library/transmission owner: "{{ transmission_user }}" # debian-transmission group: "{{ transmission_group }}" # debian-transmission - # mode: '0755' - name: Stop 'transmission-daemon' systemd service, before modifying its settings systemd: @@ -19,7 +70,10 @@ state: stopped ignore_errors: yes -- name: Back up prior /etc/transmission-daemon/settings.json (original file from apt, or new symlink contents) to /etc/transmission-daemon/settings.json.old* +# 'transmission-daemon -d' (--dump-settings) CAN GENERATE A NEW settings.json +# ...then customize ~8 var lines to create a new templates/settings.json.j2 + +- name: Back up prior /etc/transmission-daemon/settings.json (file originally from apt, or new symlink contents) to /etc/transmission-daemon/settings.json.old* copy: src: /etc/transmission-daemon/settings.json dest: /etc/transmission-daemon/settings.json.old @@ -48,13 +102,24 @@ - name: "Reverse Transmission's fragile OOTB symlink -- instead we establish /etc/transmission-daemon/settings.json -> /var/lib/transmission-daemon/.config/transmission-daemon/settings.json -- REASON: /etc/transmission-daemon/settings.json was intermittently being IGNORED, as Transmission sometimes breaks its own symlink from /var/lib/transmission-daemon/.config/transmission-daemon/settings.json (by turning it into a file instead)" file: path: /etc/transmission-daemon/settings.json - src: /var/lib/transmission-daemon/.config/transmission-daemon/settings.json + src: /var/lib/transmission-daemon/.config/transmission-daemon/settings.json # Symlink /var/lib/transmission-daemon/home/settings.json also points to this state: link force: yes # RECORD Transmission AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'transmission_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: transmission + option: transmission_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'transmission_installed: True'" set_fact: transmission_installed: True diff --git a/roles/transmission/tasks/main.yml b/roles/transmission/tasks/main.yml index c2f599628..bee271ab3 100644 --- a/roles/transmission/tasks/main.yml +++ b/roles/transmission/tasks/main.yml @@ -19,49 +19,56 @@ quiet: yes -- name: Install Transmission if 'transmission_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: transmission_installed is undefined +- block: + - name: Install Transmission if 'transmission_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: transmission_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'transmission' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: transmission + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Transmission + - option: description + value: '"Transmission is a set of lightweight BitTorrent clients (in GUI, CLI and daemon form)."' + - option: transmission_install + value: "{{ transmission_install }}" + - option: transmission_enabled + value: "{{ transmission_enabled }}" + - option: transmission_download_dir + value: "{{ transmission_download_dir }}" + - option: transmission_user + value: "{{ transmission_user }}" + - option: transmission_group + value: "{{ transmission_group }}" + - option: transmission_http_port + value: "{{ transmission_http_port }}" + - option: transmission_url + value: "{{ transmission_url }}" + - option: transmission_peer_port + value: "{{ transmission_peer_port }}" + - option: transmission_provision + value: "{{ transmission_provision }}" + - option: transmission_kalite_version + value: "{{ transmission_kalite_version }}" + - option: transmission_kalite_languages + value: "{{ transmission_kalite_languages }}" + - option: transmission_username + value: "{{ transmission_username }}" + # 2020-04-14: better to redact passwords from /etc/iiab/iiab.ini etc, so iiab-diagnostics command doesn't publish these, etc + #- option: transmission_password + # value: "{{ transmission_password }}" -- name: Add 'transmission' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: transmission - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Transmission - - option: description - value: '"Transmission is a set of lightweight BitTorrent clients (in GUI, CLI and daemon form)."' - - option: transmission_install - value: "{{ transmission_install }}" - - option: transmission_enabled - value: "{{ transmission_enabled }}" - - option: transmission_download_dir - value: "{{ transmission_download_dir }}" - - option: transmission_user - value: "{{ transmission_user }}" - - option: transmission_group - value: "{{ transmission_group }}" - - option: transmission_http_port - value: "{{ transmission_http_port }}" - - option: transmission_url - value: "{{ transmission_url }}" - - option: transmission_peer_port - value: "{{ transmission_peer_port }}" - - option: transmission_provision - value: "{{ transmission_provision }}" - - option: transmission_kalite_version - value: "{{ transmission_kalite_version }}" - - option: transmission_kalite_languages - value: "{{ transmission_kalite_languages }}" - - option: transmission_username - value: "{{ transmission_username }}" - # 2020-04-14: better to redact passwords from /etc/iiab/iiab.ini etc, so iiab-diagnostics command doesn't publish these, etc - #- option: transmission_password - # value: "{{ transmission_password }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/usb_lib/README.rst b/roles/usb_lib/README.rst index 439fa9c86..b7536387c 100644 --- a/roles/usb_lib/README.rst +++ b/roles/usb_lib/README.rst @@ -2,30 +2,34 @@ usb_lib README ============== -**PLEASE SEE "Can teachers display their own content?" WITHIN http://FAQ.IIAB.IO FOR UP-TO-DATE DOCUMENTATION.** +**PLEASE SEE** `"Can teachers display their own content?" `_ **AND** `"Can students upload their own work?" `_ **WITHIN https://FAQ.IIAB.IO FOR UP-TO-DATE DOCUMENTATION!** -This role implements functionality similar to LibraryBox, to mount "teacher content" from USB drives. +This role (1) implements functionality similar to LibraryBox, to mount "teacher content" from USB sticks / drives for students, and (2) allows students to upload their work to the teacher's USB stick / drive: -Users should have nearly immediate access to this "teacher content" (on all inserted USB drives) by browsing to http://box/usb +#. Students should have nearly immediate access to "teacher content" (on all inserted USB sticks) by browsing to http://box/usb. +#. Students can also click the "Upload to USB" button on top of this same page (http://box/usb), to upload their work to the teacher's USB stick. (FYI student uploads appear in folders like ``UPLOADS.YYYY-MM-DD`` within the root of the teacher's USB stick). -Automount is handled by usbmount, and scripts in this role look in the root of the mounted drive for... +As of January 2025, automount is handled by usbmount: (`devmon included with udevil `_ might be considered in future) -* /usb -* /USB -* /share -* /Share -* /Piratebox/Share +* A script in this role (/etc/usbmount/mount.d/70-usb-library) looks in the root of the mounted USB stick for folder /PUBLIC and if found, creates a symlink of the form /library/www/html/local_content/USBn pointing to /media/usbn/PUBLIC β€” where n is generally one of {0, 1, 2, 3, 4, 5, 6, 7}. *RESULT: Only documents within /PUBLIC are browsable by students.* This option is very useful to **prevent students from copying uploaded homework!** +* If however folder /PUBLIC is not found, the symlink is created to the root of the mounted USB stick. *RESULT: EVERYTHING on the USB stick is browsable by students β€” just like with a traditional community bulletin board.* This option is very useful when students are uploading artwork, photo essays, personal audio recordings and **science projects that are intended to be shared!** -...and if found, creates a symlink of the form /library/www/html/local_content/USBn pointing to /media/usbn β€” where n is generally one of {0, 1, 2, 3, 4, 5, 6, 7}. +Technical Details: -USB drives must be formatted with one of the filesystems listed under "FILESYSTEMS=" at ``/etc/usbmount/usbmount.conf`` β€” these are specified on/around Line 76 of: `/opt/iiab/iiab/roles/usb_lib/tasks/install.yml `_ +* USB sticks / drives must be formatted with one of the filesystems listed under "FILESYSTEMS=" at ``/etc/usbmount/usbmount.conf`` β€” these are specified on/around Line 17 of: `/opt/iiab/iiab/roles/usb_lib/files/usbmount/usbmount.conf `_ -IIAB will generally mount USB drives 'rw' allowing root to both read and write to them. In addition, in March 2021 (`PR #2715 `_) Kolibri exports were enabled by also giving non-root users read and write access to VFAT/FAT32, NTFS and exFAT USB drives, using ``umask=0000`` (in /etc/usbmount/usbmount.conf) to override the ``umask=0022`` default. If however you prefer to restore usbmount's default, set ``usb_lib_umask0000_for_kolibri: False`` in `/etc/iiab/local_vars.yml `_ (preferably do this prior to installing IIAB). +* If your IIAB was built on a Graphical Desktop OS (instead of a headless OS, like Raspberry Pi OS Lite), USB sticks will problematically be mounted twice by default, once by usbmount and once by the desktop. You must disable the automount function in the Desktop in order to use the "Upload to USB" functionality, which allows students to upload their work to your USB stick. -Official `usbmount 0.0.22 (2011-08-08) `_ documentation: + * EXAMPLE: To disable Desktop automount within "Raspberry Pi OS with desktop", go to File Manager (pcmanfm) β†’ Edit β†’ Preferences β†’ Volume Management, and uncheck "Mount removable media automatically when they are inserted". -* https://github.com/hfuchs/usbmount/blob/master/README (2010-08-11) -* https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10) -* https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25) +* IIAB will generally mount USB sticks / drives 'rw' allowing root to both read and write to them. In addition, in March 2021 (`PR #2715 `_) Kolibri exports were enabled, by also giving non-root users read and write access to VFAT/FAT32, NTFS and exFAT USB sticks β€” using ``umask=0000`` (in /etc/usbmount/usbmount.conf) to override the ``umask=0022`` default. This ``umask=0000`` is also required for students to upload to the teachers's VFAT/FAT32, NTFS and exFAT USB sticks, as introduced in January 2025 (`PR #3875 `_). If, however, you prefer to restore usbmount's default, set ``usb_lib_writable_sticks: False`` in `/etc/iiab/local_vars.yml `_ β€” please do this prior to installing IIAB β€” so you don't have to run: ``cd /opt/iiab/iiab ; ./runrole --reinstall usb_lib`` -Legacy warning: There is also a patch for problems with automount on Fedora 21+. Please note that as of 4.1.8-200.fc22.x86_64 not all USB drives will mount, even with this patch. +* Official `usbmount 0.0.22 (2011-08-08) `_ documentation: + + * https://github.com/hfuchs/usbmount/blob/master/README (2010-08-11) + * https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10) + * https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25) + +* Dev Notes at the top of: https://github.com/iiab/iiab/blob/master/roles/usb_lib/tasks/install.yml + + * January 2025 work to improve automount reliability during boot: `PR #3916 `_ diff --git a/roles/usb_lib/defaults/main.yml b/roles/usb_lib/defaults/main.yml index 2a4b19308..f7cbf10b6 100644 --- a/roles/usb_lib/defaults/main.yml +++ b/roles/usb_lib/defaults/main.yml @@ -1,12 +1,9 @@ # usb_lib_install: True # usb_lib_enabled: True -# Show entire contents of USB sticks/drives (at http://box/usb) -# iiab_usb_lib_show_all: True - -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -# usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +# usb_lib_writable_sticks: True # All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! diff --git a/roles/usb_lib/files/upload2usb/button.html b/roles/usb_lib/files/upload2usb/button.html new file mode 100644 index 000000000..52cc493ce --- /dev/null +++ b/roles/usb_lib/files/upload2usb/button.html @@ -0,0 +1,19 @@ + +Upload to USB diff --git a/roles/usb_lib/files/upload2usb/error.php b/roles/usb_lib/files/upload2usb/error.php new file mode 100644 index 000000000..46dd0e667 --- /dev/null +++ b/roles/usb_lib/files/upload2usb/error.php @@ -0,0 +1,15 @@ + +ERROR: Please make sure one and ONLY one (no more, no less) removable USB stick is plugged into your Internet-in-a-Box. Please see IIAB FAQ, "Can students upload their own work?", for additional support. + +

+ +
+ + + diff --git a/roles/usb_lib/files/upload2usb/footer.php b/roles/usb_lib/files/upload2usb/footer.php new file mode 100644 index 000000000..2e1fef0f7 --- /dev/null +++ b/roles/usb_lib/files/upload2usb/footer.php @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/roles/usb_lib/files/upload2usb/header.php b/roles/usb_lib/files/upload2usb/header.php new file mode 100644 index 000000000..ef75c2c01 --- /dev/null +++ b/roles/usb_lib/files/upload2usb/header.php @@ -0,0 +1,32 @@ + + + + + + + <?php echo $title ?> + + + + + + + + + + +
+
+
+ + +

diff --git a/roles/usb_lib/files/upload2usb/index.php b/roles/usb_lib/files/upload2usb/index.php new file mode 100644 index 000000000..6eab98dbf --- /dev/null +++ b/roles/usb_lib/files/upload2usb/index.php @@ -0,0 +1,24 @@ + + + +
+

+ + +
+ files have been uploaded today! + + + \ No newline at end of file diff --git a/roles/usb_lib/files/upload2usb/uk-swing.png b/roles/usb_lib/files/upload2usb/uk-swing.png new file mode 100644 index 000000000..c5470365e Binary files /dev/null and b/roles/usb_lib/files/upload2usb/uk-swing.png differ diff --git a/roles/usb_lib/files/upload2usb/upload-file.php b/roles/usb_lib/files/upload2usb/upload-file.php new file mode 100644 index 000000000..8c81c731d --- /dev/null +++ b/roles/usb_lib/files/upload2usb/upload-file.php @@ -0,0 +1,58 @@ +". htmlspecialchars( $uploaded_filename ). " was successfully uploaded!"; + } else { + $upload_ok = 0; + throw new RuntimeException('There was an error uploading your file.

'); + } +} + +$file_count = getFileCount($target_folder_path); + +?> + +
+ files have been uploaded today! + + + + diff --git a/roles/usb_lib/files/upload2usb/upload2usb.php b/roles/usb_lib/files/upload2usb/upload2usb.php new file mode 100644 index 000000000..555a40f5a --- /dev/null +++ b/roles/usb_lib/files/upload2usb/upload2usb.php @@ -0,0 +1,101 @@ +1 otherwise return upload path + + # error if 1<>usb sticks are installed + $rmv_usb_path_count = shell_exec('lsblk --output NAME,TRAN,RM,MOUNTPOINT --pairs | cut -d " " -f 4 | grep "^MOUNTPOINT=\"/media" | wc -l'); + + if ($rmv_usb_path_count == 0) { + throw new RuntimeException('0 USB sticks found.

'); + } elseif ($rmv_usb_path_count > 1) { + throw new RuntimeException('More than 1 USB sticks installed.

'); + } + + $rmv_usb_path = trim(str_replace('"', '', shell_exec('lsblk --output NAME,TRAN,RM,MOUNTPOINT --pairs | cut -d " " -f 4 | grep "^MOUNTPOINT=\"/media" | cut -d "=" -f 2'))); + + if (empty($rmv_usb_path)) { + throw new RuntimeException('Not able to find USB stick.

'); + } else { + return $rmv_usb_path . "/"; + } +} + +//returns folder path where file will be stored, if create_folder_p = 1, it will create the folder if it doesn't exist +function getTargetFolderPath ($create_folder_p) { + $parent_dir = getTargetUSBDriveLocation(); + + $today_folder_name = "UPLOADS." . date("Y-m-d"); + $target_folder_path = $parent_dir . $today_folder_name; + + if (!file_exists($target_folder_path) && $create_folder_p) { + mkdir($target_folder_path, 0777) or throw new RuntimeException("Not able to create upload directory.
Make sure 'usb_lib_writable_sticks' is set to 'True'.

"); + } + return $target_folder_path; +} + +//return number of files within a specified folder +function getFileCount ($folder_path) { + return count(glob($folder_path . "/*")); +} + +//check if file mimetype is acceptable for upload +function isFileMimeTypeAcceptable ($file) { + $mimetype = strtolower(mime_content_type($file)); + $invalid_mimetypes_str = array ("compress", "image/svg+xml", "octet", "text/xml", "xhtml+xml"); + foreach ($invalid_mimetypes_str as $invalid_mt_str) { + if (str_contains($mimetype, $invalid_mt_str)) { + error_log('UPLOAD2USB ERROR - MIMETYPE: ' . $mimetype); + return false; + } + } + return true; +} + +//check file content to see if it's unique or not +function isFileContentUnique ($target_folder_path, $file) { + $file_to_upload_md5 = md5_file($file); + $usb_dir = array_diff(scandir($target_folder_path), array('..', '.')); + foreach ($usb_dir as $dir_file) { + $dir_file = $target_folder_path . "/" . $dir_file; + + if (!is_dir($dir_file)) { + $dir_file_md5 = md5_file($dir_file); + if ($file_to_upload_md5 == $dir_file_md5) { + return false; + } + } + } + return true; +} + +//return unique filename +function getUniqueFileName ($target_folder_path, $filename) { + $new_filename = $filename; + $counter = 1; + while (file_exists($target_folder_path . "/" . $new_filename)) { + $counter++; + $new_filename = pathinfo($filename,8) . '-'. $counter . "." . pathinfo($filename,4); + } + return $new_filename; +} + +// Check file size - we are not going to check file size for now. +// elseif ($_FILES["uploaded_file"]["size"] > 5000000) { +// $upload_msg = "Your file is too large."; +// $upload_ok = 0; +// } + + +?> diff --git a/roles/usb_lib/files/usbmount/copyright b/roles/usb_lib/files/usbmount/copyright new file mode 100644 index 000000000..75fae2dde --- /dev/null +++ b/roles/usb_lib/files/usbmount/copyright @@ -0,0 +1,17 @@ +Format: http://dep.debian.net/deps/dep5/ +Upstream-Name: usbmount +Upstream-Contact: Martin Dickopp , RogΓ©rio Brito +Source: git://git.debian.org/usbmount/usbmount.git + +Files: * +Copyright: 2004-2007, Martin Dickopp + 2008-2011, RogΓ©rio Brito +License: BSD-2 + This package is free software; the copyright holder gives unlimited + permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY, to the extent permitted by law; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. diff --git a/roles/usb_lib/files/usbmount/usbmount b/roles/usb_lib/files/usbmount/usbmount new file mode 100644 index 000000000..8104564e7 --- /dev/null +++ b/roles/usb_lib/files/usbmount/usbmount @@ -0,0 +1,235 @@ +#!/bin/sh +# This script mounts USB mass storage devices when they are plugged in +# and unmounts them when they are removed. +# Copyright Β© 2004, 2005 Martin Dickopp +# Copyright Β© 2008, 2009, 2010 RogΓ©rio Theodoro de Brito +# Copyright Β© 2025, Jerry Vonau +# +# This file is free software; the copyright holder gives unlimited +# permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. +# https://github.com/iiab/iiab/blob/master/roles/usb_lib/files/usbmount/copyright +# https://github.com/rbrito/usbmount/blob/master/debian/copyright +#set -e +exec > /dev/null 2>&1 + +###################################################################### +# Auxiliary functions + +# Log a string via the syslog facility. +log() +{ + if [ $1 != debug ] || expr "$VERBOSE" : "[yY]" > /dev/null; then + logger -p user.$1 -t "usbmount[$$]" -- "$2" + fi +} + + +# Test if the first parameter is in the list given by the second +# parameter. +in_list() +{ + for v in $2; do + [ "$1" != "$v" ] || return 0 + done + return 1 +} + + +###################################################################### +# Main program + +# Default values for configuration variables. +ENABLED=1 +MOUNTPOINTS= +FILESYSTEMS= +MOUNTOPTIONS= +FS_MOUNTOPTIONS= +VERBOSE=no + +if [ -r /etc/usbmount/usbmount.conf ]; then + . /etc/usbmount/usbmount.conf + log debug "loaded usbmount configurations" +fi + +if [ "${ENABLED:-1}" -eq 0 ]; then + log info "usbmount is disabled, see /etc/usbmount/usbmount.conf" + exit 0 +fi + +if [ ! -x /sbin/blkid ]; then + log err "cannot execute /sbin/blkid" + exit 1 +fi + +if [ "$1" = add ]; then + + # Per Policy 9.3.2, directories under /var/run have to be created + # after every reboot. + if [ ! -e /var/run/usbmount ]; then + mkdir -p /var/run/usbmount + log debug "creating /var/run/usbmount directory" + else + log debug "/var/run/usbmount exists" + fi + + umask 022 + + # Acquire lock. + log debug "trying to acquire lock /var/run/usbmount/.mount.lock" + lockfile-create --retry 6 /var/run/usbmount/.mount || \ + { log err "cannot acquire lock /var/run/usbmount/.mount.lock"; exit 1; } + trap '( lockfile-remove /var/run/usbmount/.mount )' 0 + log debug "acquired lock /var/run/usbmount/.mount.lock" + + # Grab device information from device and "divide it" + # FIXME: improvement: implement mounting by label (notice that labels + # can contain spaces, which makes things a little bit less comfortable). + DEVINFO=$(/sbin/blkid -p $DEVNAME) + FSTYPE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]TYPE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') + UUID=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]UUID="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') + USAGE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]USAGE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') + + if ! echo $USAGE | egrep -q "(filesystem|disklabel)"; then + log debug "/$DEVNAME does not contain a filesystem or disklabel" + lockfile-remove /var/run/usbmount/.mount + exit + fi + + log debug "/$DEVNAME contains filesystem type $FSTYPE" + BOOTFW_DEV=$(/usr/bin/findmnt -no source /boot/firmware) + log debug "BOOTFW_DEV $BOOTFW_DEV" + ROOT_DEV=$(/usr/bin/findmnt -no source /) + log debug "ROOT_DEV $ROOT_DEV" + BOOT_DEV=$(/usr/bin/findmnt -no source /boot) + log debug "BOOT_DEV $BOOT_DEV" + + if [ $BOOTFW_DEV = /$DEVNAME ]; then + log debug "skipping BOOTFS_DEV $BOOTFS_DEV mounted at /boot/firmware" + lockfile-remove /var/run/usbmount/.mount + exit + elif [ $ROOT_DEV = /$DEVNAME ]; then + log debug "skipping ROOT_DEV $ROOT_DEV mounted at /" + lockfile-remove /var/run/usbmount/.mount + exit + elif [ $BOOT_DEV = /$DEVNAME ]; then + log debug "skipping BOOT_DEV $BOOT_DEV mount as /boot" + lockfile-remove /var/run/usbmount/.mount + exit + fi + + # Try to use specifications in /etc/fstab to skip. + if egrep -q "^[[:blank:]]*$DEVNAME" /etc/fstab; then + log debug "skipping /$DEVNAME exit" + lockfile-remove /var/run/usbmount/.mount + exit + elif grep -q "^[[:blank:]]*UUID=$UUID" /etc/fstab; then + log debug "skipping $UUID" + lockfile-remove /var/run/usbmount/.mount + exit + else + log debug "/$DEVNAME contains filesystem type $FSTYPE" + fstype=$FSTYPE + # Test if the filesystem type is in the list of filesystem + # types to mount. + if in_list "$fstype" "$FILESYSTEMS"; then + # Search an available mountpoint. + for v in $MOUNTPOINTS; do + if [ -d "$v" ] && ! grep -q "^[^ ][^ ]* *$v " /proc/mounts; then + mountpoint="$v" + log debug "mountpoint $mountpoint is available for /$DEVNAME" + break + fi + done + if [ -n "$mountpoint" ]; then + # Determine mount options. + options= + for v in $FS_MOUNTOPTIONS; do + if expr "$v" : "-fstype=$fstype,."; then + options="$(echo "$v" | sed 's/^[^,]*,//')" + break + fi + done + if [ -n "$MOUNTOPTIONS" ]; then + options="$MOUNTOPTIONS${options:+,$options}" + fi + + # Mount the filesystem. + log info "executing command: mount -t$fstype ${options:+-o$options} $DEVNAME $mountpoint" + mount "-t$fstype" "${options:+-o$options}" "$DEVNAME" "$mountpoint" + + # Determine vendor and model. + vendor= + if [ -r "/sys$DEVPATH/device/vendor" ]; then + vendor="`cat \"/sys$DEVPATH/device/vendor\"`" + elif [ -r "/sys$DEVPATH/../device/vendor" ]; then + vendor="`cat \"/sys$DEVPATH/../device/vendor\"`" + elif [ -r "/sys$DEVPATH/device/../manufacturer" ]; then + vendor="`cat \"/sys$DEVPATH/device/../manufacturer\"`" + elif [ -r "/sys$DEVPATH/../device/../manufacturer" ]; then + vendor="`cat \"/sys$DEVPATH/../device/../manufacturer\"`" + fi + vendor="$(echo "$vendor" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" + + model= + if [ -r "/sys$DEVPATH/device/model" ]; then + model="`cat \"/sys$DEVPATH/device/model\"`" + elif [ -r "/sys$DEVPATH/../device/model" ]; then + model="`cat \"/sys$DEVPATH/../device/model\"`" + elif [ -r "/sys$DEVPATH/device/../product" ]; then + model="`cat \"/sys$DEVPATH/device/../product\"`" + elif [ -r "/sys$DEVPATH/../device/../product" ]; then + model="`cat \"/sys$DEVPATH/../device/../product\"`" + fi + model="$(echo "$model" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" + + # Run hook scripts; ignore errors. + export UM_DEVICE="$DEVNAME" + export UM_MOUNTPOINT="$mountpoint" + export UM_FILESYSTEM="$fstype" + export UM_MOUNTOPTIONS="$options" + export UM_VENDOR="$vendor" + export UM_MODEL="$model" + log info "executing command: run-parts /etc/usbmount/mount.d" + run-parts /etc/usbmount/mount.d || : + else + # No suitable mount point found. + log warning "no mountpoint found for $DEVNAME" + exit 1 + fi + fi +fi +elif [ "$1" = remove ]; then + + # A block or partition device has been removed. + # Test if it is mounted. + while read device mountpoint fstype remainder; do + if [ "$DEVNAME" = "$device" ]; then + # If the mountpoint and filesystem type are maintained by + # this script, unmount the filesystem. + if in_list "$mountpoint" "$MOUNTPOINTS" && + in_list "$fstype" "$FILESYSTEMS"; then + log info "executing command: umount -l $mountpoint" + umount -l "$mountpoint" + + # Run hook scripts; ignore errors. + export UM_DEVICE="$DEVNAME" + export UM_MOUNTPOINT="$mountpoint" + export UM_FILESYSTEM="$fstype" + log info "executing command: run-parts /etc/usbmount/umount.d" + run-parts /etc/usbmount/umount.d || : + fi + break + fi + done < /proc/mounts +else + log err "unexpected: action '$1'" + exit 1 +fi + +log debug "usbmount execution finished" diff --git a/roles/usb_lib/files/usbmount/usbmount.conf b/roles/usb_lib/files/usbmount/usbmount.conf new file mode 100644 index 000000000..7bd194873 --- /dev/null +++ b/roles/usb_lib/files/usbmount/usbmount.conf @@ -0,0 +1,53 @@ +# Configuration file for the usbmount package, which mounts removable +# storage devices when they are plugged in and unmounts them when they +# are removed. + +# Change to zero to disable usbmount +ENABLED=1 + +# Mountpoints: These directories are eligible as mointpoints for +# removable storage devices. A newly plugged in device is mounted on +# the first directory in this list that exists and on which nothing is +# mounted yet. +MOUNTPOINTS="/media/usb0 /media/usb1 /media/usb2 /media/usb3 + /media/usb4 /media/usb5 /media/usb6 /media/usb7" + +# Filesystem types: removable storage devices are only mounted if they +# contain a filesystem type which is in this list. +FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs" + +############################################################################# +# WARNING! # +# # +# The "sync" option may not be a good choice to use with flash drives, as # +# it forces a greater amount of writing operating on the drive. This makes # +# the writing speed considerably lower and also leads to a faster wear out # +# of the disk. # +# # +# If you omit it, don't forget to use the command "sync" to synchronize the # +# data on your disk before removing the drive or you may experience data # +# loss. # +# # +# It is highly recommended that you use the pumount command (as a regular # +# user) before unplugging the device. It makes calling the "sync" command # +# and mounting with the sync option unnecessary---this is similar to other # +# operating system's "safely disconnect the device" option. # +############################################################################# +# Mount options: Options passed to the mount command with the -o flag. +# See the warning above regarding removing "sync" from the options. +MOUNTOPTIONS="sync,noexec,nodev,noatime,nodiratime" + +# Filesystem type specific mount options: This variable contains a space +# separated list of strings, each which the form "-fstype=TYPE,OPTIONS". +# +# If a filesystem with a type listed here is mounted, the corresponding +# options are appended to those specificed in the MOUNTOPTIONS variable. +# +# For example, "-fstype=vfat,gid=floppy,dmask=0007,fmask=0117" would add +# the options "gid=floppy,dmask=0007,fmask=0117" when a vfat filesystem +# is mounted. +FS_MOUNTOPTIONS="" + +# If set to "yes", more information will be logged via the syslog +# facility. +VERBOSE=yes diff --git a/roles/usb_lib/tasks/install.yml b/roles/usb_lib/tasks/install.yml index c34042781..660df7eb2 100644 --- a/roles/usb_lib/tasks/install.yml +++ b/roles/usb_lib/tasks/install.yml @@ -1,9 +1,22 @@ +# usbmount 0.0.24 and/or 0.0.25 (2022-02-08) should be investigated: +# https://github.com/iiab/iiab/issues/3409 + # Official usbmount 0.0.22 (2011-08-08) documentation: # https://github.com/rbrito/usbmount/releases # https://github.com/hfuchs/usbmount/blob/master/README (2010-08-11) # https://github.com/rbrito/usbmount/blob/master/README.md (2018-08-10) # https://github.com/rbrito/usbmount/blob/master/usbmount.conf (2010-04-25) +# The variable, usb_lib_writable_sticks (e.g., in /etc/iiab/local_vars.yml), must be set to true +# in order for non-root users to be able to write to VFAT/FAT32, NTFS and exFAT USB sticks. +# If you are still not able to write to a mounted USB stick, try unmounting the drive +# (sudo umount ) and then remount it setting umask to 0000 manually (sudo mount -o umask=0000 ). + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Does systemd-udevd.service exist stat: path: "{{ systemd_location }}/systemd-udevd.service" @@ -34,28 +47,54 @@ state: restarted when: udev_unit.stat.exists is defined and udev_unit.stat.exists -#http://raspbian.raspberrypi.org/raspbian/pool/main/u/usbmount/usbmount_0.0.22_all.deb -- name: Install {{ iiab_download_url }}/usbmount_0.0.22_all.deb, missing from Debian - apt: - deb: "{{ iiab_download_url }}/usbmount_0.0.22_all.deb" - when: is_debian +# http://raspbian.raspberrypi.org/raspbian/pool/main/u/usbmount/usbmount_0.0.22_all.deb +#- name: Install {{ iiab_download_url }}/usbmount_0.0.22_all.deb, no longer supported by {RasPiOS, Debian, Ubuntu} +# apt: +# deb: "{{ iiab_download_url }}/usbmount_0.0.22_all.deb" +# # when: is_debian -# check status of usbmount on mintlinux - should be ok Ubuntu variant -- name: Install usbmount from OS repo for Ubuntu variants +- name: Install lockfile-progs and util-linux (findmnt blkid) for usbmount from OS repo package: - name: usbmount + name: + - lockfile-progs + - util-linux state: present - when: is_ubuntu -- name: Add dir {{ doc_root }}/local_content, where USB drive links can appear (0775) +- name: Add dir {{ doc_root }}/local_content, where USB drive links can appear (0775) owned by {{ apache_user }}:{{ apache_user }} file: state: directory - path: "{{ doc_root }}/local_content" - owner: "{{ apache_user }}" + path: "{{ doc_root }}/local_content" # /library/www/html + owner: "{{ apache_user }}" # www-data group: "{{ apache_user }}" # 2020-02-13: changed from iiab_admin_user, after discussion on weekly call (#1228, #2222) mode: 0775 -- name: 'Install from template: /etc/udev/rules.d/usbmount.rules, /etc/systemd/system/usbmount@.service, /usr/bin/iiab-usb_lib-show-all-on, /usr/bin/iiab-usb_lib-show-all-off, /usr/sbin/iiab-clean-usb.sh' +- name: Set up dirs /etc/usbmount/mount.d, /etc/usbmount/umount.d, /media/usb0-7 + file: + state: directory + path: "{{ item }}" + mode: 0755 + with_items: + - /etc/usbmount/mount.d + - /etc/usbmount/umount.d + - /media/usb0 + - /media/usb1 + - /media/usb2 + - /media/usb3 + - /media/usb4 + - /media/usb5 + - /media/usb6 + - /media/usb7 + +- name: Copy files from files/usbmount to filesystem + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + with_items: + - { src: 'usbmount/usbmount.conf', dest: '/etc/usbmount/', mode: '0644' } + - { src: 'usbmount/usbmount', dest: '/usr/local/sbin/', mode: '0755' } + +- name: 'Install from template: /etc/udev/rules.d/usbmount.rules, /etc/systemd/system/usbmount@.service, /usr/local/sbin/iiab-clean-usb.sh' template: src: "{{ item.src }}" dest: "{{ item.dest }}" @@ -63,27 +102,51 @@ with_items: - { src: 'usbmount.rules.j2', dest: '/etc/udev/rules.d/usbmount.rules', mode: '0644' } - { src: 'usbmount@.service.j2', dest: '/etc/systemd/system/usbmount@.service', mode: '0644' } - - { src: 'iiab-usb_lib-show-all-on', dest: '/usr/bin/', mode: '0755' } - - { src: 'iiab-usb_lib-show-all-off', dest: '/usr/bin/', mode: '0755' } - - { src: 'iiab-clean-usb.sh', dest: '/usr/sbin/', mode: '0755' } + - { src: 'iiab-clean-usb.sh', dest: '/usr/local/sbin/', mode: '0755' } + +- name: Add dir {{ doc_root }}/upload2usb (0775) owned by {{ apache_user }}:{{ apache_user }} + file: + state: directory + path: "{{ doc_root }}/upload2usb" + owner: "{{ apache_user }}" + group: "{{ apache_user }}" + mode: 0755 + +- name: Copy files from files/upload2usb/ into {{ doc_root }}/upload2usb/ + copy: + src: "{{ item }}" + dest: "{{ doc_root }}/upload2usb/" + with_fileglob: + - upload2usb/* # 2021-03-21: If usbmount is repackaged by apt as a result of Linux kernel 5.4+ # supporting exFAT, the stanza below (might) in future no longer be needed... -# SEE ALSO: https://github.com/iiab/iiab/blob/master/roles/2-common/tasks/packages.yml#L22-L23 -- name: Add ' exfat fuseblk ntfs' to FILESYSTEMS var in /etc/usbmount/usbmount.conf - lineinfile: - regexp: '^FILESYSTEMS=.*' - line: 'FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs"' - path: /etc/usbmount/usbmount.conf +# SEE ALSO: https://github.com/iiab/iiab/blob/586bfc5cb1abf6b4333a21d3fa89695f115432dc/roles/2-common/tasks/packages.yml#L11-L12 +#- name: Add ' exfat fuseblk ntfs' to FILESYSTEMS var in /etc/usbmount/usbmount.conf +# lineinfile: +# regexp: '^FILESYSTEMS=.*' +# line: 'FILESYSTEMS="vfat ext2 ext3 ext4 hfsplus exfat fuseblk ntfs"' +# path: /etc/usbmount/usbmount.conf -- name: Remove /etc/usbmount/mount.d/00_create_model_symlink - file: - path: /etc/usbmount/mount.d/00_create_model_symlink - state: absent +#- name: Remove /etc/usbmount/mount.d/00_create_model_symlink +# file: +# path: /etc/usbmount/mount.d/00_create_model_symlink +# state: absent # RECORD 'USB_LIB' AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'usb_lib_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: usb_lib + option: usb_lib_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'usb_lib_installed: True'" set_fact: usb_lib_installed: True diff --git a/roles/usb_lib/tasks/main.yml b/roles/usb_lib/tasks/main.yml index 7836f2d3a..ee4bd18ea 100644 --- a/roles/usb_lib/tasks/main.yml +++ b/roles/usb_lib/tasks/main.yml @@ -1,7 +1,7 @@ # TO DO: (2020-02-13) # - Look at analogous NGINX logic for http://box/usb in # nginx/templates/iiab.conf.j2 and make that visually meaningful for teachers: -# https://github.com/iiab/iiab/blob/master/roles/nginx/templates/iiab.conf.j2#L5-L8 +# https://github.com/iiab/iiab/blob/master/roles/nginx/templates/iiab.conf.j2#L5-L9 # "How do i fail a task in Ansible if the variable contains a boolean value? @@ -32,12 +32,12 @@ # If setup.yml becomes the norm in future, put the 2-3 stanzas below in there: -- name: "Set 'umask=0000' for {VFAT/FAT32, NTFS, exFAT} using var FS_MOUNTOPTIONS in /etc/usbmount/usbmount.conf, so Kolibri exports work" +- name: "Set 'umask=0000' for {VFAT/FAT32, NTFS, exFAT} using var FS_MOUNTOPTIONS in /etc/usbmount/usbmount.conf -- for Kolibri exports AND student uploads to teacher's USB stick (using http://box/usb)" lineinfile: regexp: '^FS_MOUNTOPTIONS=.*' line: 'FS_MOUNTOPTIONS="-fstype=vfat,umask=0000 -fstype=ntfs,umask=0000 -fstype=exfat,umask=0000"' path: /etc/usbmount/usbmount.conf - when: usb_lib_umask0000_for_kolibri + when: usb_lib_writable_sticks # Setting 'umask=0000' for all filesystems: (much the same thing as above, as # the mount command does not use this umask setting for filesystems like ext4) @@ -46,14 +46,14 @@ # regexp: '^MOUNTOPTIONS=.*' # line: 'MOUNTOPTIONS="sync,noexec,nodev,noatime,nodiratime,umask=0000"' # path: /etc/usbmount/usbmount.conf -# when: usb_lib_umask0000_for_kolibri +# when: usb_lib_writable_sticks -- name: 'Set FS_MOUNTOPTIONS="" in /etc/usbmount/usbmount.conf, e.g. if Kolibri will not be used' +- name: 'Set FS_MOUNTOPTIONS="" in /etc/usbmount/usbmount.conf -- e.g. if Kolibri exports AND student uploads to teacher USB stick are not needed' lineinfile: regexp: '^FS_MOUNTOPTIONS=.*' line: 'FS_MOUNTOPTIONS=""' # Restore apt pkg default, e.g. for runrole path: /etc/usbmount/usbmount.conf - when: not usb_lib_umask0000_for_kolibri + when: not usb_lib_writable_sticks - name: Enable/Disable/Restart NGINX @@ -66,12 +66,6 @@ path: /etc/usbmount/mount.d/00_create_model_symlink state: absent -- name: Put variable in iiab.env that enables display of content at root of USB - lineinfile: - path: "{{ iiab_env_file }}" - regexp: "^IIAB_USB_LIB_SHOW_ALL.*" - line: "IIAB_USB_LIB_SHOW_ALL={{ iiab_usb_lib_show_all }}" - - name: Add 'usb_lib' variable values to {{ iiab_ini_file }} ini_file: @@ -83,10 +77,10 @@ - option: name value: USB_LIB - option: description - value: '"USB_LIB automounts Teacher Content on USB drives to /library/www/html/local_content, so students can browse it almost immediately at http://box/usb"' + value: '"USB_LIB (1) automounts teacher content on USB sticks to /library/www/html/local_content, so students can browse the USB; AND (2) allows students to upload their work to USB sticks / drives, all from http://box/usb"' - option: usb_lib_install value: "{{ usb_lib_install }}" - option: usb_lib_enabled value: "{{ usb_lib_enabled }}" - - option: usb_lib_umask0000_for_kolibri - value: "{{ usb_lib_umask0000_for_kolibri }}" + - option: usb_lib_writable_sticks + value: "{{ usb_lib_writable_sticks }}" diff --git a/roles/usb_lib/tasks/nginx.yml b/roles/usb_lib/tasks/nginx.yml index 7e572142a..1e6be6d21 100644 --- a/roles/usb_lib/tasks/nginx.yml +++ b/roles/usb_lib/tasks/nginx.yml @@ -1,20 +1,21 @@ - name: Install /etc/usbmount/mount.d/70-usb-library from template, if usb_lib_enabled template: - src: mount.d/70-usb-library - dest: /etc/usbmount/mount.d/ + src: mount.d/70-usb-library.j2 + dest: /etc/usbmount/mount.d/70-usb-library owner: root group: root mode: '0751' when: usb_lib_enabled -- name: Install /etc/usbmount/umount.d/70-usb-library from template, if usb_lib_enabled - template: - src: umount.d/70-usb-library - dest: /etc/usbmount/umount.d - owner: root - group: root - mode: '0751' - when: usb_lib_enabled +# 20250125: commenting out stale file, superseded by iiab-clean-usb.sh +# - name: Install /etc/usbmount/umount.d/70-usb-library from template, if usb_lib_enabled +# template: +# src: umount.d/70-usb-library +# dest: /etc/usbmount/umount.d +# owner: root +# group: root +# mode: '0751' +# when: usb_lib_enabled - name: Remove /etc/usbmount/mount.d/70-usb-library if not usb_lib_enabled file: @@ -22,11 +23,12 @@ state: absent when: not usb_lib_enabled -- name: Remove /etc/usbmount/umount.d/70-usb-library if not usb_lib_enabled - file: - path: /etc/usbmount/umount.d/70-usb-library - state: absent - when: not usb_lib_enabled +# 20250125: commenting out stale file, superseded by iiab-clean-usb.sh +# - name: Remove /etc/usbmount/umount.d/70-usb-library if not usb_lib_enabled +# file: +# path: /etc/usbmount/umount.d/70-usb-library +# state: absent +# when: not usb_lib_enabled - name: Restart 'nginx' systemd service systemd: diff --git a/roles/usb_lib/templates/content_dir.conf b/roles/usb_lib/templates/content_dir.conf.unused similarity index 100% rename from roles/usb_lib/templates/content_dir.conf rename to roles/usb_lib/templates/content_dir.conf.unused diff --git a/roles/usb_lib/templates/iiab-clean-usb.sh b/roles/usb_lib/templates/iiab-clean-usb.sh index a1876551c..360d737f4 100644 --- a/roles/usb_lib/templates/iiab-clean-usb.sh +++ b/roles/usb_lib/templates/iiab-clean-usb.sh @@ -1,14 +1,14 @@ #!/bin/bash -# Remove symlink in /library/content to automounted usb drive -# -DEVICE=`echo $@ | sed -s 's|-|/|'` -MNT_POINT=`findmnt -n /$DEVICE | awk '{print $1}'` -CONTENT_LINK_USB=`basename $MNT_POINT | awk '{print toupper($0)}'` +# Remove symlink in /library/www/html/local_content to automounted USB drive + +DEVICE="/$(echo $1 | sed 's|-|/|')" +MNT_POINT=$(findmnt -no target $DEVICE) +CONTENT_LINK_USB=$(basename $MNT_POINT | awk '{print toupper($0)}') CONTENT_LINK="/library/www/html/local_content/$CONTENT_LINK_USB" -logger -p user.notice -t "usbmount" -- "Attempting to remove link $CONTENT_LINK." + +logger -t "usb_lib (iiab-clean-usb.sh)" "Attempting to remove symlink $CONTENT_LINK, as auto-created earlier by usbmount." if [ -L $CONTENT_LINK ]; then - /bin/rm $CONTENT_LINK - logger -p user.notice -t "usbmount" -- "$CONTENT_LINK removed." + /usr/bin/rm $CONTENT_LINK + logger -t "usb_lib (iiab-clean-usb.sh)" "Symlink $CONTENT_LINK removed, as auto-created earlier by usbmount." fi - diff --git a/roles/usb_lib/templates/iiab-usb_lib-show-all-off b/roles/usb_lib/templates/iiab-usb_lib-show-all-off.unused similarity index 100% rename from roles/usb_lib/templates/iiab-usb_lib-show-all-off rename to roles/usb_lib/templates/iiab-usb_lib-show-all-off.unused diff --git a/roles/usb_lib/templates/iiab-usb_lib-show-all-on b/roles/usb_lib/templates/iiab-usb_lib-show-all-on.unused similarity index 100% rename from roles/usb_lib/templates/iiab-usb_lib-show-all-on rename to roles/usb_lib/templates/iiab-usb_lib-show-all-on.unused diff --git a/roles/usb_lib/templates/mount.d/70-usb-library b/roles/usb_lib/templates/mount.d/70-usb-library deleted file mode 100644 index 11358220d..000000000 --- a/roles/usb_lib/templates/mount.d/70-usb-library +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# Create symlink in DocumentRoot/content to autmounted usb drive -# -# based on a similar script in the xs-rsync package -# by Martin Langhoff -# -# and the adaptation for xs-activity-server by Douglas Bagnall -# -# -# by Tim Moody tim@timmoody.com - -source {{ iiab_env_file }} -case $IIAB_USB_LIB_SHOW_ALL in -'True'|'true'|'TRUE') - logger -p user.notice -t "70-usb-library" -- "Displaying root directory on $UM_MOUNTPOINT." - # regularize the variable - IIAB_USB_LIB_SHOW_ALL=True - ;; -*) - logger -p user.notice -t "70-usb-library" -- "Looking for /share, /Share, /Piratebox/Share, /USB, or /usb on $UM_MOUNTPOINT." - ;; -esac - -VERBOSE=yes - -SHARE_DIR="" -# Only show content if in these directories - -if [ -d $UM_MOUNTPOINT/share ]; then - SHARE_DIR="$UM_MOUNTPOINT/share" -fi -if [ -d $UM_MOUNTPOINT/Share ]; then - SHARE_DIR="$UM_MOUNTPOINT/Share" -fi -if [ -d $UM_MOUNTPOINT/Piratebox/Share ]; then - SHARE_DIR="$UM_MOUNTPOINT/Piratebox/Share" -fi -if [ -d $UM_MOUNTPOINT/USB ]; then - SHARE_DIR="$UM_MOUNTPOINT/USB" -fi -if [ -d $UM_MOUNTPOINT/usb ]; then - SHARE_DIR="$UM_MOUNTPOINT/usb" -fi -if [ "$IIAB_USB_LIB_SHOW_ALL" == "True" ]; then - SHARE_DIR="$UM_MOUNTPOINT" -fi - -if [ ! -z "$SHARE_DIR" ]; then - logger -p user.notice -t "70-usb-library" -- "Found Share Directory $SHARE_DIR." -else - logger -p user.notice -t "70-usb-library" -- "did not find /share, /Share, /Piratebox/Share, /USB, or /usb on USB" -fi - - -if [ "$SHARE_DIR" != "" ];then - CONTENT_LINK_USB=`basename $UM_MOUNTPOINT | awk '{print toupper($0)}'` - CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB" - logger -p user.notice -t "70-usb-library" -- "Creating link to $CONTENT_LINK." - ln -s $SHARE_DIR $CONTENT_LINK -fi diff --git a/roles/usb_lib/templates/mount.d/70-usb-library.j2 b/roles/usb_lib/templates/mount.d/70-usb-library.j2 new file mode 100644 index 000000000..8263bde1f --- /dev/null +++ b/roles/usb_lib/templates/mount.d/70-usb-library.j2 @@ -0,0 +1,67 @@ +#!/bin/bash +# Create symlink in DocumentRoot/content to automounted usb drive +# +# based on a similar script in the xs-rsync package +# by Martin Langhoff +# +# and the adaptation for xs-activity-server by Douglas Bagnall +# +# +# by Tim Moody tim@timmoody.com + +# Better to set this in /etc/usbmount/usbmount.conf +# VERBOSE=yes + +# UM_MOUNTPOINT is documented at: https://github.com/rbrito/usbmount#hook-scripts +UM_DEV=$(findmnt -no source $UM_MOUNTPOINT) + +# 2022-06-16 better security thanks to @tim-moody and @jvonau: +# https://github.com/iiab/iiab/pull/3254 +LIB_DEV=$(findmnt -no source /library | cut -d '[' -f 1) +ROOT_DEV=$(findmnt -no source /) +BOOT_DEV=$(findmnt -no source /boot) +BOOTFW_DEV=$(findmnt -no source /boot/firmware) + +# Verbose logging to illuminate occasional boot bugginess: +logger -t "usb_lib (70-usb-library)" "UM_DEV is: $UM_DEV" +logger -t "usb_lib (70-usb-library)" "LIB_DEV is: $LIB_DEV" +logger -t "usb_lib (70-usb-library)" "ROOT_DEV is: $ROOT_DEV" +logger -t "usb_lib (70-usb-library)" "BOOT_DEV is: $BOOT_DEV" +logger -t "usb_lib (70-usb-library)" "BOOTFW_DEV is: $BOOTFW_DEV" + +if [ "$UM_DEV" == "$LIB_DEV" ]; then + logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /library" + exit 1 +elif [ "$UM_DEV" == "$ROOT_DEV" ]; then + logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing rootfs" + exit 1 +elif [ "$UM_DEV" == "$BOOT_DEV" ]; then + logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /boot" + exit 1 +elif [ "$UM_DEV" == "$BOOTFW_DEV" ]; then + logger -t "usb_lib (70-usb-library)" "Skipping $UM_MOUNTPOINT containing /boot/firmware" + exit 1 +fi + +# 2025-01-25: Check for existence of folder PUBLIC on USB stick: if found, the stick will not be completely browsable. +# Teachers can set their stick for 1 of 2 two "personalities" β€” students can either upload "confidential homework" or +# "public artwork" β€” as summarized here: https://github.com/iiab/iiab/blob/master/roles/usb_lib/README.rst +if [ -d $UM_MOUNTPOINT/PUBLIC ]; then + SHARE_DIR=$UM_MOUNTPOINT/PUBLIC + logger -t "usb_lib (70-usb-library)" "Found /PUBLIC on $UM_MOUNTPOINT" +else + SHARE_DIR=$UM_MOUNTPOINT + logger -t "usb_lib (70-usb-library)" "Did not find /PUBLIC on $UM_MOUNTPOINT" +fi + +CONTENT_LINK_USB=$(basename $UM_MOUNTPOINT | awk '{print toupper($0)}') +if [ -z "$CONTENT_LINK_USB" ]; then + logger -t "usb_lib (70-usb-library)" 'ERROR: Var CONTENT_LINK_USB is empty ("rm -rf /library/www/html/local_content/" would be dangerous!)' + exit 1 +fi +CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB" +# 'rm -rf' even stronger than 'ln -nsf' and 'ln -Tsf' +# https://serverfault.com/questions/147787/how-to-update-a-symbolic-link-target-ln-f-s-not-working/522483#522483 +logger -t "usb_lib (70-usb-library)" "Creating link from $CONTENT_LINK to $SHARE_DIR" +rm -rf $CONTENT_LINK +ln -s $SHARE_DIR $CONTENT_LINK diff --git a/roles/usb_lib/templates/umount.d/70-usb-library b/roles/usb_lib/templates/umount.d.unused/70-usb-library similarity index 68% rename from roles/usb_lib/templates/umount.d/70-usb-library rename to roles/usb_lib/templates/umount.d.unused/70-usb-library index 7803b880f..d8e095008 100644 --- a/roles/usb_lib/templates/umount.d/70-usb-library +++ b/roles/usb_lib/templates/umount.d.unused/70-usb-library @@ -12,13 +12,13 @@ CONTENT_LINK_USB=`basename $UM_MOUNTPOINT | awk '{print toupper($0)}'` CONTENT_LINK="{{ doc_root }}/local_content/$CONTENT_LINK_USB" -logger -p user.notice -t "70-usb-library" -- "Attempting to remove link $CONTENT_LINK." +logger -p user.notice -t "usb_lib (70-usb-library)" -- "Attempting to remove link $CONTENT_LINK." if [ -L $CONTENT_LINK ]; then {% if is_debuntu %} - /bin/rm $CONTENT_LINK + /bin/rm -f $CONTENT_LINK {% else %} - /usr/bin/rm $CONTENT_LINK + /usr/bin/rm -f $CONTENT_LINK {% endif %} - logger -p user.notice -t "70-usb-library" -- "$CONTENT_LINK removed." + logger -p user.notice -t "usb_lib (70-usb-library)" -- "$CONTENT_LINK removed." fi diff --git a/roles/usb_lib/templates/usbmount.rules.j2 b/roles/usb_lib/templates/usbmount.rules.j2 index 564186c5a..939a31041 100644 --- a/roles/usb_lib/templates/usbmount.rules.j2 +++ b/roles/usb_lib/templates/usbmount.rules.j2 @@ -1,5 +1,3 @@ -KERNEL=="sd*", DRIVERS=="sbp2", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c" -KERNEL=="sd*", SUBSYSTEMS=="usb", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c" -KERNEL=="ub*", SUBSYSTEMS=="usb", ACTION=="add", PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c" -KERNEL=="sd*", SUBSYSTEMS=="usb", ACTION=="remove", PROGRAM="/usr/share/usbmount/usbmount remove" +ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem" PROGRAM="/bin/systemd-escape -p --template=usbmount@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c" +ACTION=="remove", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem" PROGRAM="/bin/systemd-escape -p /usr/share/usbmount/usbmount remove" diff --git a/roles/usb_lib/templates/usbmount@.service.j2 b/roles/usb_lib/templates/usbmount@.service.j2 index 34d75d9f3..6cf1f990b 100644 --- a/roles/usb_lib/templates/usbmount@.service.j2 +++ b/roles/usb_lib/templates/usbmount@.service.j2 @@ -1,14 +1,15 @@ [Unit] BindTo=%i.device After=%i.device -After=rc-local.service +After=systemd-udev-trigger.service +ConditionPathExists=/var/run [Service] #Type=oneshot TimeoutStartSec=0 Environment=DEVNAME=%I -ExecStart=/usr/share/usbmount/usbmount add -ExecStop=/usr/sbin/iiab-clean-usb.sh %I +ExecStart=/usr/local/sbin/usbmount add +ExecStop=/usr/local/sbin/iiab-clean-usb.sh %I ExecStopPost=/bin/umount /%I RemainAfterExit=yes - +RuntimeDirectory=usbmount diff --git a/roles/vnstat/tasks/install.yml b/roles/vnstat/tasks/install.yml index d015385bf..46db71ddd 100644 --- a/roles/vnstat/tasks/install.yml +++ b/roles/vnstat/tasks/install.yml @@ -1,15 +1,41 @@ +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + - name: Install 'vnstat' package package: name: vnstat state: present -- name: Install /etc/vnstat.conf from template - template: - src: vnstat.conf.j2 - dest: /etc/vnstat.conf - # owner: root - # group: root - mode: '0744' + +# Similar code block in roles/network/tasks/detected_network.yml (line ~35) and roles/network/tasks/computed_network.yml (lines ~74 and ~110) +- name: "Setting iiab_wan_iface to '{{ ansible_default_ipv4.alias }}' -- using ansible_default_ipv4.alias if detected" + set_fact: + iiab_wan_iface: "{{ ansible_default_ipv4.alias }}" + when: ansible_default_ipv4.gateway is defined + +# 2023-05-01: Probably no longer nec, as line 'Interface ""' in /etc/vnstat.conf (as installed by apt) automatically selects the default interface +- name: Insert 'Interface "{{ iiab_wan_iface }}"' into /etc/vnstat.conf + lineinfile: + path: /etc/vnstat.conf + regexp: '^Interface ' + line: 'Interface "{{ iiab_wan_iface }}"' + +# - name: Install /etc/vnstat.conf from template +# template: +# src: vnstat.conf.j2 +# dest: /etc/vnstat.conf +# mode: '0744' + + +# 2023-05-01: https://github.com/vergoh/vnstat/issues/134#issuecomment-663836557 +- name: 'Precautionary Start & Enable of vnstat.service, to mitigate intermittent #3539 (''Failed to open database "/var/lib/vnstat/vnstat.db" in read-only mode'') during WAN db creation just below' + systemd: + name: vnstat + daemon_reload: true + state: started + enabled: true - name: Create database for WAN to collect vnStat data shell: /usr/bin/vnstat -i {{ iiab_wan_iface }} @@ -21,6 +47,17 @@ # RECORD vnStat AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'vnstat_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: vnstat + option: vnstat_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'vnstat_installed: True'" set_fact: vnstat_installed: True diff --git a/roles/vnstat/tasks/main.yml b/roles/vnstat/tasks/main.yml index 5e28f26aa..40ae032f4 100644 --- a/roles/vnstat/tasks/main.yml +++ b/roles/vnstat/tasks/main.yml @@ -19,26 +19,33 @@ quiet: yes -- name: Install vnStat if 'vnstat_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: vnstat_installed is undefined +- block: + - name: Install vnStat if 'vnstat_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: vnstat_installed is undefined -- include_tasks: enable-or-disable.yml + - include_tasks: enable-or-disable.yml + - name: Add 'vnstat' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: vnstat + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: vnStat + - option: description + value: '"vnStat is a console-based network traffic monitor for Linux and BSD that keeps a log of network traffic for the selected interface(s)."' + - option: vnstat_install + value: "{{ vnstat_install }}" + - option: vnstat_enabled + value: "{{ vnstat_enabled }}" -- name: Add 'vnstat' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: vnstat - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: vnStat - - option: description - value: '"vnStat is a console-based network traffic monitor for Linux and BSD that keeps a log of network traffic for the selected interface(s)."' - - option: vnstat_install - value: "{{ vnstat_install }}" - - option: vnstat_enabled - value: "{{ vnstat_enabled }}" + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/vnstat/templates/vnstat.conf.j2 b/roles/vnstat/templates/vnstat.conf.j2.unused similarity index 100% rename from roles/vnstat/templates/vnstat.conf.j2 rename to roles/vnstat/templates/vnstat.conf.j2.unused diff --git a/roles/wordpress/tasks/install.yml b/roles/wordpress/tasks/install.yml index f0af250be..fb4aca021 100644 --- a/roles/wordpress/tasks/install.yml +++ b/roles/wordpress/tasks/install.yml @@ -11,6 +11,31 @@ # and security enhancements using timestamps under /library/wordpress, as these # can arise without warning when WordPress is online, since WordPress ~4.8 + +- name: "Set 'mysql_install: True' and 'mysql_enabled: True'" + set_fact: + mysql_install: True + mysql_enabled: True + +- name: MYSQL - run 'mysql' role (attempt to install & enable MySQL / MariaDB) + include_role: + name: mysql + +- name: FAIL (STOP THE INSTALL) IF 'mysql_installed is undefined' + fail: + msg: "WordPress install cannot proceed, as MySQL / MariaDB is not installed." + when: mysql_installed is undefined + + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + +- name: Provision MySQL DB + include_tasks: setup.yml + + # 2021-06-29: PHP modules, covering "RECOMMENDED" and "OPTIONAL" sections here: # https://make.wordpress.org/hosting/handbook/server-environment/ - name: Install libsodium23 + 8 PHP packages (run 'php -m' or 'php -i' to verify) @@ -38,29 +63,45 @@ # state: present # when: php_version is version('8.0', '<') -- name: Download {{ wordpress_download_base_url }}/{{ wordpress_src }} to {{ downloads_dir }} - get_url: - url: "{{ wordpress_download_base_url }}/{{ wordpress_src }}" - dest: "{{ downloads_dir }}" - timeout: "{{ download_timeout }}" - register: wp_download_output +- name: "Run roles/www_options/tasks/php-settings.yml with 'nginx_high_php_limits: False' by default" + include_tasks: roles/www_options/tasks/php-settings.yml + when: php_settings_done is undefined -- name: Symlink {{ downloads_dir }}/wordpress.tar.gz -> {{ wp_download_output.dest }} + +- name: Delete {{ downloads_dir }}/wordpress.tar.gz if it exists file: - src: "{{ wp_download_output.dest }}" - path: "{{ downloads_dir }}/wordpress.tar.gz" # /opt/iiab/downloads - state: link - when: wp_download_output.dest is defined + path: "{{ downloads_dir }}/wordpress.tar.gz" + state: absent -- name: Does {{ downloads_dir }}/wordpress.tar.gz link exist? +- name: Download {{ wordpress_download_base_url }}/{{ wordpress_src }} to {{ downloads_dir }}/wordpress.tar.gz + command: wget {{ wordpress_download_base_url }}/{{ wordpress_src }} -O {{ downloads_dir }}/wordpress.tar.gz + # 2022-05-04: Ansible approach below (get_url) fails with HTTP Error 429 + # (Too Many Requests) b/c Ansible's User-Agent string? Affecting 1 user in + # England and another user in Scotland, but not affecting many other + # countries/ISP's apparently? WordPress must have recently changed their + # hosting arrangements for https://wordpress.org/latest.tar.gz + # get_url: + # url: "{{ wordpress_download_base_url }}/{{ wordpress_src }}" + # dest: "{{ downloads_dir }}" + # timeout: "{{ download_timeout }}" +# register: wp_download_output + +# - name: Symlink {{ downloads_dir }}/wordpress.tar.gz -> {{ wp_download_output.dest }} +# file: +# src: "{{ wp_download_output.dest }}" +# path: "{{ downloads_dir }}/wordpress.tar.gz" # /opt/iiab/downloads +# state: link +# when: wp_download_output.dest is defined + +- name: Does {{ downloads_dir }}/wordpress.tar.gz exist? stat: path: "{{ downloads_dir }}/wordpress.tar.gz" # /opt/iiab/downloads - register: wp_link + register: wp_tar_gz - name: FAIL (force Ansible to exit) IF {{ downloads_dir }}/wordpress.tar.gz doesn't exist fail: msg: "{{ downloads_dir }}/wordpress.tar.gz is REQUIRED in order to install WordPress." - when: not wp_link.stat.exists + when: not wp_tar_gz.stat.exists - name: "Unpack {{ downloads_dir }}/wordpress.tar.gz to permanent location {{ wp_install_path }}/wordpress - owner: root, group: {{ apache_user }}, mode: '0664', keep_newer: yes" unarchive: @@ -114,6 +155,17 @@ # RECORD WordPress AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'wordpress_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: wordpress + option: wordpress_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'wordpress_installed: True'" set_fact: wordpress_installed: True diff --git a/roles/wordpress/tasks/main.yml b/roles/wordpress/tasks/main.yml index 7204f741e..106343a84 100644 --- a/roles/wordpress/tasks/main.yml +++ b/roles/wordpress/tasks/main.yml @@ -21,43 +21,46 @@ quiet: yes -- name: Provision MySQL DB for WordPress, if 'wordpress_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: setup.yml - when: wordpress_installed is undefined # and not installing +- block: -- name: Install WordPress if 'wordpress_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: wordpress_installed is undefined + - name: Install WordPress if 'wordpress_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: wordpress_installed is undefined + - name: Enable/Disable/Restart NGINX + include_tasks: nginx.yml -- name: Enable/Disable/Restart NGINX - include_tasks: nginx.yml + - name: Add 'wordpress' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: wordpress + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: WordPress + - option: description + value: '"WordPress is a blog and web site management application."' + - option: wordpress_install + value: "{{ wordpress_install }}" + - option: wordpress_enabled + value: "{{ wordpress_enabled }}" + - option: wordpress_src + value: "{{ wordpress_src }}" + - option: wp_abs_path + value: "{{ wp_abs_path }}" + - option: wp_db_name + value: "{{ wp_db_name }}" + - option: wp_db_user + value: "{{ wp_db_user }}" + - option: wp_url + value: "{{ wp_url }}" + - option: wp_full_url + value: "{{ wp_full_url }}" + rescue: -- name: Add 'wordpress' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: wordpress - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: WordPress - - option: description - value: '"WordPress is a blog and web site management application."' - - option: wordpress_install - value: "{{ wordpress_install }}" - - option: wordpress_enabled - value: "{{ wordpress_enabled }}" - - option: wordpress_src - value: "{{ wordpress_src }}" - - option: wp_abs_path - value: "{{ wp_abs_path }}" - - option: wp_db_name - value: "{{ wp_db_name }}" - - option: wp_db_user - value: "{{ wp_db_user }}" - - option: wp_url - value: "{{ wp_url }}" - - option: wp_full_url - value: "{{ wp_full_url }}" + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/roles/www_base/files/html/html/credits.html b/roles/www_base/files/html/html/credits.html index e6c428260..6ab6950cc 100644 --- a/roles/www_base/files/html/html/credits.html +++ b/roles/www_base/files/html/html/credits.html @@ -23,9 +23,9 @@ All PhET Interactive Simulations content is available for free at phet.colorado.edu.
All MedLine content is available for free at medlineplus.gov.
All Hesperian content is available for free at hesperian.org.
- Arabic translations of Hesperian content were done by Arab Resource Collective and are available for free at mawared.org.
+ Arabic translations of Hesperian content were done by Arab Resource Collective and are available for free at mawared.org.
All Gutenberg content is available for free at www.gutenberg.org.
- All OLPC content is available for free at wiki.laptop.org.
+ All OLPC content is available for free at wiki.laptop.org.
All MIT Scratch content is available for free at scratch.mit.edu.
All UNESCO's IICBA content is available for free at www.iicba.unesco.org.
All Math Expression content is available for free at www.mathexpression.com.
@@ -36,9 +36,9 @@ Internet-in-a-Box also includes the work of content aggregators which we gratefully acknowledge:

- RACHEL is a curation of selected offline content at oer2go.org.
- Kiwix is a ZIM server and repository of Wikimedia and other content in a compressed ZIM file format at www.kiwix.org.
+ Kiwix is a ZIM server and repository of Wikimedia and other content in a compressed ZIM file format at www.kiwix.org.
KA Lite is a server and repository of Khan Academy content in various languages at learningequality.org/ka-lite.

+ OER2Go/RACHEL is a curation of selected offline content at rachel.worldpossible.org/content.
Internet-in-a-Box also contains a number of applications each of which has its own attribution information, which is included.

diff --git a/roles/www_base/tasks/main.yml b/roles/www_base/tasks/main.yml index f7fe20fc6..8efe11472 100644 --- a/roles/www_base/tasks/main.yml +++ b/roles/www_base/tasks/main.yml @@ -1,6 +1,12 @@ # Role "www_base" runs here, probably in 3-BASE-SERVER. # Role "www_options" runs later, likely in 4-SERVER-OPTIONS. + +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # 2021-06-27: Antifragile roles can become less brittle by fully declaring # their own dependencies (i.e. for modularity, separation-of-concerns, # encapsulation, compartmentalization, scope sanity, etc). @@ -28,7 +34,7 @@ - name: Install php-stem.yml if php_version == 7.4 and (ansible_machine == "armv6l" or ansible_machine == "armv7l" or ansible_machine == "aarch64" or ansible_machine == "x86_64") include_tasks: php-stem.yml when: php_version == 7.4 and (ansible_machine == "armv6l" or ansible_machine == "armv7l" or ansible_machine == "aarch64" or ansible_machine == "x86_64") - # or php_version == 8.0 or php_version == 8.1 (IIAB MIGHT SUPPORT THESE LATER IN 2022) + # or php_version == 8.0 or php_version == 8.1 or php_version == 8.2 (IIAB MIGHT SUPPORT THESE LATER IN 2023) # or php_version == 7.2 or php_version == 7.3 (PROBABLY WORK, AT YOUR OWN RISK!) - name: Create dir {{ doc_root }}/home -- if you customized var iiab_home_url e.g. in /etc/iiab/local_vars.yml, that dir is created later -- by www_options/tasks/main.yml @@ -54,6 +60,17 @@ # RECORD www_base AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'www_base_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: www_base + option: www_base_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'www_base_installed: True'" set_fact: www_base_installed: True diff --git a/roles/www_base/tasks/php-stem.yml b/roles/www_base/tasks/php-stem.yml index fd8256066..15332a942 100644 --- a/roles/www_base/tasks/php-stem.yml +++ b/roles/www_base/tasks/php-stem.yml @@ -2,7 +2,7 @@ # README & Code: https://github.com/iiab/php-stem -# Source Code also here: http://download.iiab.io/packages/php-stem.src.tar +# Source Code also here: https://download.iiab.io/packages/php-stem.src.tar # June 2018 debugging & compilation thanks to Tim Moody & George Hunt # Original bug: https://github.com/iiab/iiab/issues/829 @@ -47,7 +47,7 @@ armv6l: armhf armv7l: armhf aarch64: aarch64 - x86_64: x86 + x86_64: x64 - name: Set php_stem_arch to "{{ php_stem_arches[ansible_machine] }}" using php_stem_arches[ansible_machine is "{{ ansible_machine }}"] set_fact: @@ -94,9 +94,9 @@ # stem_available: True # when: php_version == 7.4 and (ansible_machine == "aarch64" or ansible_machine == "x86_64") -# - name: Unarchive http://download.iiab.io/packages/php{{ php_version }}-stem.rpi.tar to / (rpi) +# - name: Unarchive https://download.iiab.io/packages/php{{ php_version }}-stem.rpi.tar to / (rpi) # unarchive: -# src: http://download.iiab.io/packages/php{{ php_version }}-stem.rpi.tar +# src: https://download.iiab.io/packages/php{{ php_version }}-stem.rpi.tar # dest: / # owner: root # group: root @@ -104,9 +104,9 @@ # remote_src: yes # when: (ansible_machine == "armv7l" or ansible_machine == "armv6l") and stem_available is defined -# - name: Unarchive http://download.iiab.io/packages/php{{ php_version }}-stem.aarch64.tar to / (rpi) +# - name: Unarchive https://download.iiab.io/packages/php{{ php_version }}-stem.aarch64.tar to / (rpi) # unarchive: -# src: http://download.iiab.io/packages/php{{ php_version }}-stem.aarch64.tar +# src: https://download.iiab.io/packages/php{{ php_version }}-stem.aarch64.tar # dest: / # owner: root # group: root @@ -114,9 +114,9 @@ # remote_src: yes # when: ansible_machine == "aarch64" and stem_available is defined -# - name: Unarchive http://download.iiab.io/packages/php{{ php_version }}-stem.x64.tar to / (x64) +# - name: Unarchive https://download.iiab.io/packages/php{{ php_version }}-stem.x64.tar to / (x64) # unarchive: -# src: http://download.iiab.io/packages/php{{ php_version }}-stem.x64.tar +# src: https://download.iiab.io/packages/php{{ php_version }}-stem.x64.tar # dest: / # owner: root # group: root diff --git a/roles/www_base/templates/iiab-refresh-wiki-docs.sh b/roles/www_base/templates/iiab-refresh-wiki-docs.sh index 5cc9b3f54..9ff61e654 100755 --- a/roles/www_base/templates/iiab-refresh-wiki-docs.sh +++ b/roles/www_base/templates/iiab-refresh-wiki-docs.sh @@ -15,23 +15,34 @@ INPUT=/tmp/iiab-wiki OUTPUT=/tmp/iiab-wiki.out DESTPATH={{ doc_root }}/info # /library/www/html/info DOCSPATH=$DESTPATH/docs # /library/www/html/info/docs +ADMINDOCSPATH=$DESTPATH/admin-console # /library/www/html/info/admin-console +# Note 1: sed (below) shortens URLs to 'admin-console' +# Note 2: Depends on "fancyindex on;" in roles/nginx/templates/iiab.conf.j2 rm -rf $INPUT rm -rf $OUTPUT mkdir -p $INPUT mkdir -p $OUTPUT mkdir -p $DOCSPATH +mkdir -p $ADMINDOCSPATH git clone https://github.com/iiab/iiab.wiki.git $INPUT - -for f in `ls $INPUT`; do +for f in `ls $INPUT`; do # Unlike further below, $f does NOT include path FTRIMMED=${f%.md} if [ $FTRIMMED = "Home" ]; then FTRIMMED=index; fi pandoc -s $INPUT/$f -o $OUTPUT/$FTRIMMED.html done - rsync -av $OUTPUT/ $DESTPATH +if [ -d /opt/iiab/iiab-admin-console/docs ]; then + cp /opt/iiab/iiab-admin-console/docs/*.md $ADMINDOCSPATH + for f in $ADMINDOCSPATH/*.md; do # Unlike above, $f INCLUDES path + FTRIMMED=${f%.md} + pandoc -s $f -o $FTRIMMED.html + rm $f + done +fi + # Download FAQ etc lynx -reload -source https://wiki.iiab.io/go/FAQ > $DESTPATH/FAQ.html lynx -reload -source https://wiki.iiab.io/go/Security > $DESTPATH/Security.html @@ -54,42 +65,45 @@ cp -p "{{ iiab_dir }}/roles/lokole/Lokole-IIAB_Users_Manual.pdf" $DOCSPATH # # MAKE LINKS REFER TO LOCAL ITEMS... # ...on main page (http://box/info) -sed -i -r "s|https://magazines-attachments.raspberrypi.org/books/full_pdfs/000/000/038/original/BeginnersGuide-4thEd-Eng_v2.pdf|docs/BeginnersGuide-4thEd-Eng_v2.pdf|g" $DESTPATH/index.html -sed -i -r "s|https://.*archive.org/15/items/other_doc/other_doc.pdf|docs/Raspberry_Pi_User_Guide_v4.pdf|g" $DESTPATH/index.html -sed -i -r "s|https://github.com/iiab/iiab/blob/master/roles/lokole/Lokole-IIAB_Users_Manual.pdf|docs/Lokole-IIAB_Users_Manual.pdf|g" $DESTPATH/index.html +sed -i "s|https://magazines-attachments.raspberrypi.org/books/full_pdfs/000/000/038/original/BeginnersGuide-4thEd-Eng_v2.pdf|docs/BeginnersGuide-4thEd-Eng_v2.pdf|g" $DESTPATH/index.html +sed -i "s|https://.*archive.org/15/items/other_doc/other_doc.pdf|docs/Raspberry_Pi_User_Guide_v4.pdf|g" $DESTPATH/index.html +sed -i "s|https://github.com/iiab/iiab/blob/master/roles/lokole/Lokole-IIAB_Users_Manual.pdf|docs/Lokole-IIAB_Users_Manual.pdf|g" $DESTPATH/index.html # ...and within subpages -for f in $DESTPATH/*.html; do - sed -i -r "s|https://github.com/iiab/iiab/wiki/([-.A-Za-z0-9]*)|\1.html|g" $f +for f in $(find $DESTPATH -name "*.html"); do # Recursive (even if not yet nec, as of 2023-01-11) +#for f in $DESTPATH/*.html; do # Non-recursive (omits subdirs) + sed -i -r "s|https://github.com/iiab/iiab/wiki/([-.~A-Za-z0-9]*)|\1.html|g" $f - sed -i -e "s|https://github.com/xsce/xsce/blob/release-6.2/\(.*\)\.md\">|\1.html\">|g" $f - sed -i -e "s|https://github.com/xsce/xsce/wiki/\(.*\)\">|\1.html\">|g" $f + sed -i "s|https://github.com/iiab/iiab-admin-console/tree/master/docs|admin-console|g" $f - sed -i -e "s|https://wiki.iiab.io/go/FAQ|FAQ.html|g" $f - sed -i -e "s|http://wiki.laptop.org/go/IIAB/FAQ|FAQ.html|g" $f - sed -i -e "s|/go/IIAB/FAQ|FAQ.html|g" $f - sed -i -e "s|http://wiki.iiab.io/FAQ|FAQ.html|g" $f - sed -i -e "s|http://FAQ.IIAB.IO|FAQ.html|g" $f - sed -i -e "s|http://faq.iiab.io|FAQ.html|g" $f - sed -i -e "s|http://schoolserver.org/FAQ|FAQ.html|g" $f - sed -i -e "s|http://schoolserver.org/faq|FAQ.html|g" $f - sed -i -e "s|http://wiki.laptop.org/go/XS_Community_Edition/FAQ|FAQ.html|g" $f + sed -i "s|https://github.com/xsce/xsce/blob/release-6.2/\(.*\)\.md\">|\1.html\">|g" $f + sed -i "s|https://github.com/xsce/xsce/wiki/\(.*\)\">|\1.html\">|g" $f - sed -i -e "s|http://wiki.laptop.org/go/IIAB/Security|Security.html|g" $f - sed -i -e "s|/go/IIAB/Security|Security.html|g" $f - sed -i -e "s|http://wiki.iiab.io/Security|Security.html|g" $f + sed -i "s|https://wiki.iiab.io/go/FAQ|FAQ.html|g" $f + #sed -i "s|http://wiki.laptop.org/go/IIAB/FAQ|FAQ.html|g" $f + sed -i "s|/go/IIAB/FAQ|FAQ.html|g" $f + sed -i "s|http://wiki.iiab.io/FAQ|FAQ.html|g" $f + sed -i "s|http://FAQ.IIAB.IO|FAQ.html|g" $f + sed -i "s|http://faq.iiab.io|FAQ.html|g" $f + #sed -i "s|http://schoolserver.org/FAQ|FAQ.html|g" $f + #sed -i "s|http://schoolserver.org/faq|FAQ.html|g" $f + #sed -i "s|http://wiki.laptop.org/go/XS_Community_Edition/FAQ|FAQ.html|g" $f - sed -i -e "s|http://wiki.laptop.org/go/IIAB/local_vars.yml|local_vars.yml|g" $f - sed -i -e "s|/go/IIAB/local_vars.yml|local_vars.yml|g" $f - sed -i -e "s|http://wiki.iiab.io/local_vars.yml|local_vars.yml|g" $f + #sed -i "s|http://wiki.laptop.org/go/IIAB/Security|Security.html|g" $f + sed -i "s|/go/IIAB/Security|Security.html|g" $f + sed -i "s|http://wiki.iiab.io/Security|Security.html|g" $f - sed -i -e "s|http://wiki.laptop.org/go/IIAB/local_vars_min.yml|local_vars_min.yml|g" $f - sed -i -e "s|/go/IIAB/local_vars_min.yml|local_vars_min.yml|g" $f - sed -i -e "s|http://wiki.iiab.io/local_vars_min.yml|local_vars_min.yml|g" $f + #sed -i "s|http://wiki.laptop.org/go/IIAB/local_vars.yml|local_vars.yml|g" $f + sed -i "s|/go/IIAB/local_vars.yml|local_vars.yml|g" $f + sed -i "s|https://wiki.iiab.io/local_vars.yml|local_vars.yml|g" $f - sed -i -e "s|http://wiki.laptop.org/go/IIAB/local_vars_big.yml|local_vars_big.yml|g" $f - sed -i -e "s|/go/IIAB/local_vars_big.yml|local_vars_big.yml|g" $f - sed -i -e "s|http://wiki.iiab.io/local_vars_big.yml|local_vars_big.yml|g" $f + #sed -i "s|http://wiki.laptop.org/go/IIAB/local_vars_min.yml|local_vars_min.yml|g" $f + #sed -i "s|/go/IIAB/local_vars_min.yml|local_vars_min.yml|g" $f + #sed -i "s|http://wiki.iiab.io/local_vars_min.yml|local_vars_min.yml|g" $f + + #sed -i "s|http://wiki.laptop.org/go/IIAB/local_vars_big.yml|local_vars_big.yml|g" $f + #sed -i "s|/go/IIAB/local_vars_big.yml|local_vars_big.yml|g" $f + #sed -i "s|http://wiki.iiab.io/local_vars_big.yml|local_vars_big.yml|g" $f done exit 0 diff --git a/roles/www_options/tasks/main.yml b/roles/www_options/tasks/main.yml index b2c1afbc5..f157abb26 100644 --- a/roles/www_options/tasks/main.yml +++ b/roles/www_options/tasks/main.yml @@ -2,135 +2,75 @@ # Role "www_options" runs here, probably in 4-SERVER-OPTIONS. +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 + + # HOMEPAGE - name: Create dir {{ doc_root }}{{ iiab_home_url }} just in case variable iiab_home_url was customized. (Standard path {{doc_root}}/home was created earlier.) file: state: directory - path: "{{ doc_root }}{{ iiab_home_url }}" # /library/www/html/home + path: "{{ doc_root }}{{ iiab_home_url }}" # e.g. /library/www/html/home owner: "{{ apache_user }}" group: "{{ apache_user }}" mode: '0755' # Used to be run by httpd/tasks/install.yml -- name: "IN CASE NGINX IS DISABLED: Enable IIAB pages via Apache (e.g. on port 80) if apache_install" - include_tasks: roles/httpd/tasks/homepage.yml - when: apache_installed is defined +#- name: "IN CASE NGINX IS DISABLED: Enable IIAB pages via Apache (e.g. on port 80) if apache_install" +# include_tasks: roles/httpd/tasks/homepage.yml +# when: apache_installed is defined # Used to be run by nginx/tasks/install.yml - name: Enable IIAB pages via NGINX (e.g. on port 80) if nginx_install include_tasks: roles/nginx/tasks/homepage.yml when: nginx_installed is defined - #when: nginx_install -- name: Make home page autostart on localhost (the server's console) if session manager is LXDE (rpi) + +# 2022-07-22: SIMILAR TO roles/iiab-admin/tasks/pwd-warnings.yml FOR passwords +# AND roles/network/tasks/netwarn.yml FOR iiab-network + +# 2024-12-12: RasPiOS changed compositor from wayfire to labwc: https://forums.raspberrypi.com/viewtopic.php?t=379321 +- name: Does directory /home/{{ iiab_admin_user }}/.config/labwc/ exist? stat: - path: /etc/xdg/lxsession/LXDE-pi/autostart - register: lxde_present + path: /home/{{ iiab_admin_user }}/.config/labwc/ + register: labwc_dir -- name: Check for Chromium name change +- name: Does /usr/bin/chromium-browser exist? stat: - path: /usr/bin/chromium - register: chromium_present + path: /usr/bin/chromium-browser + register: chromium_browser -- name: Add chromium-browser to /etc/xdg/lxsession/LXDE-pi/autostart if session manager is LXDE +# - name: Does /usr/bin/chromium exist? (check for browser filename change) +# stat: +# path: /usr/bin/chromium +# register: chromium_present + +# 2024-12-12: RasPiOS changed compositor from wayfire to labwc: https://forums.raspberrypi.com/viewtopic.php?t=379321 +- name: If both above exist, add '/usr/bin/chromium-browser --disable-restore-session-state http://box/home &' to /home/{{ iiab_admin_user }}/.config/labwc/autostart lineinfile: - path: /etc/xdg/lxsession/LXDE-pi/autostart - regexp: '^/usr/bin/chromium-browser' - line: '/usr/bin/chromium-browser --disable-restore-session-state http://box/home' - when: - lxde_present.stat.exists and not chromium_present.stat.exists + path: /home/{{ iiab_admin_user }}/.config/labwc/autostart # iiab-admin + create: yes + regexp: '^/usr/bin/chromium' + line: '/usr/bin/chromium-browser --disable-restore-session-state http://box/home &' + when: labwc_dir.stat.exists and labwc_dir.stat.isdir and chromium_browser.stat.exists -- name: Add chromium to /etc/xdg/lxsession/LXDE-pi/autostart if session manager is LXDE - lineinfile: - path: /etc/xdg/lxsession/LXDE-pi/autostart - regexp: '^/usr/bin/chromium' - line: '/usr/bin/chromium --disable-restore-session-state http://box/home' - when: - lxde_present.stat.exists and chromium_present.stat.exists +# - name: Add chromium to /etc/xdg/lxsession/LXDE-pi/autostart +# lineinfile: +# path: /etc/xdg/lxsession/LXDE-pi/autostart +# regexp: '^/usr/bin/chromium' +# line: '/usr/bin/chromium --disable-restore-session-state http://box/home' +# when: lxde_pi_autostart_present.stat.exists and chromium_present.stat.exists -- debug: - msg: 'THE 5 ANSIBLE STANZAS BELOW ONLY RUN... when: moodle_install or nextcloud_install or pbx_install or wordpress_install' - -- block: # 5-STANZA BLOCK BEGINS - - # roles/nginx has installed pkg 'php{{ php_version }}-fpm' in 3-base-server - - - name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/fpm/php.ini for lightweight use of WordPress/Nextcloud/PBX (allow photos/docs up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" - lineinfile: - path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } - - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } - - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } - - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } - - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is 128M / Nextcloud requests 512M' } - - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } - when: not nginx_high_php_limits and not moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: moodle_install or nextcloud_install or pbx_install or wordpress_install - - - name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/cli/php.ini for lightweight use of WordPress/Nextcloud/PBX (allow photos/docs up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" - lineinfile: - path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } - - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } - - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } - - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } - - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is 128M / Nextcloud requests 512M' } - - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } - when: not nginx_high_php_limits and not moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: moodle_install or nextcloud_install or pbx_install or wordpress_install - - # WARNING: This might cause excess use of RAM/disk or other resources! - # The first 5 values below were chosen by @ericnitschke and @kananigit on - # 2018-09-19: https://github.com/iiab/iiab/issues/1147 - - # 2020-03-08: IIAB DOES NOT SUPPORT UNINSTALLING APPS, so additional - # clauses (to reset/restore PHP's defaults) are not necessary at this time. - - # 2021-06-28: WITH PHP 8, MOODLE'S CLI INSTALLER UNFORTUNATELY *REQUIRES* - # editing /etc/php/{{ php_version }}/cli/php.ini (below) -- though during - # regular operation it uses: .../fpm/php.ini - # And in the past it used: .../apache2/php.ini - - - name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/fpm/php.ini for schools that use WordPress/Moodle/Nextcloud/PBX intensively (allow photos/docs up to 500MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" - lineinfile: - path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 500M ; default is 2M' } - - { regexp: '^post_max_size', line: 'post_max_size = 500M ; default is 8M' } - - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } - - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } - - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is 128M / Nextcloud requests 512M' } - - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } - when: nginx_high_php_limits or moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: moodle_install or nextcloud_install or pbx_install or wordpress_install - - - name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/cli/php.ini for schools that use WordPress/Moodle/Nextcloud/PBX intensively (allow photos/docs up to 500MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" - lineinfile: - path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - with_items: - - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 500M ; default is 2M' } - - { regexp: '^post_max_size', line: 'post_max_size = 500M ; default is 8M' } - - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } - - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } - - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is 128M / Nextcloud requests 512M' } - - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } - when: nginx_high_php_limits or moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: moodle_install or nextcloud_install or pbx_install or wordpress_install - - - name: Restart 'php{{ php_version }}-fpm' systemd service - systemd: - name: php{{ php_version }}-fpm - state: restarted - - when: moodle_install or nextcloud_install or pbx_install or wordpress_install # 5-STANZA BLOCK ENDS. COMPARE apache_allow_sudo conditionals below. +# 2022-12-29: php-settings.yml is ALSO attempted (on demand) by every +# /tasks/install.yml that needs it (Matomo, Moodle, Nextcloud, PBX, +# WordPress) so './runrole ' and similar are fully self-sufficient! +- name: "Run php-settings.yml -- allows post-install toggling of nginx_high_php_limits in /etc/iiab/local_vars.yml -- if you run './runrole www_options'" + include_tasks: php-settings.yml + # 2025-01-29: PHP's own defaults (presumably from the 1990s?) were Way Too Low -- for usb-lib's upload2usb, and in general -- so let's run php-settings.yml every time! + # when: nginx_high_php_limits or matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install # 'Is a "Rapid Power Off" button possible for low-electricity environments?' @@ -138,27 +78,46 @@ # COMPARE nginx_high_php_limits further above. -# 2020-03-08: DOES THE FLAG BELOW (apache_allow_sudo) PRESUMABLY WORK +# 2020-03-08: DOES THE FLAG BELOW (allow_www_data_poweroff) PRESUMABLY WORK # WITH NGINX TOO ? (The single-click poweroff button on IIAB's home # page certainly does still work with NGINX.) -- name: Give {{ apache_user }} (per variable apache_user) permission to poweroff, installing /etc/sudoers.d/020_apache_poweroff from template +- name: Give {{ apache_user }} (per variable apache_user) permission to poweroff, installing /etc/sudoers.d/020_www_data_poweroff from template template: - src: 020_apache_poweroff.j2 - dest: /etc/sudoers.d/020_apache_poweroff + src: 020_www_data_poweroff.j2 + dest: /etc/sudoers.d/020_www_data_poweroff mode: '0440' - when: apache_allow_sudo + when: allow_www_data_poweroff -- name: Remove {{ apache_user }} (per variable apache_user) permission to poweroff, removing /etc/sudoers.d/020_apache_poweroff +- name: Remove {{ apache_user }} (per variable apache_user) permission to poweroff, removing /etc/sudoers.d/020_www_data_poweroff file: - path: /etc/sudoers.d/020_apache_poweroff + path: /etc/sudoers.d/020_www_data_poweroff state: absent - when: not apache_allow_sudo + when: not allow_www_data_poweroff +# 2022-06-30: internet_available var removed +- name: 'Test for Internet access, using: https://wiki.iiab.io' + get_url: + #url: "{{ iiab_download_url }}/heart-beat.txt" + url: https://wiki.iiab.io + #dest: /tmp/heart-beat.txt + dest: /tmp/internet_access_test.html + #timeout: "{{ download_timeout }}" + # @jvonau recommends: 100sec is too much (keep 10sec default) + ignore_errors: True + #async: 10 + #poll: 2 + register: internet_access_test + +- name: Remove downloaded Internet test file /tmp/internet_access_test.html + file: + path: /tmp/internet_access_test.html + state: absent + - name: Run /usr/bin/iiab-refresh-wiki-docs (scraper script) to create http://box/info offline documentation. (This script was installed in Stage 3 = roles/3-base-server/tasks/main.yml, which ran roles/www_base/tasks/main.yml) command: /usr/bin/iiab-refresh-wiki-docs - when: internet_available and not nodocs + when: not internet_access_test.failed and not nodocs - name: (Re)Start '{{ apache_service }}' systemd service, if installed & enabled @@ -176,6 +135,17 @@ # RECORD www_options AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'www_options_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: www_options + option: www_options_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'www_options_installed: True'" set_fact: www_options_installed: True diff --git a/roles/www_options/tasks/php-settings.yml b/roles/www_options/tasks/php-settings.yml new file mode 100644 index 000000000..7109ccfeb --- /dev/null +++ b/roles/www_options/tasks/php-settings.yml @@ -0,0 +1,218 @@ +# 2022-12-29: This file (php-settings.yml) is ALSO invoked on demand, by: +# +# roles/matomo/tasks/install.yml +# roles/moodle/tasks/install.yml +# roles/nextcloud/tasks/install.yml +# roles/pbx/tasks/freepbx.yml +# roles/wordpress/tasks/install.yml + + +# 2022-12-30: FYI ansible_date_time.tz provides TZ ABBREVIATIONS (equivalent +# to 'date +%Z' output) which leads to serious ambiguity -- and not just (A) +# seasonal EST/EDT ambiguities, or (B) floods of geographic synonyms for the +# very same time zone! More Seriously: (C) both commands above output "IST" +# for both Israel Standard Time (+0200) AND India Standard Time (+0530). Etc! +# +# While Ansible provides 2 other vars that (slightly) help disambiguate +# (ansible_date_time.tz_dst and ansible_date_time.tz_offset), there's a far +# better way -- which is to read the System TZ directly from Linux: +# +# timedatectl show -p Timezone --value +# +# This takes care of essentially everything (e.g. output "America/New_York") +# by checking (1) symlink /etc/localtime then (2) text file /etc/timezone if +# nec, then (3) if neither exist, "UTC" is declared (correctly!) Potential +# drawback: timedatectl is not easily usable within chroot environments. + +# 2025-01-29: Current GitHub Actions chroot environments for RPi (using guyot/arm-runner-action@v2) surface this error, after PR #3927 mainlined php-settings.yml... +# "System has not been booted with systemd as init system (PID 1). Can't operate.\nFailed to connect to bus: Host is down" +# ...which might be mitigated in 2 ways: +# 1) Try spawning these "guyot/arm-runner-action@v2" GHA workflows with... use_systemd_nspawn: true +# 2) Weaken timedatectl command just below, trying this instead... shell: readlink /etc/localtime | sed 's#^/usr/share/zoneinfo/##' + +- name: Extract Time Zone from symlink /etc/localtime, text file /etc/timezone, or if all else fails declare Etc/UTC + # command: timedatectl show -p Timezone --value + # 2025-02-01: "guyot/arm-runner-action@v2" GHA workflows don't seem to work with "use_systemd_nspawn: true", so hack in the equivalent of timedatectl... + shell: tmp=$(readlink /etc/localtime) && echo $tmp | sed 's|^/usr/share/zoneinfo/||' || cat /etc/timezone || echo Etc/UTC + register: tz_cli + +- name: Store 'date.timezone = {{ tz_cli.stdout }}' (from above) in /etc/php/{{ php_version }}/fpm/php.ini and /etc/php/{{ php_version }}/cli/php.ini + ini_file: + path: "{{ item }}" + section: Date + option: date.timezone + value: "{{ tz_cli.stdout }}" # e.g. America/New_York or UTC + with_items: + - /etc/php/{{ php_version }}/fpm/php.ini + - /etc/php/{{ php_version }}/cli/php.ini + + +# WARNING: 'nginx_high_php_limits: True' (especially!) might cause excess use of +# RAM/disk or other resources! Five original values below chosen by @kananigit +# and @ericnitschke on 2018-09-19: https://github.com/iiab/iiab/issues/1147 + +# 2020-03-08: IIAB DOES NOT SUPPORT UNINSTALLING APPS, so additional clauses +# (to reset/restore PHP's own defaults) are not necessary at this time. + +# 2021-06-28: WITH PHP 8.x, MOODLE'S CLI INSTALLER UNFORTUNATELY *REQUIRES* +# editing /etc/php/{{ php_version }}/cli/php.ini (below) -- though during +# regular operation it uses: .../fpm/php.ini +# And in the past it used: .../apache2/php.ini + + +- name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/fpm/php.ini for LIGHTWEIGHT use of Matomo/Nextcloud/PBX/WordPress (allow file size up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" + lineinfile: + path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } + - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } + - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } + - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } + - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is 128M / Nextcloud requests 512M' } + - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } + when: not nginx_high_php_limits and not moodle_install and not nextcloud_install + +- name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/cli/php.ini for LIGHTWEIGHT use of Matomo/Nextcloud/PBX/WordPress (allow file size up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" + lineinfile: + path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } + - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } + - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } + - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } + - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is -1 (i.e. no limit) / Nextcloud requests 512M' } + - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } + when: not nginx_high_php_limits and not moodle_install and not nextcloud_install + + +- name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/fpm/php.ini for Moodle/Nextcloud or INTENSIVE use of Matomo/PBX/WordPress (allow file size up to 10000MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" + lineinfile: + path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 10000M ; default is 2M' } + - { regexp: '^post_max_size', line: 'post_max_size = 10000M ; default is 8M' } + - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } + - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } + - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is 128M / Nextcloud requests 512M' } + - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } + when: nginx_high_php_limits or moodle_install or nextcloud_install + +- name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/cli/php.ini for Moodle/Nextcloud or INTENSIVE use of Matomo/PBX/WordPress (allow file size up to 10000MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" + lineinfile: + path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + with_items: + - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 10000M ; default is 2M' } + - { regexp: '^post_max_size', line: 'post_max_size = 10000M ; default is 8M' } + - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } + - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } + - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is -1 (i.e. no limit) / Nextcloud requests 512M' } + - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } + when: nginx_high_php_limits or moodle_install or nextcloud_install + + +# To tweak .ini files, Ansible's ini_file is normally better than lineinfile: +# https://docs.ansible.com/ansible/latest/collections/community/general/ini_file_module.html +# +# But for the 6 * 4 above, explanatory comments (inserted by lineinfile) offer +# important context to implementers modifying both php.ini files after the fact. + + +- name: Restart 'php{{ php_version }}-fpm' systemd service + systemd: + name: php{{ php_version }}-fpm + state: restarted + +- name: "Set 'php_settings_done: True' so php-settings.yml runs just once (per Ansible run)" + set_fact: + php_settings_done: True + + +# - debug: +# msg: 'THE 5 ANSIBLE STANZAS BELOW ONLY RUN... when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install' + +# - block: # 5-STANZA BLOCK BEGINS + +# # roles/nginx has installed pkg 'php{{ php_version }}-fpm' in 3-base-server + +# - name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/fpm/php.ini for LIGHTWEIGHT use of Matomo/Nextcloud/PBX/WordPress (allow photos/docs up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" +# lineinfile: +# path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini +# regexp: "{{ item.regexp }}" +# line: "{{ item.line }}" +# with_items: +# - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } +# - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } +# - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } +# - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } +# - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is 128M / Nextcloud requests 512M' } +# - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } +# when: not nginx_high_php_limits and not moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install + +# - name: "Enact 'nginx_high_php_limits: False' in /etc/php/{{ php_version }}/cli/php.ini for LIGHTWEIGHT use of Matomo/Nextcloud/PBX/WordPress (allow photos/docs up to 100MB, 100s timeouts, with 2 PHP system defaults: memory_limit = 128M, max_input_vars = 1000)" +# lineinfile: +# path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini +# regexp: "{{ item.regexp }}" +# line: "{{ item.line }}" +# with_items: +# - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 100M ; default is 2M' } +# - { regexp: '^post_max_size', line: 'post_max_size = 100M ; default is 8M' } +# - { regexp: '^max_execution_time', line: 'max_execution_time = 100 ; default is 30' } +# - { regexp: '^max_input_time', line: 'max_input_time = 100 ; default is 60' } +# - { regexp: '^memory_limit', line: 'memory_limit = 128M ; default is -1 (i.e. no limit) / Nextcloud requests 512M' } +# - { regexp: '^max_input_vars', line: 'max_input_vars = 1000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } +# when: not nginx_high_php_limits and not moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install + +# # WARNING: This might cause excess use of RAM/disk or other resources! +# # The first 5 values below were chosen by @ericnitschke and @kananigit on +# # 2018-09-19: https://github.com/iiab/iiab/issues/1147 + +# # 2020-03-08: IIAB DOES NOT SUPPORT UNINSTALLING APPS, so additional +# # clauses (to reset/restore PHP's defaults) are not necessary at this time. + +# # 2021-06-28: WITH PHP 8, MOODLE'S CLI INSTALLER UNFORTUNATELY *REQUIRES* +# # editing /etc/php/{{ php_version }}/cli/php.ini (below) -- though during +# # regular operation it uses: .../fpm/php.ini +# # And in the past it used: .../apache2/php.ini + +# - name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/fpm/php.ini for Moodle or INTENSIVE use of Matomo/Nextcloud/PBX/WordPress (allow photos/docs up to 500MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" +# lineinfile: +# path: /etc/php/{{ php_version }}/fpm/php.ini # COMPARE /etc/php/{{ php_version }}/cli/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini +# regexp: "{{ item.regexp }}" +# line: "{{ item.line }}" +# with_items: +# - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 500M ; default is 2M' } +# - { regexp: '^post_max_size', line: 'post_max_size = 500M ; default is 8M' } +# - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } +# - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } +# - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is 128M / Nextcloud requests 512M' } +# - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } +# when: nginx_high_php_limits or moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install + +# - name: "Enact 'nginx_high_php_limits: True' in /etc/php/{{ php_version }}/cli/php.ini for Moodle or INTENSIVE use of Matomo/Nextcloud/PBX/WordPress (allow photos/docs up to 500MB, 300s timeouts, memory_limit = 512M for Nextcloud, max_input_vars = 5000 for Moodle)" +# lineinfile: +# path: /etc/php/{{ php_version }}/cli/php.ini # COMPARE /etc/php/{{ php_version }}/fpm/php.ini AND /etc/php/{{ php_version }}/apache2/php.ini +# regexp: "{{ item.regexp }}" +# line: "{{ item.line }}" +# with_items: +# - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 500M ; default is 2M' } +# - { regexp: '^post_max_size', line: 'post_max_size = 500M ; default is 8M' } +# - { regexp: '^max_execution_time', line: 'max_execution_time = 300 ; default is 30' } +# - { regexp: '^max_input_time', line: 'max_input_time = 300 ; default is 60' } +# - { regexp: '^memory_limit', line: 'memory_limit = 512M ; default is -1 (i.e. no limit) / Nextcloud requests 512M' } +# - { regexp: '^max_input_vars', line: 'max_input_vars = 5000 ; default is 1000 / Moodle 3.11+ requires 5000+ with PHP 8+' } +# when: nginx_high_php_limits or moodle_install # REMINDER: THIS ENTIRE 5-STANZA BLOCK IS ONLY INVOKED... when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install + +# - name: Restart 'php{{ php_version }}-fpm' systemd service +# systemd: +# name: php{{ php_version }}-fpm +# state: restarted + +# when: matomo_install or moodle_install or nextcloud_install or pbx_install or wordpress_install # 5-STANZA BLOCK ENDS. COMPARE allow_www_data_poweroff conditionals below. diff --git a/roles/www_options/templates/020_apache_poweroff.j2 b/roles/www_options/templates/020_www_data_poweroff.j2 similarity index 100% rename from roles/www_options/templates/020_apache_poweroff.j2 rename to roles/www_options/templates/020_www_data_poweroff.j2 diff --git a/roles/yarn/tasks/install.yml b/roles/yarn/tasks/install.yml index 48628d688..331a10474 100644 --- a/roles/yarn/tasks/install.yml +++ b/roles/yarn/tasks/install.yml @@ -1,34 +1,61 @@ -- name: "Yarn | GPG" - apt_key: - url: https://dl.yarnpkg.com/debian/pubkey.gpg - state: present +- name: Record (initial) disk space used + shell: df -B1 --output=used / | tail -1 + register: df1 -- name: "Yarn | Ensure Debian sources list file exists" - file: - path: /etc/apt/sources.list.d/yarn.list - owner: root - mode: '0644' - state: touch -- name: "Yarn | Ensure Debian package is in sources list" - lineinfile: - dest: /etc/apt/sources.list.d/yarn.list - regexp: 'deb https://dl.yarnpkg.com/debian/ stable main' - line: 'deb https://dl.yarnpkg.com/debian/ stable main' - state: present +- name: Yarn | Download apt key to /usr/share/keyrings/yarn.gpg + shell: curl https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn.gpg -- name: "Yarn | Update APT cache" +- name: Yarn | Add signed Yarn PPA to /etc/apt/sources.list.d/dl_yarnpkg_com_debian.list + apt_repository: + repo: "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" + #filename: yarn # If legacy filename yarn.list is preferred + +# 2023-04-01 above avoids DEPRECATED apt-key command & associated problems: +# https://github.com/iiab/iiab/wiki/IIAB-Platforms#etcapttrustedgpg-legacy-keyring-warnings + +# - name: "Yarn | GPG" +# apt_key: +# url: https://dl.yarnpkg.com/debian/pubkey.gpg +# state: present + +# - name: "Yarn | Ensure Debian sources list file exists" +# file: +# path: /etc/apt/sources.list.d/yarn.list +# owner: root +# mode: '0644' +# state: touch + +# - name: "Yarn | Ensure Debian package is in sources list" +# lineinfile: +# dest: /etc/apt/sources.list.d/yarn.list +# regexp: 'deb https://dl.yarnpkg.com/debian/ stable main' +# line: 'deb https://dl.yarnpkg.com/debian/ stable main' +# state: present + +- name: Yarn | Update APT cache apt: update_cache: yes -- name: "Yarn | Install" +- name: Yarn | Install package: name: yarn - state: latest + #state: latest # No need to mention it, with apt # RECORD Yarn AS INSTALLED +- name: Record (final) disk space used + shell: df -B1 --output=used / | tail -1 + register: df2 + +- name: Add 'yarn_disk_usage = {{ df2.stdout|int - df1.stdout|int }}' to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: yarn + option: yarn_disk_usage + value: "{{ df2.stdout|int - df1.stdout|int }}" + - name: "Set 'yarn_installed: True'" set_fact: yarn_installed: True diff --git a/roles/yarn/tasks/main.yml b/roles/yarn/tasks/main.yml index fc1255729..c44758b22 100644 --- a/roles/yarn/tasks/main.yml +++ b/roles/yarn/tasks/main.yml @@ -26,23 +26,31 @@ var: yarn_installed -- name: Install Yarn if 'yarn_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: yarn_installed is undefined +- block: + - name: Install Yarn if 'yarn_installed' not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: yarn_installed is undefined -- name: Add 'yarn' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab_state.yml - section: yarn - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Yarn - - option: description - value: '"Fast, reliable, and secure dependency management. Comparable to npm. Released by Facebook in October 2016."' - - option: yarn_install - value: "{{ yarn_install }}" - - option: yarn_enabled - value: "{{ yarn_enabled }}" + - name: Add 'yarn' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: yarn + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Yarn + - option: description + value: '"Fast, reliable, and secure dependency management. Comparable to npm. Released by Facebook in October 2016."' + - option: yarn_install + value: "{{ yarn_install }}" + - option: yarn_enabled + value: "{{ yarn_enabled }}" + + rescue: + + - name: 'SEE ERROR ABOVE (skip_role_on_error: {{ skip_role_on_error }})' + fail: + msg: "" + when: not skip_role_on_error diff --git a/run-one-role.yml b/run-one-role.yml index c7dc1b98c..c10a42a2b 100644 --- a/run-one-role.yml +++ b/run-one-role.yml @@ -3,10 +3,10 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml - - /etc/iiab/iiab_state.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml + - /etc/iiab/iiab_state.yml roles: - { role: 0-init } diff --git a/runrole b/runrole index d29bb900b..4e8657208 100755 --- a/runrole +++ b/runrole @@ -8,13 +8,14 @@ INSTALL=false ENABLED=false REINSTALL=false CWD=`pwd` -ARGS="--extra-vars {" # bash forces {...} to '{...}' for Ansible, SEE BOTTOM +#ARGS="--extra-vars {" +ARGS="--extra-vars {\"skip_role_on_error\":False," # bash forces {...} to '{...}' for Ansible, SEE BOTTOM (IFS-like issue) INVENTORY=ansible_hosts PLAYBOOK=run-one-role.yml if [ ! -f $PLAYBOOK ]; then echo "Exiting: IIAB Playbook not found." - echo "Please run this in /opt/iiab/iiab (top level of the git repo)." + echo "Please run this in /opt/iiab/iiab (top level of git repo)." exit 1 fi @@ -27,28 +28,48 @@ if [ $# -eq 0 ] || [ "$2" == "--reinstall" ] || [ "$3" == "--reinstall" ]; then exit 0 fi -# 2020-08-05: yes /etc/iiab/iiab_state.yml is necessary, but we DON'T -# want to encourage sloppy operators to delete/touch this file. -# -# (The iiab_state.yml file should always be created by ./iiab-install, -# for IIAB's Ansible roles that then auto-populate this file.) -# -# FYI ./iiab-network and ./iiab-configure likewise warn operators (IN RED!) -# if they try to run without the existence of /etc/iiab/iiab_state.yml : -# -# ERROR! vars file /etc/iiab/iiab_state.yml was not found -# -# Needed for Stages 1-3 if not installed yet -#if [ ! -f $IIAB_STATE_FILE ]; then -# touch $IIAB_STATE_FILE -#fi - if [ "$1" == "--reinstall" ]; then - ARGS="$ARGS\"reinstall\":True," # Needs boolean not string so use JSON list + ARGS="$ARGS\"reinstall\":True," # Needs boolean not string so use JSON list REINSTALL=true shift fi + +# 4 snippets to guide -> bootstrap -> accelerate role debugging on bare OS's: + +mkdir -p /etc/iiab # -p avoids errors, effectively like '|| true' +if [ ! -f /etc/iiab/local_vars.yml ]; then + echo -e "\n\e[1mEXITING: /opt/iiab/iiab/runrole REQUIRES /etc/iiab/local_vars.yml\e[0m\n" >&2 + + echo -e "(1) See http://FAQ.IIAB.IO -> What is local_vars.yml and how do I customize it?" >&2 + echo -e "(2) SMALL/MEDIUM/LARGE samples are included in /opt/iiab/iiab/vars" >&2 + echo -e "(3) NO TIME FOR DETAILS? RUN INTERNET-IN-A-BOX'S FRIENDLY 1-LINE INSTALLER:\n" >&2 + + echo -e ' https://download.iiab.io\n' >&2 + + exit 1 +fi + +# In comparison, ./iiab-network and ./iiab-configure warn operators (IN RED) +# if run without the existence of /etc/iiab/iiab_state.yml +if [ ! -f $IIAB_STATE_FILE ]; then # touch $IIAB_STATE_FILE + echo -e "\n\e[1mCreating... $IIAB_STATE_FILE\e[0m" + cat > $IIAB_STATE_FILE << EOF +# DO *NOT* MANUALLY EDIT THIS, THANKS! +# IIAB does NOT currently support uninstalling apps/services. + +EOF +fi + +if ! [[ $(command -v ansible) ]]; then + echo -e "\n\e[1mPlease install Ansible, by running:\n\nsudo /opt/iiab/iiab/scripts/ansible\e[0m\n" + exit 1 +fi + +mkdir -p /etc/ansible/facts.d +cp scripts/local_facts.fact /etc/ansible/facts.d/local_facts.fact + + ROLE_VAR=$1 # Ansible role name & var name sometimes differ :/ if [ $1 == "calibre-web" ]; then ROLE_VAR=calibreweb @@ -104,13 +125,14 @@ if ! $INSTALL; then ARGS="$ARGS\"${ROLE_VAR}_install\":True," fi + if [ $# -eq 2 ]; then export ANSIBLE_LOG_PATH="$2" else export ANSIBLE_LOG_PATH="$CWD/iiab-debug.log" fi -ARGS="$ARGS\"role_to_run\":\"$1\"}" # $1 works like \"$1\" if str validated +ARGS="$ARGS\"role_to_run\":\"$1\"}" # $1 works like \"$1\" if str type validated CMD="ansible-playbook -i $INVENTORY $PLAYBOOK --connection=local $ARGS" echo -e "\e[1mbash will now run this, adding single quotes around the {...} curly braces:\e[0m\n\n$CMD\n" ansible -m setup -i $INVENTORY localhost --connection=local | grep python diff --git a/runroles-base.yml b/runroles-base.yml index 55bcb1efd..8df997790 100644 --- a/runroles-base.yml +++ b/runroles-base.yml @@ -3,9 +3,9 @@ become: yes vars_files: - - vars/default_vars.yml - - vars/{{ ansible_local.local_facts.os_ver }}.yml - - /etc/iiab/local_vars.yml + - vars/default_vars.yml + - vars/{{ ansible_local.local_facts.os_ver }}.yml + - /etc/iiab/local_vars.yml roles: - { role: 0-init } diff --git a/scripts/ansible b/scripts/ansible index 82f9bbde4..22c8cbacd 100755 --- a/scripts/ansible +++ b/scripts/ansible @@ -4,11 +4,11 @@ # https://stackoverflow.com/questions/9952177/whats-the-meaning-of-the-parameter-e-for-bash-shell-command-line/9952249 # PLZ SEE http://FAQ.IIAB.IO > "What is Ansible and what version should I use?" -# https://github.com/iiab/iiab/wiki/Technical-Contributors-Guide#understanding-ansible +# https://github.com/iiab/iiab/wiki/Technical-Contributors-Guide#female_detective-understanding-ansible APT_PATH=/usr/bin # Avoids problematic /usr/local/bin/apt on Linux Mint -CURR_VER=undefined # Ansible version you currently have installed -GOOD_VER=2.12.1 # Orig for 'yum install [rpm]' & XO laptops (pip install) +CURR_VER=undefined # Ansible version you have installed, e.g. [core 2.18.3] +GOOD_VER=2.18.3 # Orig for 'yum install [rpm]' & XO laptops (pip install) # 2021-06-22: The apt approach (with PPA source in /etc/apt/sources.list.d/ and # .gpg key etc) are commented out with ### below. Associated guidance/comments @@ -25,27 +25,39 @@ GOOD_VER=2.12.1 # Orig for 'yum install [rpm]' & XO laptops (pip install) # 'lsb_release -sc' gives Mint 20 codename 'ulyana' etc: (TOO FINE-GRAINED) ###if grep -q buster /etc/os-release /etc/debian_version; then -### CODENAME=bionic # Debian 10, RaspiOS 10 & Buster-like distros +### CODENAME=bionic # Debian 10, RasPiOS 10 & Buster-like distros ###else -### CODENAME=focal # Debian 11+, RaspiOS 11+, Ubuntu 20.04+, Mint 20+ (ETC) +### CODENAME=focal # Debian 11+, RasPiOS 11+, Ubuntu 20.04+, Mint 20+ (ETC) ###fi # APRIL 2021 - ansible-base (2.10) was renamed to ansible-core (2.11+): # https://www.ansible.com/blog/ansible-3.0.0-qa # https://github.com/ansible/ansible/tags -# https://github.com/ansible/ansible/releases (OLD) +# https://github.com/ansible/ansible/releases +# https://github.com/ansible/ansible/commits/stable-2.18 +# https://github.com/ansible/ansible/blob/stable-2.18/changelogs/CHANGELOG-v2.18.rst +# https://github.com/ansible/ansible/commits/stable-2.17 +# https://github.com/ansible/ansible/blob/stable-2.17/changelogs/CHANGELOG-v2.17.rst +# https://github.com/ansible/ansible/commits/stable-2.16 +# https://github.com/ansible/ansible/blob/stable-2.16/changelogs/CHANGELOG-v2.16.rst +# https://github.com/ansible/ansible/commits/stable-2.15 +# https://github.com/ansible/ansible/blob/stable-2.15/changelogs/CHANGELOG-v2.15.rst +# https://github.com/ansible/ansible/commits/stable-2.14 +# https://github.com/ansible/ansible/blob/stable-2.14/changelogs/CHANGELOG-v2.14.rst +# https://github.com/ansible/ansible/commits/stable-2.13 +# https://github.com/ansible/ansible/blob/stable-2.13/changelogs/CHANGELOG-v2.13.rst # https://github.com/ansible/ansible/commits/stable-2.12 # https://github.com/ansible/ansible/blob/stable-2.12/changelogs/CHANGELOG-v2.12.rst -# https://github.com/ansible/ansible/blob/devel/docs/docsite/rst/roadmap/ROADMAP_2_12.rst # https://pypi.org/project/ansible-core/ -# https://pypi.org/project/ansible-base/ -# https://releases.ansible.com/ansible-core/ +# https://pypi.org/project/ansible-base/ (OLD) +# https://releases.ansible.com/ansible-core/ (OLD) # https://releases.ansible.com/ansible-base/ (OLD) # https://launchpad.net/~ansible # https://launchpad.net/~ansible-gha # https://launchpad.net/~ansible/+archive/ubuntu/ansible +# https://launchpad.net/~ansible/+archive/ubuntu/ansible/+packages # https://launchpad.net/~ansible/+archive/ubuntu/ansible-2.10 (OLD) -# http://ppa.launchpad.net/ansible/ansible/ubuntu/pool/main/a/ansible/ +# http://ppa.launchpad.net/ansible/ansible/ubuntu/pool/main/a/ansible/ (OLD) # http://ppa.launchpad.net/ansible/ansible/ubuntu/pool/main/a/ansible-core/ # FYI .travis.yml installs ansible-core in a slightly different way (PRs #2689 & #2743) @@ -59,18 +71,18 @@ GOOD_VER=2.12.1 # Orig for 'yum install [rpm]' & XO laptops (pip install) #pip3 install --upgrade ansible-core # Then start a new shell, so /usr/local/bin works #ansible-galaxy collection install -r collections.yml -# TEMPORARILY USE ansible-base 2.10.16 (REMOVE W/ "pip3 uninstall ansible-base") +# TEMPORARILY USE ansible-base 2.10.17 (REMOVE W/ "pip3 uninstall ansible-base") #apt install python3-pip -#pip3 install ansible-base==2.10.16 # Start new shell, so /usr/local/bin works +#pip3 install ansible-base==2.10.17 # Start new shell, so /usr/local/bin works # TEMPORARILY USE ANSIBLE 2.9.27 (REMOVE IT WITH "pip3 uninstall ansible") #apt install python3-pip #pip3 install ansible==2.9.27 # TEMPORARILY USE ANSIBLE 2.4.2 DUE TO 2.4.3 MEMORY BUG. Details: iiab/iiab#669 -#echo "Install http://download.iiab.io/packages/ansible_2.4.2.0-1ppa~xenial_all.deb" +#echo "Install https://download.iiab.io/packages/ansible_2.4.2.0-1ppa~xenial_all.deb" #cd /tmp -#wget http://download.iiab.io/packages/ansible_2.4.2.0-1ppa~xenial_all.deb +#wget https://download.iiab.io/packages/ansible_2.4.2.0-1ppa~xenial_all.deb #apt -y --allow-downgrades install ./ansible_2.4.2.0-1ppa~xenial_all.deb export DEBIAN_FRONTEND=noninteractive @@ -84,15 +96,15 @@ echo -e "RECOMMENDED PREREQUISITES:" echo -e "(1) Verify you're online" echo -e "(2) Remove all prior versions of Ansible using..." echo -e " 'apt purge ansible-core' and/or 'pip3 uninstall ansible-core' and/or" -echo -e " 'apt purge ansible-base' and/or 'pip3 uninstall ansible-base' and/or" +#echo -e " 'apt purge ansible-base' and/or 'pip3 uninstall ansible-base' and/or" echo -e " 'apt purge ansible' and/or 'pip3 uninstall ansible'" -echo -e "(3) Remove all lines containing 'ansible' from..." -echo -e " /etc/apt/sources.list and /etc/apt/sources.list.d/*\n" +#echo -e "(3) Remove all lines containing 'ansible' from..." +#echo -e " /etc/apt/sources.list and /etc/apt/sources.list.d/*\n" -echo -e "IIAB INSTALL INSTRUCTIONS: (OLDER, MANUAL APPROACH)" -echo -e "https://github.com/iiab/iiab/wiki/IIAB-Installation#do-everything-from-scratch\n" +#echo -e "IIAB INSTALL INSTRUCTIONS: (OLDER, MANUAL APPROACH)" +#echo -e "https://github.com/iiab/iiab/wiki/IIAB-Installation#do-everything-from-scratch\n" -if [ $(command -v ansible) ]; then # "command -v" is POSIX compliant; also catches built-in commands like "cd" +if [ "$(command -v ansible)" ]; then # "command -v" is POSIX compliant; also catches built-in commands like "cd" CURR_VER=$(ansible --version | head -1 | cut -f 2- -d " ") # Above works with 'ansible [core 2.11.0rc2]' -- these old ways do not: #CURR_VER=$(ansible --version | head -1 | awk '{print $2}') @@ -105,7 +117,7 @@ echo -e "(Internet-in-a-Box requests ansible-core $GOOD_VER or higher)\n" # Code above designed to work on all Linux distributions, to preserve options, # in support of any volunteer(s) wanting to port IIAB to a new Linux/distro. -if [ ! -f /etc/debian_version ]; then # e.g. RaspiOS, Ubuntu, Mint & Debian +if [ ! -f /etc/debian_version ]; then # e.g. RasPiOS, Ubuntu, Mint & Debian echo -e "\nEXITING: /etc/debian_version FILE NOT FOUND. Linux OS support info here:" echo -e " https://github.com/iiab/iiab/wiki/IIAB-Platforms\n" exit 1 @@ -124,6 +136,10 @@ fi ###echo "deb [signed-by=/usr/share/keyrings/iiab-ansible-keyring.gpg] http://ppa.launchpad.net/ansible/ansible/ubuntu $CODENAME main" \ ### > /etc/apt/sources.list.d/iiab-ansible.list +# 2022-11-09: ansible-core 2.12.10+ PPA works on 32-bit RasPiOS, until upstream wheels -> cryptography is fixed (PR #3421) +#echo "deb [signed-by=/usr/share/keyrings/iiab-ansible-keyring.gpg] http://ppa.launchpad.net/ansible/ansible/ubuntu focal main" \ +# > /etc/apt/sources.list.d/iiab-ansible.list + # In future we might instead consider 'add-apt-repository ppa:ansible/ansible' # or 'apt-add-repository ppa:ansible/bionic/ansible' etc, e.g. for streamlined # removal using 'apt-add-repository -r' -- however that currently requires @@ -132,7 +148,7 @@ fi # 2020-08-20: TEMP WORKAROUND (REVERT TO ANSIBLE 2.9.6) MITIGATING # iiab/iiab#2481 (Ansible 2.9.12 and 2.10.0's 666-TO-600 file permissions -# problem). This workaround installs 2.9.6-1ppa~disco onto RaspiOS, from +# problem). This workaround installs 2.9.6-1ppa~disco onto RasPiOS, from # https://launchpad.net/~ansible/+archive/ubuntu/ansible #echo "deb http://ppa.launchpad.net/ansible/ansible/ubuntu disco main" \ # > /etc/apt/sources.list.d/iiab-ansible.list @@ -143,16 +159,19 @@ fi ###cp /opt/iiab/iiab/scripts/iiab-ansible-keyring.gpg /usr/share/keyrings/iiab-ansible-keyring.gpg #chmod 644 /usr/share/keyrings/iiab-ansible-keyring.gpg +# 2022-11-09: ansible-core 2.12.10+ PPA works on 32-bit RasPiOS, until upstream wheels -> cryptography is fixed (PR #3421) +#cp /opt/iiab/iiab/scripts/iiab-ansible-keyring.gpg /usr/share/keyrings/iiab-ansible-keyring.gpg + ###echo -e 'PPA source "deb [signed-by=/usr/share/keyrings/iiab-ansible-keyring.gpg] http://ppa.launchpad.net/ansible/ansible/ubuntu '$CODENAME' main"' ###echo -e "successfully saved to /etc/apt/sources.list.d/iiab-ansible.list\n" ###echo -e "IF *OTHER* ANSIBLE SOURCES APPEAR BELOW, PLEASE MANUALLY REMOVE THEM TO" ###echo -e 'ENSURE ANSIBLE UPDATES CLEANLY: (then re-run this script to be sure!)\n' ###grep '^deb .*ansible' /etc/apt/sources.list /etc/apt/sources.list.d/*.list | grep -v '^/etc/apt/sources.list.d/iiab-ansible.list:' || true # Override bash -e (instead of aborting at 1st error) -echo -e "\napt update; apt install python3-pip # Also installs 'python3-setuptools' and 'python3' etc" +#echo -e "\napt update; apt install python3-pip # Also installs 'python3-setuptools' and 'python3' etc" #echo -e "https://github.com/iiab/iiab/blob/master/scripts/ansible.md\n" -$APT_PATH/apt update -$APT_PATH/apt -y install python3-pip +#$APT_PATH/apt update +#$APT_PATH/apt -y install python3-pip # 2021-07-29: # 'python3-packaging' dropped for now @@ -172,9 +191,101 @@ $APT_PATH/apt -y install python3-pip # cache system-wide before installing: # https://stackoverflow.com/questions/9510474/removing-pips-cache/61762308#61762308 # https://github.com/iiab/iiab/pull/3022 -pip3 config --global set global.no-cache-dir false -echo -e "\n\n'pip3 install --upgrade ansible-core' will now run:\n" -pip3 install --upgrade ansible-core # ansible-core 2.12 (released 2021-11-08) requires Python >= 3.8 +#pip3 config --global set global.no-cache-dir false + +#if ! uname -m | grep -q 64; then + # echo "2022-11-09: ansible-core 2.12.10+ PPA works on 32-bit RasPiOS, using /etc/apt/sources.list.d/iiab-ansible.list, until upstream wheels -> cryptography is fixed (PR #3421)" + # $APT_PATH/apt -y --allow-downgrades install ansible-core +# echo -e "\n\n'pip3 install cryptography==39.0.2' will now run:\n" +# pip3 install --break-system-packages cryptography==39.0.2 || pip3 install cryptography==39.0.2 # PR #3459 https://www.piwheels.org/project/cryptography/ -- WAS 37.0.4 which as of 2023-01-06 was the "latest compatible with ansible-core available via piwheels.org" +#fi + +#echo -e "\n\n'pip3 install --upgrade ansible-core' will now run:\n" # REMINDER: ansible-core 2.12 (released 2021-11-08) requires Python >= 3.8 +#pip3 install --break-system-packages --upgrade ansible-core || pip3 install --upgrade ansible-core # PR #3493: Revert to old syntax if pip < 23.0.1, as flag --break-system-packages (for Python 3.11+ / PEP 668) is brand new in Feb 2023: https://github.com/pypa/pip/pull/11780 + +echo -e "\napt update; apt install python3-venv" +$APT_PATH/apt update +$APT_PATH/apt -y install python3-venv + +# 2023-09-08 PR #3634: 'apt install ansible-core' is overweight, but works on +# "32-bit" RasPiOS 12 (@EMG70 set 'arm_64bit=0' in /boot/config.txt per #3516 +# to force boot its 32-bit kernel; its 64-bit kernel should work too!) +# IN SHORT: This ugly hack appears sufficient for all "32-bit" Bookworm+ OS's +# (similar to 32-bit Debian 12 on AMD/Intel a month ago, i.e. PR #3617). +# 2023-09-10 PR #3637: Even safer test than querying for Debian 12+ -- verify +# that apt package ansible-core is truly available: +#if ! dpkg --print-architecture | grep -q 64 && apt-cache show ansible-core > /dev/null; then +#if ! dpkg --print-architecture | grep -q 64 && ! grep -q ^11 /etc/debian_version; then +# 2023-09-10 PR #3632: Revert above #3634 and #3637 trying /etc/pip.conf w/ cryptography 41.0.3 +if [[ $(dpkg --print-architecture) == "i386" ]] && apt-cache show ansible-core > /dev/null; then + # 2023-08-10 #3613/#3615/#3617: apt-not-pip kludge for legacy 32-bit i386 + # (DEBIAN 12+ ETC) avoids #3547 rust/wheels/cryptography compiling mess! + $APT_PATH/apt -y install ansible-core # Bookworm ~= ansible-core 2.14.3 +else + # 2023-03-22: OS's like Ubuntu 23.04 and Debian 12 (e.g. with Python 3.11+) ask + # that virtual environments (venv) be used to safely isolate pip installs: + # https://peps.python.org/pep-0668 + + # 2023-09-08: NEW WAY ANSIBLE RECOMMENDS? https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html + # $APT_PATH/apt -y install pipx # Typically adds 50+ packages! + # pipx install ansible-core + # pipx ensurepath # Adds /root/.local/bin to $PATH -- next time you open a shell -- e.g. for /root/.local/bin/ansible -> /root/.local/pipx/venvs/ansible-core/bin/ansible + # Or, to install package globally for multi-user access: (pypa/pipx#754) + # PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install ansible-core + + # 2023-10-11: RasPiOS Bookworm doc for Python with venv (PEP 668 now enforced!) + # https://www.raspberrypi.com/documentation/computers/os.html#python-on-raspberry-pi + # https://www.raspberrypi.com/documentation/computers/os.html#using-pip-with-virtual-environments + + echo -e "\nCreate virtual environment for Ansible" + python3 -m venv /usr/local/ansible + + # 2023-09-10: Work around #3526 "32-bit" RasPiOS 12 pre-release issue... + # 'Package issue: cryptography 41.0.3 leads to cffi 1.15.1 failure on + # "32-bit" Raspberry Pi OS [REASON: /etc/pip.conf missing on some Bookworm + # pre-releases' == https://github.com/piwheels/packages/issues/390 + if ! [ -f /etc/pip.conf ] && [ -f /etc/rpi-issue ]; then + cat > /etc/pip.conf << EOF +[global] +extra-index-url=https://www.piwheels.org/simple +EOF + fi + + # "if not ubuntu" (covers RasPiOS & Debian) would also work, but is overbroad: + # if ! grep -qi ubuntu /etc/os-release; then + # + # if [ -f /etc/rpi-issue ] && [[ $(dpkg --print-architecture) == armhf ]]; then + # + # 2023-03-24 #3547 similar to #3459 re: cryptography, piwheels, rust. + # Release problems chart: https://www.piwheels.org/project/cryptography/ + # if ! dpkg --print-architecture | grep -q 64; then # 32-bit in general! + # 2023-09-07: Commenting out cryptography 40.0.1 below, as @EMG70 evaluates + # new upstream piwheels fix (e.g. cryptography 41.0.3 for now) + # on pre-release 32-bit RasPiOS 12... (#3526) + # if [[ $(dpkg --print-architecture) == armhf ]]; then # 32-bit ARM + # # 2023-09-30: cryptography 40.0.1 and 41.0.4 both fail for now, see #3650 + # $APT_PATH/apt -y install libffi-dev python3-dev + # /usr/local/ansible/bin/python3 -m pip install cryptography==41.0.3 + # # else + # # 2023-08-10: 'apt install rustc pkg-config libssl-dev' was not enough! + # # So we use apt to install cryptography 38.0.4 for Debian 12.1 -- where + # # `dpkg --print-architecture` was i386 and `uname -m` was i686: + # # $APT_PATH/apt -y install python3-cryptography + # fi + + # 2023-05-22: 2.14.6 was better than 2.15.0 for FreePBX (#3588, ansible/ansible#80863) + # 2023-10-01 #3650: --prefer-binary or --only-binary ensure you get wheels, + # even if they're not the very latest release -- thereby avoiding compiling + # messes -- and obviating the need for these 2: (above, both commented out) + # - 'apt -y install libffi-dev python3-dev' + # - painstaking pinning of cryptography or cffi (etc) to older version #s + /usr/local/ansible/bin/python3 -m pip install --prefer-binary --upgrade ansible-core + echo -e "\nCreate symlinks /usr/local/bin/ansible* -> /usr/local/ansible/bin/ansible*" + cd /usr/local/ansible/bin + for bin in ansible*; do + ln -sf /usr/local/ansible/bin/"$bin" /usr/local/bin/"$bin" + done +fi # (Re)running collection installs appears safe, with --force-with-deps to force # upgrade of collection and dependencies it pulls in. Note Ansible may support @@ -197,7 +308,7 @@ ansible-galaxy collection install --force-with-deps \ echo -e "\n\nSUCCESS! PLEASE VERIFY ANSIBLE WITH COMMANDS LIKE:\n" echo -e " ansible --version" -echo -e " pip3 show ansible-core" +echo -e " /usr/local/ansible/bin/pip3 show ansible-core" echo -e ' apt -a list "ansible*"' -echo -e " ansible-galaxy collection list\n" -echo -e "WARNING: Start a new Linux shell, if it changed from /usr/bin to /usr/local/bin\n\n" +echo -e " ansible-galaxy collection list\n\n" +#echo -e "WARNING: Start a new Linux shell, if it changed from /usr/bin to /usr/local/bin\n\n" diff --git a/scripts/iiab-apps-to-be-installed b/scripts/iiab-apps-to-be-installed new file mode 100755 index 000000000..84b6e2f11 --- /dev/null +++ b/scripts/iiab-apps-to-be-installed @@ -0,0 +1,44 @@ +#!/bin/bash + +# Lists IIAB Apps set to install BUT not yet installed (according to /etc/iiab/iiab_state.yml) + +iiab_var_value() { + v1=$(grep "^$1:\s" /opt/iiab/iiab/vars/default_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + v2=$(grep "^$1:\s" /etc/iiab/local_vars.yml | tail -1 | sed "s/^$1:\s\+//; s/#.*//; s/\s*$//; s/^\(['\"]\)\(.*\)\1$/\2/") + [[ $v2 != "" ]] && echo $v2 || echo $v1 # [ "$v2" ] ALSO WORKS +} + +# https://askubuntu.com/questions/1250974/user-root-cant-write-to-file-in-tmp-owned-by-someone-else-in-20-04-but-can-in +# https://unix.stackexchange.com/questions/503111/group-permissions-for-root-not-working-in-tmp +[[ $(id -un) == "root" ]] && + rm -f /tmp/iiab-apps-list /tmp/iiab-apps-to-be-installed + +# 2022-06-18: 40 apps (list not quite complete) +#grep -l _installed: /opt/iiab/iiab/roles/*/tasks/install.yml | cut -d/ -f6 > /tmp/iiab-apps-list + +# 2022-06-18: 46 apps (list incorrect) -- adds these 6: iiab_admin, minetest, network (HAS NO _installed VAR), pylibs, www_base, www_options +#grep -l _installed: /opt/iiab/iiab/roles/*/tasks/* | cut -d/ -f6 | sort | uniq > /tmp/iiab-apps-list + +# 2022-06-18: 50 apps (list long but ok!) -- adds these 10: dansguardian, dhcpd, iiab_admin, minetest, named, pylibs, squid, wondershaper, www_base, www_options +grep -hro '[A-Za-z_][A-Za-z_]*_installed: True' --exclude-dir=0-DEPRECATED-ROLES /opt/iiab/iiab/roles | sed 's/_installed: True$//' | sort | uniq > /tmp/iiab-apps-list + +# Non-root CANNOT rm files from /tmp, but CAN write to them (unlike root!!) +# This ALSO creates the file (useful when "Apps2B" == 0, for iiab-summary etc) +truncate -s 0 /tmp/iiab-apps-to-be-installed + +# So other (non-root) users CAN later write to these, even if they CAN'T chmod! +chmod 777 /tmp/iiab-apps-list /tmp/iiab-apps-to-be-installed 2>/dev/null + +while read app; do + if [[ $app == "calibre-web" ]]; then + app=calibreweb + elif [[ $app == "osm-vector-maps" ]]; then + app=osm_vector_maps + fi + + # echo ${app}_install: $(iiab_var_value ${app}_install) + + if [[ $(iiab_var_value ${app}_install) =~ ^[Tt]rue$ ]] && ! grep -q "${app}_installed: True" /etc/iiab/iiab_state.yml; then + echo $app | tee -a /tmp/iiab-apps-to-be-installed + fi +done < /tmp/iiab-apps-list diff --git a/scripts/iiab-diagnostics b/scripts/iiab-diagnostics index 1368a58a8..193ba4fc7 100755 --- a/scripts/iiab-diagnostics +++ b/scripts/iiab-diagnostics @@ -4,13 +4,23 @@ # PLEASE SEE /opt/iiab/iiab/scripts/iiab-diagnostics.README.md OR ONLINE HERE: # https://github.com/iiab/iiab/blob/master/scripts/iiab-diagnostics.README.md -IIAB_RELEASE=`cat /etc/iiab/iiab.env | grep IIAB_RELEASE | cut -d'=' -f2` -OS_VER=`cat /etc/iiab/iiab.env | grep OS_VER | cut -d'=' -f2` -#HASH=`cd /opt/iiab/iiab; git log --pretty=format:'%h' -n 1` -HASH1=`cd /opt/iiab/iiab; git log --pretty=format:'%H' -n 1` -HASH2=`cd /opt/iiab/iiab-admin-console; git log --pretty=format:'%H' -n 1` +IIAB_RELEASE=$(cat /etc/iiab/iiab.env | grep IIAB_RELEASE | cut -d'=' -f2) +OS_VER=$(cat /etc/iiab/iiab.env | grep OS_VER | cut -d'=' -f2) YMDT=$(date +%F_%T_%Z) +# git config --global --add safe.directory /opt/iiab/iiab # Nec below, if non-root +# HASH1=$(cd /opt/iiab/iiab; git log --pretty=format:'%H' -n 1) # --pretty=format:'%h' (8 chars) +# BRANCH1=$(cd /opt/iiab/iiab; git branch --show-current) +# REMOTE_URL1=$(cd /opt/iiab/iiab; git config remote.$(git config branch.$BRANCH1.remote).url) +# PR_COUNT1=$(cd /opt/iiab/iiab; git log "$(git describe --tags --abbrev=0)..HEAD" --oneline --grep='Merge pull request' | wc -l) +# TAG_COMMITS1=$(cd /opt/iiab/iiab; git describe --tags | sed 's/-[^-]*$//; s/-\([[:digit:]][[:digit:]]*\)$/ (\1 commits)/') +# git config --global --add safe.directory /opt/iiab/iiab-admin-console # Nec below, if non-root +# HASH2=$(cd /opt/iiab/iiab-admin-console; git log --pretty=format:'%H' -n 1) +# BRANCH2=$(cd /opt/iiab/iiab-admin-console; git branch --show-current) +# REMOTE_URL2=$(cd /opt/iiab/iiab-admin-console; git config remote.$(git config branch.$BRANCH2.remote).url) +# PR_COUNT2=$(cd /opt/iiab/iiab-admin-console; git log "$(git describe --tags --abbrev=0)..HEAD" --oneline --grep='Merge pull request' | wc -l) +# TAG_COMMITS2=$(cd /opt/iiab/iiab-admin-console; git describe --tags | sed 's/-[^-]*$//; s/-\([[:digit:]][[:digit:]]*\)$/ (\1 commits)/') + echo -e "\nGathers IIAB diagnostics into 1 file, to accelerate troubleshooting. USAGE:" echo echo -e " iiab-diagnostics" @@ -19,7 +29,7 @@ echo -e " sudo iiab-diagnostics PATH/FILE1 PATH/FILE2 ... # COMPLETE RESU echo echo -ne "Can you provide a \e[1mshort public nickname:\e[0m (no spaces!) " read nickname < /dev/tty -if [ "$nickname" = "" ]; then +if [[ $nickname == "" ]]; then nickname="NONAME" fi @@ -38,12 +48,12 @@ function cat_file_raw() { # $1 = path/filename; $2 = # of lines, for tail echo "FILE EXISTS BUT IS EMPTY!" >> $outfile elif [ $# -eq 1 ]; then echo >> $outfile - # Redact most passwords from /etc/iiab/local_vars.yml, /etc/hostapd/hostapd.conf, /etc/wpa_supplicant/wpa_supplicant.conf, /etc/netplan/*, /etc/network/interfaces, /etc/network/interfaces.d/* ETC -- not much to worry about in /etc/iiab/iiab.ini (' = ') - cat "$1" | sed 's/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\):\).*/\1 [REDACTED]/; s/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\)[= \t]\).*/\1[REDACTED]/' | iconv -t UTF-8//IGNORE >> $outfile + # Redact (mask) most passwords from /etc/iiab/local_vars.yml, /etc/hostapd/hostapd.conf, /etc/wpa_supplicant/wpa_supplicant.conf, /etc/netplan/*, /etc/network/interfaces, /etc/network/interfaces.d/*, /etc/NetworkManager/system-connections/* ETC -- not much to worry about in /etc/iiab/iiab.ini (' = ') + sed 's/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\|wep-key[0-3]\):\).*/\1 [REDACTED]/; s/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\|wep-key[0-3]\)[= \t]\).*/\1[REDACTED]/' "$1" | iconv -t UTF-8//IGNORE | cat -v >> $outfile else # e.g. last 100 lines, maximum echo " ...ITS LAST $2 LINES FOLLOW..." >> $outfile echo >> $outfile - tail -$2 "$1" | sed 's/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\):\).*/\1 [REDACTED]/; s/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\)[= \t]\).*/\1[REDACTED]/' | iconv -t UTF-8//IGNORE >> $outfile + tail -$2 "$1" | sed 's/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\|wep-key[0-3]\):\).*/\1 [REDACTED]/; s/^\(\s*[[:alnum:]#_-]*\(psk\|passphrase\|password\|wep-key[0-3]\)[= \t]\).*/\1[REDACTED]/' | iconv -t UTF-8//IGNORE | cat -v >> $outfile fi echo >> $outfile elif [ -h "$1" ]; then @@ -82,26 +92,41 @@ function cat_dir() { fi } -function cat_cmd() { # $1 = command + params, $2 = explanation +function cat_cmd() { # $1 = command + params, $2 = explanation echo " $1 # $2" echo "=IIAB==========================================================================" >> $outfile - cmd=$(echo "$1" | sed 's/\s.*$//') # Keep command on left; Drop params on right - pth=$(command -v $cmd | sed 's/[^/]*$//') # Keep only path on left; Drop command on right - if [ "$2" = "" ]; then - echo "COMMAND: $pth$1" >> $outfile + cmd=$(echo "$1" | sed 's/^\s*\(\S\S*\)\b.*$/\1/') # Keep command on left; Drop params on right (NEC b/c 'command -v' interprets every word on the line!) + #pth=$(command -v $cmd | sed 's/[^/]*$//') # Keep only path on left; Drop command & params on right + path_cmd=$(command -v $cmd) # Use canonical path on left (would drop params on right, but over-interpret each word as a cmd!) + spc_params=$(echo "$1" | sed 's/^\s*\S\S*\s*/ /;s/\s*$//') # Drop command on left; Keep a single space + params on right; RTrim + #spc_params=$(echo "$1" | sed 's/^\s*\S*//;s/\s*$//;s/^\s\s*/ /') # LTrim + drop original path + command on left; RTrim; Compress whitespace in between + #spc_params=$(echo "$1" | sed 's/^[[:blank:]]*[^[:blank:]]*//;s/[[:blank:]]*$//;s/^[[:blank:]][[:blank:]]*/ /') # Equivalent (POSIX compliant) + if [[ $path_cmd == "" ]]; then + if [[ $2 == "" ]]; then + echo "COMMAND: $1" >> $outfile + else + echo "COMMAND: $1 # $2" >> $outfile + fi else - echo "COMMAND: $pth$1 # $2" >> $outfile + if [[ $2 == "" ]]; then + echo "COMMAND: $path_cmd$spc_params" >> $outfile + else + echo "COMMAND: $path_cmd$spc_params # $2" >> $outfile + fi fi echo >> $outfile - if [ "$pth" = "" ]; then + if [[ $path_cmd == "" ]]; then echo "COMMAND NOT FOUND: $1" >> $outfile else - $(echo "eval $1") >> $outfile # eval is nec within backticks, so | (pipes) work: https://stackoverflow.com/a/7184782 + bash -c "$1" >> $outfile # Works with | (pipes) and 'ls -l /lib/firmware/cypress/*43455*' etc! + #(exec $1 >> $outfile) # Works with | (pipes) and 'ls -l /lib/firmware/cypress/*43455*' etc! Subshell needed (parens) as exec then exits entire shell. + #eval $1 >> $outfile # Should be identical to below, i.e. insufficient -- "eval" combine ARGs into a single string. + #$(echo "eval $1") >> $outfile # "eval" works with | (pipes) per https://stackoverflow.com/a/7184782 BUT globbing like 'ls -l /lib/firmware/cypress/*43455*' FAILS to output lines w/ filenames that contain spaces (ugly IFS issues!) fi echo >> $outfile } -function cat_tail() { # $1 = path/filename; $2 = # of lines, for tail +function cat_tail() { # $1 = path/filename; $2 = # of lines, for tail echo " $1" echo "=IIAB==========================================================================" >> $outfile cat_file_raw "$1" $2 # e.g. last 100 lines, maximum @@ -110,59 +135,52 @@ function cat_tail() { # $1 = path/filename; $2 = # of lines, for tail # START BUILDING UP THE FILE THAT'LL CONTAIN THE DIAGNOSTICS! echo -e "\nCompiling diagnostics..." -echo -e "\n 0. Filename Header + Git Hashes + Raspberry Pi Model + OS" +echo -e "\n 0. HW + SW Quick Summary" echo "This is: $outfile" >> $outfile echo >> $outfile -echo -e "\n\n\n\n0. GIT HASHES + RASPBERRY PI MODEL + OS" >> $outfile -echo >> $outfile -echo "iiab commit: $HASH1" >> $outfile -echo "iiab-admin-console commit: $HASH2" >> $outfile -echo >> $outfile -cat_file /etc/iiab/pr-list-pulled -cat_file /proc/device-tree/model # Should be identical to /sys/firmware/devicetree/base/model -cat_file /etc/rpi-issue -echo "-IIAB-EXPLANATION-OF-THE-ABOVE-------------------------------------------------" >> $outfile +echo -e "\n\n\n0. HW + SW Quick Summary" >> $outfile echo >> $outfile +/opt/iiab/iiab/scripts/iiab-summary | iconv -t UTF-8//IGNORE | cat -v >> $outfile # Make odd chars visible, just in case (e.g. dpaste.com pastebin disallows null chars) if [ -f /etc/rpi-issue ]; then echo "stage2 = Raspberry Pi OS Lite" >> $outfile echo "stage4 = Raspberry Pi OS with desktop" >> $outfile echo "stage5 = Raspberry Pi OS with desktop + recommended software" >> $outfile - echo >> $outfile echo "SEE https://github.com/RPi-Distro/pi-gen#stage-anatomy" >> $outfile -else - echo "(This is NOT Raspberry Pi OS!)" >> $outfile + echo >> $outfile fi -echo >> $outfile -cat_file /etc/issue.net -cat_file /etc/debian_version -cat_cmd 'dpkg --print-architecture' 'RaspiOS-on-PC shows: i386' -cat_cmd 'dpkg --print-foreign-architectures' 'RaspiOS-on-PC shows: amd64' -cat_cmd 'systemctl is-active display-manager.service' 'Graphical Desktop?' -cat_cmd 'grep "^openvpn_" /etc/iiab/local_vars.yml' +if [ -s /tmp/iiab-apps-to-be-installed ]; then + echo "iiab-apps-to-be-installed :" >> $outfile + cat /tmp/iiab-apps-to-be-installed >> $outfile + echo >> $outfile +fi +cat_cmd 'ls -ltr /etc/iiab/install-flags' 'IIAB install flags' -echo -e '\n\n 1. Files Specially Requested: (from "iiab-diagnostics PATH/FILE1 PATH/FILE2")\n' -echo -e '\n\n\n\n1. FILES SPECIALLY REQUESTED (FROM "iiab-diagnostics PATH/FILE1 PATH/FILE2")\n' >> $outfile +echo -e '\n 1. Files Specially Requested: (from "iiab-diagnostics PATH/FILE1 PATH/FILE2")\n' +echo -e '\n\n\n1. FILES SPECIALLY REQUESTED (FROM "iiab-diagnostics PATH/FILE1 PATH/FILE2")\n' >> $outfile for f in "$@"; do cat_file $f done if [ $# -eq 0 ]; then - echo -e " 2. Regular Files:\n" + echo -e " 2. Regular Files etc:\n" else - echo -e "\n 2. Regular Files:\n" + echo -e "\n 2. Regular Files etc:\n" fi -echo -e "\n\n\n\n2. REGULAR FILES\n" >> $outfile +echo -e "\n\n\n2. REGULAR FILES ETC\n" >> $outfile #cat_file /dev/sda # Device "file" test #cat_file /nonsense # Non-existence test #cat_file /opt/iiab/iiab # Directory test #cat_file /tmp/empty-file # Empty file test #cat_file /usr/bin/iiab-support-on # Symlink test cat_file /.iiab-image +cat_file /etc/default/locale # e.g. on Debian 12 +cat_file /etc/locale.conf # e.g. on Debian 13+ and Ubuntu +cat_cmd 'localectl' 'Locale settings' +cat_cmd 'locale -a' 'Available locales' cat_file /etc/iiab/iiab.env cat_file /etc/iiab/iiab.ini -cat_file /etc/iiab/local_vars.yml # Redacts most passwords above +cat_file /etc/iiab/local_vars.yml # Redacts most passwords above cat_file /etc/iiab/iiab_state.yml -#cat_file /etc/iiab/config_vars.yml # No longer common cat_file /etc/resolv.conf cat_file /etc/network/interfaces cat_file /etc/hostapd/hostapd.conf # Redacts most passwords above @@ -176,22 +194,27 @@ cat_file /library/www/html/home/menu.json #cat_file /tmp/all-ansible-vars echo -e "\n 3. Content of Directories: (1-level deep)\n" -echo -e "\n\n\n\n3. CONTENT OF DIRECTORIES (1-LEVEL DEEP)\n" >> $outfile +echo -e "\n\n\n3. CONTENT OF DIRECTORIES (1-LEVEL DEEP)\n" >> $outfile cat_dir /etc/network/interfaces.d cat_dir /etc/systemd/network -cat_dir /etc/NetworkManager/system-connections +cat_dir /etc/NetworkManager/system-connections # Redacts most passwords above cat_dir /etc/netplan # Redacts most passwords above #cat_dir /etc/sysconfig/network-scripts/if-cfg* # No longer common #cat_dir /etc/network # Above file /etc/network/interfaces suffices echo -e "\n 4. Output of Commands:\n" -echo -e "\n\n\n\n\n4. OUTPUT OF COMMANDS\n" >> $outfile +echo -e "\n\n\n\n4. OUTPUT OF COMMANDS\n" >> $outfile cat_cmd 'uname -a' 'Linux kernel' +cat_cmd 'sudo dmesg | grep -i "command line:"' 'Kernel boot parameters' cat_cmd 'free' 'RAM memory' cat_cmd 'lscpu' 'CPU details' +cat_cmd 'rpi-eeprom-update' 'RPi Bootloader EEPROM' cat_cmd 'df -h' 'Disk usage' +cat_cmd 'df -ah' 'Disk usage detail' cat_cmd 'lsblk' 'Partition mount points' cat_cmd 'blkid' 'Mount point details' +cat_file /etc/fstab +cat_cmd 'lshw -C network' 'Network hardware/interfaces' cat_cmd 'ip addr' 'Network interfaces' cat_cmd 'ifconfig' 'Network interfaces (old view)' cat_cmd 'ip route' 'Routing table' @@ -210,18 +233,37 @@ cat_cmd 'iw list' 'List capabilities of all wireless devices' cat_cmd 'systemctl status hostapd' 'Downstream Wi-Fi: Is hostapd running?' cat_cmd 'ls -l /etc/wpa_supplicant' 'Upstream Wi-Fi' cat_cmd 'ps -AH' 'Process hierarchy: staging of hostapd & wpa_supplicant?' -cat_cmd 'dmesg | grep brcm' 'Diagnostic messages: RPi Wi-Fi firmware' +cat_cmd 'sudo journalctl -b | grep wpa_supplicant' 'wpa_supplicant log since boot' +cat_cmd 'sudo journalctl -b | grep NetworkManager | head -100' 'NetworkManager log since boot' +#cat_cmd 'sudo dmesg | grep brcm' 'Diagnostic messages: RPi Wi-Fi firmware' +cat_cmd 'sudo dmesg | grep Firmware:' '(Wi-Fi) firmware boot diagnostics' +cat_cmd 'ls -l /lib/firmware/cypress/*43430*' 'WiFi firmware for: RPi Zero W, Zero 2 W & 3' +cat_cmd 'ls -l /lib/firmware/cypress/*43455*' 'WiFi firmware for: RPi 3 B+, 4, 5 & 500' +cat_cmd 'sudo dmesg | grep -i -e 80211 -e 802\.11 -e wireless -e wifi -e wlan -e broadcom -e brcm -e bcm -e realtek | head -100' 'Wi-Fi firmware/driver msgs' cat_cmd 'lspci -nn' 'Devices on PCI buses' cat_cmd 'env' 'Environment variables' +cat_cmd 'node -v' 'Node.js version' +cat_cmd 'npm -v' 'npm version' +cat_cmd '/opt/iiab/kiwix/bin/kiwix-serve --version' 'kiwix-tools' +cat_cmd 'cd /usr/local/calibre-web-py3; sudo git log --graph --oneline --decorate | head -50' 'Calibre-Web version' +cat_cmd 'sudo lb --version' 'xklb version' +cat_cmd 'sudo yt-dlp --version' 'yt-dlp version' +cat_cmd 'systemctl status calibre-web' 'Is Calibre-Web running?' +cat_cmd 'sudo journalctl -u calibre-web | tail -100' 'Calibre-Web systemd log' +cat_tail /var/log/calibre-web.log 100 +cat_tail /var/log/xklb.log 300 +cat_cmd 'sudo journalctl -t IIAB-CMDSRV' 'Admin Console CMDSRV log' #cat_cmd 'ansible localhost -m setup 2>/dev/null' 'All Ansible facts' # For cleaner scraping of Ansible vars, consider "./runrole all-vars /tmp/all-ansible-vars" 27-31 lines above? echo -e "\n 5. Firewall Rules:\n" -echo -e "\n\n\n\n5. FIREWALL RULES\n" >> $outfile +echo -e "\n\n\n5. FIREWALL RULES\n" >> $outfile #cat_file /usr/bin/iiab-gen-iptables cat_cmd 'sudo iptables-save' 'Firewall rules' +cat_cmd 'sudo ufw status verbose' 'Firewall status & rules' -echo -e "\n 6. Log Files: (last 100 lines of each)\n" -echo -e "\n\n\n\n6. LOG FILES (LAST 100 LINES OF EACH)\n" >> $outfile +echo -e "\n 6. Log Files: (e.g. last 100 lines of each)\n" +echo -e "\n\n\n6. LOG FILES (e.g. LAST 100 LINES OF EACH)\n" >> $outfile +cat_cmd 'grep -B2 "SEE ERROR ABOVE" /opt/iiab/iiab/*.log' 'for skip_role_on_error' cat_tail /opt/iiab/iiab/iiab-install.log 100 cat_tail /opt/iiab/iiab/iiab-configure.log 100 cat_tail /opt/iiab/iiab/iiab-debug.log 100 @@ -241,17 +283,22 @@ echo -e " $outfile\e[0m" #else echo echo -ne "\e[42;1mPublish it to a web pastebin? [Y/n]\e[0m " -read ans < /dev/tty +read -n 1 -r ans < /dev/tty +echo #fi echo -e "\e[1m" -if [ "$ans" == "" ] || [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - echo -ne "PUBLISHING TO URL... " - #pastebinit -b dpaste.com < $outfile - pastebinit -b sprunge.us < $outfile # Run 'pastebinit -l' to list other possible pastebin site URLs +#if [ "$ans" == "" ] || [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then +if ! [[ $ans =~ ^[nNqQ]$ ]]; then + echo -ne "PUBLISHING TO URL... " # Run 'pastebinit -l' to list other possible pastebin site URLs. ASIDE: Quirky pastebin-like https://temp.sh can sometimes work (like a file transfer service) for larger files. + pastebinit -b paste.centos.org $outfile # 2024-08-10: Basic line numbers & "4 weeks" good enough? + #nc termbin.com 9999 < $outfile # 2024-08-10: No line numbers & limited to 7 days (rudimentary but reliable option if nec in future?!) + #pastebinit -b dpaste.com $outfile # 2024-08-10: Unfortunately limited to 30 days by default. Claims 1,000,000 character maximum pastebin size (or usage quota within N days?) But newly restricted to LESS THAN 500 LINES (e.g. after IP address blocks & email appeals kinda work, but take almost 24h each time!) + #pastebinit -b sprunge.us $outfile # Stopped working for many weeks (mid-2023, and again in mid-2024) + #pastebinit -b paste2.org $outfile # Spammy/dangerous pastebins else echo -e "If you later decide to publish it, run:" echo - echo -e " pastebinit -b sprunge.us < $outfile" + echo -e " pastebinit -b paste.centos.org $outfile" fi echo -e "\e[0m" diff --git a/scripts/iiab-diagnostics.README.md b/scripts/iiab-diagnostics.README.md index 837418609..7c064b757 100644 --- a/scripts/iiab-diagnostics.README.md +++ b/scripts/iiab-diagnostics.README.md @@ -1,10 +1,16 @@ ## Objective -To streamline troubleshooting of remote Internet-in-a-Box (IIAB) installations, we bundle up common machine/software diagnostics, all together in 1 human-readable small file, that can be easily circulated online AND offline. +To streamline troubleshooting of remote Internet-in-a-Box (IIAB) installations, we bundle up common machine/software diagnostics, all together in 1 human-readable file of about 2000 lines, that can be easily circulated online AND offline. -Passwords (including Wi-Fi passwords) are auto-redacted from this file, to protect your community confidentiality. +Just FYI Raspberry Pi OS's [/usr/bin/raspinfo](https://github.com/raspberrypi/utils/blob/master/raspinfo/raspinfo) serves a very similar purpose, but we do not include that program's 700-to-800 line output at present. -The ``pastebinit`` command can then be used to auto-upload this file, creating a short URL that makes it much easier to circulate among [volunteers](http://internet-in-a-box.org/pages/contributing.html). +For a more concise "instant" summary of any IIAB machine (about 20-25 lines) try this command instead: [/usr/bin/iiab-summary](iiab-summary) + +## What `iiab-diagnostics` does + +Passwords (including Wi-Fi passwords) are auto-redacted as the output file is generated, to protect your community confidentiality. + +Finally, the ``pastebinit`` command can be used to auto-upload the output file (human-readable, approx 2000 lines) creating a short URL that makes it much easier to circulate among [volunteers](https://internet-in-a-box.org/contributing.html). But first off, the file is compiled by harvesting 1 + 6 kinds of things: @@ -49,7 +55,7 @@ But first off, the file is compiled by harvesting 1 + 6 kinds of things: Or, you can later/manually upload it using the ``pastebinit`` command: ``` - pastebinit -b sprunge.us < /etc/iiab/diag/NEW-FILE-NAME + pastebinit -b dpaste.com /etc/iiab/diag/NEW-FILE-NAME ``` Either way, this will generate an actual web link (URL). @@ -58,8 +64,6 @@ But first off, the file is compiled by harvesting 1 + 6 kinds of things: Include a description of the symptoms, and how to reproduce the problem. -4. If you don't understand Step 3, email everything to bugs@iiab.io instead. - ## Source Code -Please look over the bottom of [iiab-diagnostics](iiab-diagnostics) (lines 110-231 especially) to learn more about which common IIAB files and commands make this rapid troubleshooting possible. +Please look over the bottom of [iiab-diagnostics](iiab-diagnostics) (lines 135-273 especially) to learn more about which common IIAB files and commands make this rapid troubleshooting possible. diff --git a/scripts/iiab-item-size.py b/scripts/iiab-item-size.py new file mode 100755 index 000000000..6e1261ba3 --- /dev/null +++ b/scripts/iiab-item-size.py @@ -0,0 +1,183 @@ +#!/usr/bin/python3 +# Auto-calculate IIAB + EduPack disk space needs, in advance [& design review] +# https://github.com/iiab/iiab/pull/3594 + +import os, sys, syslog +from datetime import date +import pwd, grp +import shutil +import argparse +import sqlite3 +import iiab.iiab_lib as iiab +import iiab.adm_lib as adm +import requests +import json + +all_menu_defs = adm.get_all_menu_defs() + +def main(): + parser = argparse.ArgumentParser(description="Get size for item.") + parser.add_argument("name", help="Name item.") + + # menu_dir + args = parser.parse_args() + + name = args.name + + content= get_item_size(name) + + #print('size: ',iiab.human_readable(content["size"])) + print(f'content ', content) + + sys.exit() + +def get_zims_size_from_header(url): + #url = 'https://download.kiwix.org/zim/other/mdwiki_en_all_2023-03.zim' + response = requests.head(url, allow_redirects=True) + size = 0 + if (response.status_code == 200): + size = int(response.headers.get('Content-Length', 0)) + return size + +def get_zims_size_from_file(name): + data_output = {} + data_output['download_url']= '' + data_output['size'] = 0 + + with open('/etc/iiab/kiwix_catalog.json') as json_file: + data = json.load(json_file)['zims'] + result = { data[element]['perma_ref']: data[element] for element in list(data.keys())} + if result.get(name) is not None: + data_output['download_url']= result[name]['download_url'] + data_output['size']= (int(result[name].get('size',0)) * 1024) + 1023 + return data_output + +def get_zims_size(name): + data = get_zims_size_from_file(name) + #if data['size'] <= 1023: + # data['size'] = get_zims_size_from_header(data['download_url']) + return data + +def get_oer2go_size_from_file(name): + data_output = {} + data_output['download_url']= '' + data_output['size'] = 0 + + with open('/etc/iiab/oer2go_catalog.json') as json_file: + data = json.load(json_file)['modules'] + if data.get(name) is not None: + data_output['download_url']= data[name]['rsync_url'] + data_output['size']= (int(data[name].get('ksize',0)) * 1024) + 1023 + return data_output + +def get_map_size_from_file(name): + data_output = {} + data_output['download_url']= '' + data_output['size'] = 0 + + with open('/etc/iiab/map-catalog.json') as json_file: + data = json.load(json_file)['base'] + result = { data[element]['perma_ref']: data[element] for element in list(data.keys())} + if result.get(name) is not None: + data_output['download_url']= result[name]['archive_url'] + data_output['size']= (int(result[name].get('size',0))) + 1023 + return data_output + + +def get_item_size(name_input): + return [get_size(element) for element in [name_input]] + +def get_items_size(name_input): + return [get_size(element) for element in name_input] + +def element_unknown(name): + return {"size":0} + +def build_otput(name, type_element, function): + data = function(name) + if data['size']== 0: + print(name, ": the size of this",type_element,"element is unknown") + + return { + "name": name + ,"type": type_element + ,"size": data['size'] + } + + +intended_use_dict = { + "azuracast":{ + "name":"name" + ,"type":"azuracast" + ,"function":element_unknown + } + ,"calibre":{ + "name":"name" + ,"type":"calibre" + ,"function":element_unknown + } + ,"external":{ + "name":"name" + ,"type":"external" + ,"function":element_unknown + } + ,"html":{ + "name":"moddir" + ,"type":"module" + ,"function":get_oer2go_size_from_file + } + ,"info":{ + "name":"name" + ,"type":"info" + ,"function":element_unknown + } + ,"internetarchive":{ + "name":"name" + ,"type":"internetarchive" + ,"function":element_unknown + } + ,"kalite":{ + "name":"name" + ,"type":"kalite" + ,"function":element_unknown + } + ,"kolibri":{ + "name":"name" + ,"type":"kolibri" + ,"function":element_unknown + } + ,"map":{ + "name":"name" + ,"type":"map" + ,"function":get_map_size_from_file + } + ,"webroot":{ + "name":"name" + ,"type":"webroot" + ,"function":element_unknown + } + ,"zim":{ + "name":"zim_name" + ,"type":"zim" + ,"function":get_zims_size + } +} + + +def get_size(name_input): + if name_input in all_menu_defs: + info = all_menu_defs[name_input] + intended_use = info["intended_use"] + + try: + data_intend = intended_use_dict[intended_use] + name_element = info[data_intend["name"]] + return build_otput(name_element, data_intend["type"], data_intend["function"]) + except: + pass + + return build_otput(name_input, "unknown", element_unknown) + +# Now start the application +if __name__ == "__main__": + main() diff --git a/scripts/iiab-network b/scripts/iiab-network new file mode 100755 index 000000000..c2d12056f --- /dev/null +++ b/scripts/iiab-network @@ -0,0 +1,3 @@ +#!/bin/bash -e +cd /opt/iiab/iiab +sudo ./iiab-network diff --git a/scripts/iiab-root-login b/scripts/iiab-root-login new file mode 100755 index 000000000..2d968e857 --- /dev/null +++ b/scripts/iiab-root-login @@ -0,0 +1,60 @@ +#!/bin/bash -e +# "-e" tries to exit right away on error. + +# Enable (and set!) root login password for ssh and sftp. +# To help everyday IIAB implementers upload content with FileZilla: +# https://wiki.iiab.io/go/FAQ#How_do_I_add_my_own_content%3F + +# AT YOUR OWN RISK. If this absolutely must be run non-interactively, use: +# sudo iiab-root-login + +if [ ! -f /etc/ssh/sshd_config ]; then + echo -e '\n\e[41;1mERROR: /etc/ssh/sshd_config is missing (is openssh-server installed?)\e[0m\n' + exit 1 +fi + +if ! systemctl is-active ssh > /dev/null; then + echo -e "\n\e[41;1mERROR: ssh service is not active (run 'systemctl status ssh' ?)\e[0m\n" + exit 1 +fi + +if [ $# -eq 0 ]; then + echo -e '\n\e[1;33mPICK A STRONG PASSWORD TO PROTECT YOUR IIAB!\e[0m' + echo -en '\nWhat ssh and sftp password do you want for user "root" ? ' + read ans < /dev/tty +else + ans=$1 + echo +fi + +if [[ $ans == "" ]]; then + echo -e '\n\e[41;1mEXITING: User "root" cannot have an empty password.\e[0m\n' + exit 1 +else + echo root:"$ans" | chpasswd + echo -e 'Password changed, for user "root".\n' +fi + +# Comment out problematic line(s) in file(s) like... +# /etc/ssh/sshd_config.d/60-cloudimg-settings.conf +# ...that appear in Multipass VMs, etc: +sed -i 's/^PermitRootLogin[[:blank:]].*/# &/' /etc/ssh/sshd_config.d/* || true +sed -i 's/^PasswordAuthentication[[:blank:]].*/# &/' /etc/ssh/sshd_config.d/* || true + +if grep -q '^PermitRootLogin[[:blank:]]' /etc/ssh/sshd_config; then + sed -i 's/^PermitRootLogin[[:blank:]].*/PermitRootLogin yes/' /etc/ssh/sshd_config +else + echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config +fi + +if grep -q '^PasswordAuthentication[[:blank:]]' /etc/ssh/sshd_config; then + sed -i 's/^PasswordAuthentication[[:blank:]].*/PasswordAuthentication yes/' /etc/ssh/sshd_config +else + echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config +fi + +if systemctl reload ssh; then + echo -e '\e[44;1mUser "root" can now upload to IIAB using FileZilla!\e[0m\n' +else + echo -e '\e[41;1mERROR: Unable to reload ssh service.\e[0m\n' +fi diff --git a/scripts/iiab-size.py b/scripts/iiab-size.py new file mode 100755 index 000000000..c44e7034b --- /dev/null +++ b/scripts/iiab-size.py @@ -0,0 +1,45 @@ +#!/usr/bin/python3 +# Auto-calculate IIAB + EduPack disk space needs, in advance [& design review] +# https://github.com/iiab/iiab/pull/3594 + +import os, sys, syslog +from datetime import date +import pwd, grp +import shutil +import argparse +import sqlite3 +import iiab.iiab_lib as iiab +import iiab.adm_lib as adm +import requests +import json +import importlib +from functools import reduce +iiab_item_size = importlib.import_module("iiab-item-size") + +def main(): + parser = argparse.ArgumentParser(description="Read menu file for get size.") + parser.add_argument("menuFile", help="Is the menu file.") + # menu_dir + args = parser.parse_args() + + menu_file = args.menuFile + if not os.path.exists(menu_file): + print('Menu file ' + menu_file + ' not found.') + exit(1) + + total_size= content_from_menu(menu_file) + + print('total: ',iiab.human_readable(total_size)) + print(f'total (bytes): ', total_size) + + sys.exit() + +def content_from_menu(menu_file): + menu = adm.read_json(menu_file) + items = iiab_item_size.get_items_size(menu["menu_items_1"]) + total_size = reduce(lambda accumulator,item: accumulator+int(item['size']), items, 0) + return total_size + +# Now start the application +if __name__ == "__main__": + main() diff --git a/scripts/iiab-summary b/scripts/iiab-summary new file mode 100755 index 000000000..73bcc9693 --- /dev/null +++ b/scripts/iiab-summary @@ -0,0 +1,92 @@ +#!/bin/bash + +# Intentionally very concise summary of IIAB details. +# Can evolve for int'l community needs, alongside the much longer: +# https://github.com/iiab/iiab/blob/master/scripts/iiab-diagnostics.README.md + +git config --global --add safe.directory /opt/iiab/iiab # Nec below, if non-root +cd /opt/iiab/iiab +SHORT_HASH1=$(git log --pretty=format:'%h' -n 1) # --pretty=format:'%H' (all 40 chars) +TAG1=$(git describe --tags --abbrev=0) +COMMITS1=$(git log "$TAG1..HEAD" --oneline | wc -l) +PR_COUNT1=$(git log "$TAG1..HEAD" --oneline --grep='Merge pull request' | wc -l) +COMMIT_MSG1=$(git log --format=%B -1 | head -1) +BRANCH1=$(git branch --show-current) +REMOTE_URL1="none" +tmp=$(git config branch.$BRANCH1.remote) && { + if [[ $tmp =~ ^"https://" ]]; then + REMOTE_URL1=$tmp + else + REMOTE_URL1=$(git config remote.$tmp.url) + fi +} + +git config --global --add safe.directory /opt/iiab/iiab-admin-console # Nec below, if non-root +cd /opt/iiab/iiab-admin-console +SHORT_HASH2=$(git log --pretty=format:'%h' -n 1) # --pretty=format:'%H' (all 40 chars) +TAG2=$(git describe --tags --abbrev=0) +COMMITS2=$(git log "$TAG2..HEAD" --oneline | wc -l) +PR_COUNT2=$(git log "$TAG2..HEAD" --oneline --grep='Merge pull request' | wc -l) +COMMIT_MSG2=$(git log --format=%B -1 | head -1) +BRANCH2=$(git branch --show-current) +REMOTE_URL2="none" +tmp=$(git config branch.$BRANCH2.remote) && { + if [[ $tmp =~ ^"https://" ]]; then + REMOTE_URL2=$tmp + else + REMOTE_URL2=$(git config remote.$tmp.url) + fi +} + +echo "$(grep install_date /etc/iiab/iiab.ini) Current TZ: $(date +%Z)" +echo +echo -e "iiab: $SHORT_HASH1, $PR_COUNT1 PR's / $COMMITS1 commits since tag $TAG1" +echo -e " \"$COMMIT_MSG1\"" +echo " $REMOTE_URL1 branch: $BRANCH1" +if [ -f /etc/iiab/pr-list-pulled ]; then + echo + echo "/etc/iiab/pr-list-pulled:" + cat /etc/iiab/pr-list-pulled +fi +echo +if [ -d /opt/iiab/iiab-admin-console ]; then + echo -e "iiab-admin-console: $SHORT_HASH2, $PR_COUNT2 PR's / $COMMITS2 commits since tag $TAG2" + echo -e " \"$COMMIT_MSG2\"" + echo " $REMOTE_URL2 branch: $BRANCH2" +else + echo " WARNING: Directory /opt/iiab/iiab-admin-console does not exist!" +fi +echo +if [ -f /etc/rpi-issue ]; then + cat /etc/rpi-issue + echo "/etc/debian-version: $(cat /etc/debian_version)" +else + echo "$(cat /etc/issue.net) $(cat /etc/debian_version)" +fi +echo "display-manager? $(systemctl is-active display-manager.service) Arch1: $(dpkg --print-architecture) Arch2: $(dpkg --print-foreign-architectures)" +uname -nrvm +echo "$(lscpu | grep '^Model name:' | sed 's/^Model name:\s*//') $(lscpu | grep '^CPU(s):' | tr -s ' ') "$(free -m | tail -2 | tr -s ' ' | cut -d' ' -f1-2) +if [ -f /proc/device-tree/model ]; then + cat /proc/device-tree/model | tr -d '\000' ; echo # dpaste.com pastebin doesn't allow null chars! MORE RPi DETAIL: tail -4 /proc/cpuinfo +fi +if [ -f /sys/class/thermal/thermal_zone0/temp ]; then + echo "Temperature(s): "$(cat /sys/class/thermal/thermal_zone*/temp) # Prettier if avail: vcgencmd measure_temp +fi +#if command -v landscape-sysinfo > /dev/null; then # Slow, Ubuntu Server only +# landscape-sysinfo --sysinfo-plugins=Disk,Temperature,Load # Like: uptime -p +#fi +echo +/opt/iiab/iiab/scripts/iiab-apps-to-be-installed > /dev/null +echo "$(df -h /) ZIMs: $(ls /library/zims/content/ | wc -l) OER2Go: $(ls /library/www/html/modules/ | wc -l) Apps2B: $(cat /tmp/iiab-apps-to-be-installed | wc -l)" +echo +#grep "^openvpn_handle:" /etc/iiab/local_vars.yml +#grep "^tailscale_installed:" /etc/iiab/iiab_state.yml +#if [[ $(command -v /usr/bin/tailscale) ]]; then +if tailscale ip &> /dev/null; then + #echo "VPN: $(tailscale ip) $(tailscale whois --json $(tailscale ip -1) | jq -r .Node.Tags[])" + echo "VPN: $(tailscale ip) $(tailscale status --json | jq -r .Self.Tags[])" +fi +echo $(ip -o link show | awk -F': ' '{print $2}') # Better order than: ls -rt /sys/class/net +echo $(echo $(hostname -A) $(hostname -a) | xargs -n1 | sort | uniq) +hostname -I +echo diff --git a/scripts/iiab-update b/scripts/iiab-update new file mode 100755 index 000000000..2e3f9e4f3 --- /dev/null +++ b/scripts/iiab-update @@ -0,0 +1,148 @@ +#!/bin/bash -e +# "-e" tries to exit right away on error. + +# Upgrade IIAB core software (apt updates, Ansible, Admin Console, etc). + +# Also with a focus on upgrading IIAB Calibre-Web, if that's installed: +# https://github.com/iiab/calibre-web/wiki + +# 2024-07-18 fixes underway, thanks to: +# https://stackoverflow.com/questions/21096478/overwrite-executing-bash-script-files +# https://stackoverflow.com/questions/2285403/how-to-make-shell-scripts-robust-to-source-being-changed-as-they-run +# https://stackoverflow.com/questions/2336977/can-a-shell-script-indicate-that-its-lines-be-loaded-into-memory-initially + +{ + if [[ $(id -un) != "root" ]]; then + echo -e "\nPlease run: sudo iiab-update\n" + exit 1 + fi + + if [[ $1 == "-f" || $1 == "--fast" ]]; then + echo -e "\n\n\e[44;1mAttempting a FAST upgrade of IIAB Calibre-Web...\e[0m\n" + echo -e "\n\e[33m'iiab-update -f' DOES NOT apply apt updates.\e[0m" + else + echo -e "\n\n\e[44;1mUpgrading IIAB core software: (apt updates, Ansible, Admin Console, etc)\e[0m\n" + echo -e "\n\e[44;1mOr try 'iiab-update -f' for a FAST upgrade of IIAB Calibre-Web!\e[0m\n\n" + echo -e "\e[4mNow running: apt update\e[0m\n" + apt update + echo -e "\n\e[4mNow running: apt dist-upgrade -y\e[0m\n" + apt dist-upgrade -y + echo -e "\n\e[4mNow running: apt autoremove -y\e[0m\n" + apt autoremove -y + fi + + cd /opt/iiab/iiab + if [[ $(git branch --show-current) != "master" || $(git status --porcelain --untracked-files=no) != "" ]]; then # Permit detritus, e.g. untracked files like adm-run-roles-tmp.yml + echo -e "\n\n\e[41;1mIn /opt/iiab/iiab, (1) 'git branch' MUST show current branch 'master' and (2) 'git status' must show NO MODIFIED FILES.\e[0m\n\n" + exit 1 + fi + echo -e "\n\n\e[4mNow running: git pull https://github.com/iiab/iiab --no-rebase --no-edit\e[0m\n" + git pull https://github.com/iiab/iiab --no-rebase --no-edit + echo + if grep -q 'tailscale_installed: True' /etc/iiab/iiab_state.yml; then + echo -e "\e[4mNow running: cp -u roles/tailscale/templates/iiab-vpn /usr/bin\e[0m\n" + cp -u roles/tailscale/templates/iiab-vpn /usr/bin + fi + if [[ $1 == "-f" || $1 == "--fast" ]]; then # Otherwise ./runrole does it below! (as Ansible runs roles/0-init) + cd scripts + echo -e "\e[4mNow running: cp -u iiab-update iiab-summary iiab-diagnostics iiab-root-login /usr/bin\e[0m\n" + cp -u iiab-update iiab-summary iiab-diagnostics iiab-root-login /usr/bin + fi + + if [[ $1 == "-f" || $1 == "--fast" ]]; then + echo -e "\n\e[33m'iiab-update -f' DOES NOT upgrade Ansible.\e[0m\n\n" + else + echo -e "\n\n\e[4mNow running: scripts/ansible\e[0m" + scripts/ansible + fi + + if grep -q 'calibreweb_installed: True' /etc/iiab/iiab_state.yml; then + if [[ $1 == "-f" || $1 == "--fast" ]]; then + echo -e "\e[4mChecking if an older version of 'library' (formerly 'xklb') exists...\e[0m" + if pipx list | grep -q 'xklb'; then + echo -e "\e[4mOlder version 'xklb' detected. Now running: pipx uninstall xklb\e[0m" + pipx uninstall xklb + fi + echo -e "\e[4mNow running: pipx uninstall library # THIS ALSO UNINSTALLS yt-dlp\e[0m\n" + pipx uninstall library || true + echo -e "\n\e[4mNow running: pipx install library # THIS ALSO INSTALLS yt-dlp\e[0m\n" + pipx install library + echo -e "\n\e[4mNow running: yt-dlp --version\e[0m\n" + yt-dlp --version + echo -e '\n\e[4mNeed better YouTube scraping? Run this for the latest yt-dlp "nightly" release:\e[0m\n\n\e[1mpipx inject --pip-args="--upgrade --pre" -f library yt-dlp[default]\e[0m\n' + # NEED BETTER/EXPERIMENTAL YouTube SCRAPING? UNCOMMENT THE NEXT LINE: + # pipx inject --pip-args="--upgrade --pre" -f library yt-dlp[default] + # + # https://github.com/yt-dlp/yt-dlp-nightly-builds/releases + # https://pypi.org/project/yt-dlp/#history + cd /usr/local/calibre-web-py3 + if [[ $(git branch --show-current) != "master" || $(git status --porcelain --untracked-files=no) != "" ]]; then # Permit venv detritus, e.g. untracked files like these 5: bin/ include/ lib/ lib64 pyvenv.cfg + echo -e "\n\e[41;1mIn /usr/local/calibre-web-py3, (1) 'git branch' MUST show current branch 'master' and (2) 'git status' must show NO MODIFIED FILES.\e[0m\n\n" + exit 1 + fi + echo -e "\e[4mNow running: systemctl stop calibre-web\e[0m\n" + systemctl stop calibre-web + echo -e "\e[4mNow running: git pull https://github.com/iiab/calibre-web --no-rebase --no-edit\e[0m\n" + git pull https://github.com/iiab/calibre-web --no-rebase --no-edit + echo -e "\n\e[4mNow running: bin/pip install -r requirements.txt --prefer-binary\e[0m\n" + bin/pip install -r requirements.txt --prefer-binary > /dev/null + echo -e "\e[4mNow running: systemctl restart calibre-web\e[0m\n" + systemctl restart calibre-web + else + cd /opt/iiab/iiab + echo -e "\n\e[4mNow running: ./runrole --reinstall calibre-web\e[0m\n" + ./runrole --reinstall calibre-web + fi + fi + + # 2024-07-17: Run Admin Console stanza last for safety -- it failed ~50% of the + # time over 20 tests for me -- leading to 3+ different kinds of errors right + # after "(Restarting CMDSRV" e.g. "syntax error near unexpected token" was the + # most common error -- once the error was "command not found" -- and another + # time Admin Console's ./install VERY MYSTERIOUSLY RAN TWICE! + # + # Any chance this get_oer2go_catalog error ~15 lines up...might be related ? + # + # ... + # Finished writing to /etc/iiab/kiwix_catalog.json + # SUCCESS/opt/admin/cmdsrv/scripts/get_oer2go_catalog:52: SyntaxWarning: invalid escape sequence '\<' + # php_parser = re.compile('\<\?php echo .+? \?>') + # Skipping module not needed by Internet in a Box 12 en-PhET + # ... + # [ ~15 lines ] + # ... + # (Restarting CMDSRV + # ... + # [ VARIOUS ERRORS SOMETIMES HAPPEN HERE ] + + if [ -d /opt/admin ]; then + if [[ $1 == "-f" || $1 == "--fast" ]]; then + echo -e "\n\e[33m'iiab-update -f' DOES NOT upgrade Admin Console.\e[0m" + else + cd /opt/iiab/iiab-admin-console + if [[ $(git branch --show-current) != "master" || $(git status --porcelain) != "" ]]; then + echo -e "\n\n\e[41;1mIn /opt/iiab/iiab-admin-console, (1) 'git branch' MUST show current branch 'master' and (2) 'git status' must show NO MODIFIED FILES.\e[0m\n\n" + exit 1 + fi + GITHASH1=$(git rev-parse HEAD) + echo -e "\n\e[4mNow running: git pull https://github.com/iiab/iiab-admin-console --no-rebase --no-edit\e[0m\n" + git pull https://github.com/iiab/iiab-admin-console --no-rebase --no-edit + GITHASH2=$(git rev-parse HEAD) + if [[ $GITHASH1 != $GITHASH2 ]]; then + echo -e "\n\e[4mNow running: ./install\e[0m\n" + ./install + else + echo -e "\n\e[33mSkipping Admin Console './install' β€” as it appears up-to-date!\e[0m" + fi + fi + fi + + if [[ $1 == "-f" || $1 == "--fast" ]]; then + echo -e "\n\n\e[44;1m'iiab-update -f' COMPLETE!\e[0m\n" + echo -e "\e[44;1mIf Calibre-Web fails, please try 'iiab-update' WITHOUT '-f'\e[0m\n\n" # \e[7m == reverse video (e.g. black on white) + else + echo -e "\n\n\e[44;1miiab-update COMPLETE!\e[0m\n\n" + fi + + exit # https://stackoverflow.com/questions/2285403/how-to-make-shell-scripts-robust-to-source-being-changed-as-they-run +} diff --git a/scripts/install_python2.sh b/scripts/install_python2.sh new file mode 100755 index 000000000..b9d0d2bed --- /dev/null +++ b/scripts/install_python2.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# https://packages.debian.org/search?keywords=libpython2.7-stdlib&searchon=names&suite=all§ion=all +# https://packages.debian.org/bullseye/libpython2.7-stdlib +# https://packages.ubuntu.com/search?keywords=libpython2.7-stdlib&searchon=names&suite=all§ion=all +# https://packages.ubuntu.com/jammy-updates/libpython2.7-stdlib + +# payload to be installed: +# libpython2-stdlib +# libpython2.7-minimal +# libpython2.7-stdlib +# python2-minimal +# python2.7-minimal +# python2.7 +# python2 + +export DEBIAN_FRONTEND=noninteractive +ARCH=$(dpkg --print-architecture) + +# 2023-05-19: #3573 -> PR #3582: Ubuntu 23.10's virtualenv 20.23 no longer +# supports Python 2. Root cause is virtualenv 20.22.0 (2023-04-19) which +# removed Python 2 support: https://virtualenv.pypa.io/en/latest/changelog.html +# Unfortunately older versions from Ubuntu 22.04 (#3583) & 23.04 like... +# http://launchpadlibrarian.net/651276954/virtualenv_20.19.0+ds-1_all.deb +# ...can drag in newer 20.23+ version of python3-virtualenv, leaving +# us with /usr/bin/virtualenv 20.23 once again, i.e. preventing Python 2. +# Whereas pip (which installs /usr/local/bin/virtualvenv) at least works: +# +#iif grep -qi ubuntu /etc/os-release; then # Ubuntu 23.10+ (and Mint 22+ ?) needs this. Ubuntu 23.04 tolerates it. +# apt -y install python3-pip +# pip install virtualenv==20.21.1 --break-system-packages +#else +# apt -y install virtualenv # Debian 12 & RasPiOS 12 are A-Ok with built-in virtualenv 20.17.1 (<= 20.21.1) +#fi +# +#apt -y install virtualenv +# https://github.com/iiab/iiab/pull/3535#issuecomment-1503626474 +#apt -y install media-types libffi8 libssl3 + +# libpython2.7-stdlib from ubuntu-22.04 used in amd64|arm64|armhf is compiled against libssl3 and libffi8 +# `apt info libpython2.7-stdlib` +#cd /tmp + +case $ARCH in + "amd64") + # works on U23.04 x86_64 VM + cat << EOF > /etc/apt/sources.list.d/python2.list +deb [trusted=yes] http://archive.ubuntu.com/ubuntu jammy main universe +deb [trusted=yes] http://archive.ubuntu.com/ubuntu jammy-updates main universe +EOF + ;; + + "arm64") + # gave 404 errors on U23.04 x86_64 VM need to circle back to U23.04 arm64 and confirm + cat << EOF > /etc/apt/sources.list.d/python2.list +deb [trusted=yes] http://ports.ubuntu.com/ jammy main universe +deb [trusted=yes] http://ports.ubuntu.com/ jammy-updates main universe +EOF + ;; + + "armhf") + # armhf compile flags differ between RasPiOS and Ubuntu + if [ -f /etc/rpi-issue ] && ! grep -q 11 /etc/issue; then # RasPiOS 12+ / Bookworm+ + cat << EOF > /etc/apt/sources.list.d/python2.list +deb [trusted=yes] http://ports.ubuntu.com/ jammy main universe +deb [trusted=yes] http://ports.ubuntu.com/ jammy-updates main universe +EOF +# elif ! [ -f /etc/rpi-issue ]; then # Ubuntu/Debian on armhf not supported +# cat << EOF > /etc/apt/sources.list.d/python2.list +# deb http://ports.ubuntu.com/ jammy main universe +# deb http://ports.ubuntu.com/ jammy-updates main universe +# EOF + fi + ;; + + "i386") + # Building on scripts/ansible fix PR #3615 + if grep -q '^ID=debian$' /etc/os-release; then + cat << EOF > /etc/apt/sources.list.d/python2.list +deb http://deb.debian.org/debian bullseye main contrib non-free +deb http://deb.debian.org/debian bullseye-updates main contrib non-free +EOF + fi + ;; +esac + +apt update +if grep -qi ubuntu /etc/os-release; then # Ubuntu 23.10+ (and Mint 22+ ?) needs this. Ubuntu 23.04 tolerates it. + # 2023-05-20: 4 lines below borrow from Ubuntu 22.04: (Is this really less + # fragile than the pip approach ~40 lines above, in preparing for 24.04 ?) + apt -y install python3-platformdirs=2.5.1-1 + apt-mark hold python3-platformdirs + apt -y install python3-virtualenv=20.13.0+ds-2 + apt-mark hold python3-virtualenv # 2023-09-26: 'apt-mark hold virtualenv' was definitely insufficient on Ubuntu 23.10 + # 2023-05-21 PR #3587: Above 4 lines should really install a more recent + # version of virtualenv, probably from 'lunar' (Ubuntu 23.04) ? +else + apt -y install virtualenv # Debian 12 & RasPiOS 12 are A-Ok with built-in virtualenv 20.17.1 (<= 20.21.1) +fi +apt -y install python2 +rm /etc/apt/sources.list.d/python2.list || true +apt update diff --git a/scripts/install_python2_kalite-venv_u2404.sh b/scripts/install_python2_kalite-venv_u2404.sh new file mode 100755 index 000000000..cc40edcc2 --- /dev/null +++ b/scripts/install_python2_kalite-venv_u2404.sh @@ -0,0 +1,51 @@ +#!/bin/bash +export DEBIAN_FRONTEND=noninteractive + +cat << EOF > /etc/apt/sources.list.d/python2.list +deb [trusted=yes] http://archive.ubuntu.com/ubuntu jammy main universe +deb [trusted=yes] http://archive.ubuntu.com/ubuntu jammy-updates main universe +EOF + +apt update + +apt -y --allow-downgrades install python3.11=3.11.0~rc1-1~22.04 python3.11-minimal=3.11.0~rc1-1~22.04 libpython3.11-stdlib=3.11.0~rc1-1~22.04 libpython3.11-minimal=3.11.0~rc1-1~22.04 +apt-mark hold python3.11 python3.11-minimal libpython3.11-stdlib libpython3.11-minimal + +apt -y --allow-downgrades install python3-platformdirs=2.5.1-1 +apt-mark hold python3-platformdirs + +apt -y install python2 python2-pip-whl python2-setuptools-whl + +apt -y --allow-downgrades install python3-pip-whl=22.0.2+dfsg-1 +apt-mark hold python3-pip-whl + +apt -y --no-install-recommends install python3-pip=22.0.2+dfsg-1 +apt-mark hold python3-pip + +apt -y --allow-downgrades install python3-virtualenv=20.13.0+ds-2 +apt-mark hold python3-virtualenv + +apt -y --allow-downgrades install virtualenv=20.13.0+ds-2 +apt-mark hold virtualenv + +virtualenv --always-copy --pip 20.3.4 --setuptools 44.1.1 --no-wheel -p python2.7 /usr/local/kalite/venv + +cd /usr/local/kalite/venv +source bin/activate +bin/pip install ka-lite-static --no-python-version-warning --no-cache-dir +deactivate + +#apt -y remove `apt list *python2* | grep installed | awk -F / '{ print $1 }'` +apt-mark unhold $(apt-mark showhold) || true + +rm /etc/apt/sources.list.d/python2.list + +apt -y remove libmpdec3 python3-pip python3-wheel + +apt update +apt -y upgrade # Why 'apt upgrade' here? + +# python3-venv is needed for other venv's like roles/jupyterhub, e.g. #3716. +# So we restore python3-venv originally installed by scripts/ansible -- this +# is nec b/c python3-pip-whl downgrade to 22.0.2 (line ~19 above) removes it: +apt -y install python3-venv diff --git a/scripts/local_facts.fact b/scripts/local_facts.fact index 168aaf84a..e9f1fdb19 100755 --- a/scripts/local_facts.fact +++ b/scripts/local_facts.fact @@ -3,21 +3,25 @@ # Higher-level purpose explained at the bottom of: # https://github.com/iiab/iiab/blob/master/vars/default_vars.yml -# 2020-10-27: Most of the 11 variables require a command[*] to be run to +# 2020-10-27: Most of the [15] variables require a command[*] to be run to # establish the var's value. WE DISPLAY ALL ERRORS / DIAGNOSTICS AND CONTINUE. # # [*] DOESN'T MATTER WHAT COMMAND: so long as it fails with Return Code != 0 -# If statements then use that RC to force the var to these default values... +# If RC == 0, var is forced from its default value here: (using cmd's output) STAGE=0 OS="none" -VERSION_ID="none" # This var's combined with the above, before being output +VERSION_ID="none" # Just a temp var, for: OS_VER="$OS-$VERSION_ID" +OS_VER="none" IIAB_BRANCH="none" +IIAB_REMOTE_URL="none" +IIAB_RECENT_TAG="none" IIAB_COMMIT="none" -#XO_MODEL="none" RPI_MODEL="none" DEVICETREE_MODEL="none" ANSIBLE_VERSION="none" +PYTHON_VERSION="none" +PHP_VERSION="none" DHCPCD="none" # The last 3 conditioned on string output not RC. SEE BELOW. NETWORK_MANAGER="none" SYSTEMD_NETWORKD="none" @@ -55,61 +59,98 @@ OS_VER="$OS-$VERSION_ID" # Previously supported Linux distributions / versions: #"fedora-18" | \ #"fedora-22" | \ + #"centos-7" | \ #"debian-8" | \ #"debian-9" | \ #"debian-10" | \ + #"debian-11" | \ #"ubuntu-16" | \ #"ubuntu-17" | \ #"ubuntu-18" | \ #"ubuntu-19" | \ - #"centos-7" | \ + #"ubuntu-2004" | \ + #"ubuntu-2104" | \ + #"ubuntu-2110" | \ + #"ubuntu-2210" | \ + #"ubuntu-2204" | \ + #"ubuntu-2304" | \ + #"ubuntu-2310" | \ + #"linuxmint-20" | \ + #"linuxmint-21" | \ #"raspbian-8" | \ #"raspbian-9" | \ #"raspbian-10" | \ + #"raspbian-11" | \ -# 2021-09-27: With Debian 12 (Bookworm) pre-releases, please manually add -# this line to its /etc/os-release before installing IIAB: VERSION_ID="12" +# 2023-12-31: With Debian 13 (Trixie) pre-releases, please manually add +# this line to its /etc/os-release before installing IIAB: VERSION_ID="13" case $OS_VER in - "debian-11" | \ "debian-12" | \ - "ubuntu-2004" | \ - "ubuntu-2104" | \ - "ubuntu-2110" | \ - "ubuntu-2204" | \ - "linuxmint-20" | \ - "linuxmint-21" | \ - "raspbian-11") + "debian-13" | \ + "ubuntu-2404" | \ + "ubuntu-2410" | \ + "ubuntu-2504" | \ + "linuxmint-22" | \ + "raspbian-12" | \ + "raspbian-13") ;; *) echo -e "\n\e[41;1mOS '$OS_VER' IS NOT SUPPORTED. Please read:\e[0m\n\n\e[1mhttps://github.com/iiab/iiab/wiki/IIAB-Platforms\e[0m\n" ; exit 1 # Used by /opt/iiab/iiab/iiab-install ;; esac -# These next 2 help indicate what version of IIAB + +# These next 4 help indicate what version of IIAB tmp=$(git rev-parse --abbrev-ref HEAD) && IIAB_BRANCH=$tmp +tmp=$(git config branch.$IIAB_BRANCH.remote) && { + if [[ $tmp =~ ^"https://" ]]; then + IIAB_REMOTE_URL=$tmp + else + IIAB_REMOTE_URL=$(git config remote.$tmp.url) + fi +} + +tmp=$(git describe --tags --abbrev=0) && + IIAB_RECENT_TAG=$tmp + tmp=$(git rev-parse --verify HEAD) && IIAB_COMMIT=$tmp -#tmp=$(cat /proc/device-tree/mfg-data/MN) && -# XO_MODEL=$tmp -tmp=$(grep -ai raspberry /proc/device-tree/model) && - RPI_MODEL=$tmp +grep -iq raspberry /proc/cpuinfo && + RPI_MODEL=$(grep -i raspberry /proc/cpuinfo | sed 's/.*: //') + #RPI_MODEL=$(grep -ai raspberry /proc/device-tree/model | tr -d '\0') # /proc/device-tree/model e.g. 'Parallels ARM Virtual Machine' identical to... # /sys/firmware/devicetree/base/model (also true on RPi hardware!) -tmp=$(cat /proc/device-tree/model) && +# tr -d '\0' ...strips out its null byte, for cleaner output (PR #3086) + +tmp=$(tr -d '\0' < /proc/device-tree/model) && DEVICETREE_MODEL=$tmp + tmp=$(ansible --version) && ANSIBLE_VERSION=$(echo "$tmp" | head -1 | cut -f 2- -d " " | sed 's/.* \([^ ]*\)\].*/\1/') # Above works with 'ansible [core 2.11.0rc2]' -- these old ways do not: #ANSIBLE_VERSION=$(echo "$tmp" | head -1 | awk '{print $2}') #ANSIBLE_VERSION=$(echo "$tmp" | head -1 | sed -e 's/.* //') +if tmp=$(python3 -c 'from sys import version_info; print("%s.%s" % (version_info.major, version_info.minor));'); then + PYTHON_VERSION=$tmp +else + echo -e "\e[1m\nPython 3 is REQUIRED for Internet-in-a-Box. You might want to run:\n\nsudo apt install python3\n\e[0m" + exit 1 +fi + +tmp=$(apt list php) && + PHP_VERSION=$(echo $tmp | grep -Po '[0-9]+\.[0-9]+' | head -1) +# Extracts the first (topmost, leftmost) MAJOR.MINOR, even if not yet installed +# Safer than: echo $tmp | grep php | head -1 | sed 's/.*://; s/[^0-9.].*//') +# https://stackoverflow.com/questions/16675179/how-to-use-sed-to-extract-substring/16675391#16675391 + # THE LAST 3 BELOW ARE DIFFERENT as "systemctl is-enabled" unhelpfully returns # the same error code (i.e. 1) REGARDLESS whether the service is (A) disabled @@ -135,16 +176,18 @@ tmp=$(systemctl is-enabled systemd-networkd) # https://en.wikipedia.org/wiki/Here_document cat < var is initially set to 'False' at the bottom of -# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: -is_debuntu: True -is_debian: True # Opposite of is_ubuntu for now -is_debian_11: True - -# 2019-01-31: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dhcp_service: isc-dhcp-server -dns_user: bind - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_conf_dir: apache2/sites-available -apache_user: www-data -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 7.4 -postgresql_version: 13 -systemd_location: /lib/systemd/system -python_ver: 3.9 diff --git a/vars/debian-11.yml.unused b/vars/debian-11.yml.unused new file mode 100644 index 000000000..67020e3c3 --- /dev/null +++ b/vars/debian-11.yml.unused @@ -0,0 +1,20 @@ +# Every is_ var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_debian: True # Opposite of is_ubuntu for now +is_debian_11: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "7.4" +# postgresql_version: 13 +# python_version: "3.9" diff --git a/vars/debian-12.yml b/vars/debian-12.yml index 4ac59c25d..d06a61285 100644 --- a/vars/debian-12.yml +++ b/vars/debian-12.yml @@ -1,29 +1,5 @@ -# Every is_ var is initially set to 'False' at the bottom of +# Every is_ var is initially set to 'False' at the bottom of # /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: is_debuntu: True is_debian: True # Opposite of is_ubuntu for now is_debian_12: True - -# 2019-01-31: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dhcp_service: isc-dhcp-server -dns_user: bind - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_conf_dir: apache2/sites-available -apache_user: www-data -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 8.0 -postgresql_version: 13 -systemd_location: /lib/systemd/system -python_ver: 3.9 diff --git a/vars/debian-13.yml b/vars/debian-13.yml new file mode 100644 index 000000000..09ef89f68 --- /dev/null +++ b/vars/debian-13.yml @@ -0,0 +1,5 @@ +# Every is_ var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_debian: True # Opposite of is_ubuntu for now +is_debian_13: True diff --git a/vars/debian-8.yml b/vars/debian-8.yml.unused similarity index 100% rename from vars/debian-8.yml rename to vars/debian-8.yml.unused diff --git a/vars/debian-9.yml b/vars/debian-9.yml.unused similarity index 100% rename from vars/debian-9.yml rename to vars/debian-9.yml.unused diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 128cb899b..a45384e1e 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -13,9 +13,15 @@ # IIAB (PRE-)release version number, for {{ iiab_env_file }} -iiab_base_ver: 7.2 +iiab_base_ver: 8.3 iiab_revision: 0 +# 2022-06-23: ./iiab-install (with 'sudo iiab') follow the traditional linear +# install path, intentionally overriding this value, until "SOFTWARE INSTALL IS +# COMPLETE". But you can run './iiab-install --risky' if you truly need +# iiab-install to run with 'skip_role_on_error: True' (PRs #3255, #3256, #3262) +skip_role_on_error: True + iiab_etc_path: /etc/iiab # Main configuration file @@ -31,7 +37,7 @@ iiab_dir: "{{ iiab_base }}/iiab" pip_packages_dir: "{{ iiab_base }}/pip-packages" yum_packages_dir: "{{ iiab_base }}/yum-packages" downloads_dir: "{{ iiab_base }}/downloads" -iiab_download_url: http://download.iiab.io/packages +iiab_download_url: https://download.iiab.io/packages content_base: /library doc_base: "{{ content_base }}/www" @@ -66,9 +72,6 @@ admin_console_group: iiab-admin # This group & sudo log in to Admin Console. # Obtain a password hash - OLD WAY: # python -c 'import crypt; print crypt.crypt("", "$6$<salt>")' -# Time Zone (php used to need timezone set). SEE: roles/0-init/tasks/tz.yml -local_tz: "{{ ansible_date_time.tz }}" - # Set these to False if you do not want to install/enable IIAB Admin Console admin_console_install: True admin_console_enabled: True @@ -86,18 +89,18 @@ js_menu_install: True # IIAB Networking README: https://github.com/iiab/iiab/tree/master/roles/network # IIAB Networking Doc: https://github.com/iiab/iiab/wiki/IIAB-Networking # Read it offline too: http://box/info > "IIAB Networking" +network_install: True +network_enabled: True # NETWORK PARAMETERS FOLLOW ACROSS THE NEXT 100 LINES, as enabled by Ansible's # NETWORK role (/opt/iiab/iiab/roles/network). SEE ALSO: # https://github.com/iiab/iiab/blob/master/roles/network/defaults/main.yml -# The following variable may be useful in debugging: -disregard_network: False # Use cache, or error out if cache does not exist. - iiab_hostname: box iiab_domain: lan -lan_ip: 172.18.96.1 -lan_netmask: 255.255.224.0 +lan_ip: 10.10.10.10 +network_172: False # Change to True if you set the above to 172.18.96.1 +lan_netmask: 255.255.255.0 # Change to 255.255.224.0 if using 172.18.96.1 # Internal Wi-Fi Access Point # Values are used if there is an internal Wi-Fi adapter and hostapd is enabled. @@ -106,19 +109,46 @@ lan_netmask: 255.255.224.0 # YOU'LL PREVENT OLDER LAPTOPS/PHONES/TABLETS (WHICH REQUIRE 2.4 GHz) FROM # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. # -# Raspberry Pi OS requires WiFi country -- SET THIS IN /etc/iiab/local_vars.yml +# Raspberry Pi OS requires WiFi country since March 2018. +# +# If you're running Raspberry Pi OS, you may have already set the country code +# in /etc/wpa_supplicant/wpa_supplicant.conf e.g. if you ran raspi-config or used +# the Wi-Fi widget in the top-right of its graphical desktop. +# +# If so, this detected value will be considered authoritative, and will be used +# to populate /etc/hostapd/hostapd.conf +# +# Finally, if IIAB does not detect a country code from your OS, the following +# fallback variable will be used instead: (to populate /etc/hostapd/hostapd.conf) host_country_code: US host_ssid: Internet in a Box host_wifi_mode: g host_channel: 6 -hostapd_secure: False # 2021-03-02 #2696 WiFi EAPOL fails if hotspot passwords, -hostapd_password: changeme # eg if firmware wifi_hotspot_capacity_rpi_fix: True +hostapd_secure: False # 2021-03-02 WiFi EAPOL fails if hotspot passwords, +hostapd_password: changeme # espec if WiFi firmware patched below? #2696 hostapd_install: True # 2020-01-21: this var MIGHT be implemented in future. hostapd_enabled: True -wifi_hotspot_capacity_rpi_fix: True # Restores the ability of RPi internal -# WiFi hotspots to service 30-to-32 client devices. Background explanation: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and PR #2472. -wifi_up_down: True # Creates a 2nd virtual WiFi adapter for upstream WiFi + +# Raspberry Pi 3 B+ and 4 OS's don't allow more than ~4 students to use the +# internal WiFi hotspot. Increase this to 19 or 24 student WiFi devices (or +# 32 on older OS's from 2020) using EXACTLY 1 of the 5 lines below: +# +#rpi3bplus_rpi4_wifi_firmware: os # Use your OS's WiFi firmware e.g. 7.45.241 +#rpi3bplus_rpi4_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.234 +rpi3bplus_rpi4_wifi_firmware: 19 # SEE: github.com/iiab/iiab/issues/2853 +#rpi3bplus_rpi4_wifi_firmware: 24 # REQUIRES "wifi_up_down: False" BELOW! +#rpi3bplus_rpi4_wifi_firmware: 32 # UNRELIABLE (INTERMITTENT) with 2021+ OS's +# +# BACKGROUND: https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# +# Raspberry Pi Zero W and 3 OS's don't allow more than ~10 students to use the +# internal WiFi hotspot. Or try increasing this to 30 student WiFi devices: +# +rpizerow_rpi3_wifi_firmware: os # Use yr OS WiFi firmware e.g. 7.45.98 +#rpizerow_rpi3_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.98.118 +#rpizerow_rpi3_wifi_firmware: 30 # Or firmware 7.45.98.65 from 2018-09-28 + +wifi_up_down: True # AP+STA mode: Uses "ap0" WiFi adapter for upstream WiFi # (e.g. to Internet) in addition to downstream WiFi (e.g. classroom hotspot). # Set True if client machines should have "passthrough" access to WAN/Internet: @@ -140,7 +170,7 @@ wan_netmask: # wan_netmask: 255.255.255.0 wan_gateway: # wan_gateway: 192.168.1.254 # If nec wan_nameserver can override ISP-provided DNS servers via dnsmasq: # /etc/resolv.conf dictates which backend is used for the machine itself, so -# 127.0.0.1 means you get dnsmasq (so it works right away on RaspiOS) while +# 127.0.0.1 means you get dnsmasq (so it works right away on RasPiOS) while # 127.0.0.53 gives you systemd-networkd (so Ubuntu itself does NOT use this # dnsmasq-specified upstream DNS [e.g. wan_nameserver] but its LAN clients do!) wan_nameserver: # wan_nameserver: 192.168.1.254 or 8.8.8.8 or 1.1.1.1 @@ -163,23 +193,23 @@ ports_externally_visible: 3 # ssh + http-or-https + common IIAB services # # Or further customize your iptables firewall by editing: # /opt/iiab/iiab/roles/network/templates/gateway/iiab-gen-iptables -# And then run: cd /opt/iiab/iiab; ./iiab-network +# And then run: sudo iiab-network # dnsmasq - handles DHCP and DNS dnsmasq_install: True dnsmasq_enabled: True # UNMAINTAINED as of July 2021 -dhcpd_install: False -dhcpd_enabled: False +#dhcpd_install: False +#dhcpd_enabled: False # UNMAINTAINED as of July 2021 # named (BIND) -named_install: False -named_enabled: False +#named_install: False +#named_enabled: False block_DNS: False -# Enable in local_vars.yml AFTER installing IIAB! Then run "cd /opt/iiab/iiab; ./iiab-network" +# Enable in local_vars.yml AFTER installing IIAB! Then run: sudo iiab-network dns_jail_enabled: False # UNMAINTAINED as of October 2017: https://github.com/iiab/iiab/pull/382 @@ -189,27 +219,22 @@ dns_jail_enabled: False # 1-PREP -# SSHD runs here & also below in 4-SERVER-OPTIONS -sshd_install: True # Required by OpenVPN +# OPENSSH-SERVER +sshd_install: True sshd_enabled: True sshd_port: 22 # Not fully functional. SEE: roles/sshd/tasks/install.yml # https://remote.it can help you remotely maintain an IIAB. +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/remoteit remoteit_install: True remoteit_enabled: False +# OPTION #1: Run 'sudo iiab-remoteit' later. OPTION #2: Set this now: +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 -openvpn_install: True -openvpn_enabled: False -# For /etc/iiab/openvpn_handle -openvpn_handle: "" # Empty string on purpose since ~2016, for /etc/iiab/uuid -# SEE https://github.com/iiab/iiab/blob/master/roles/openvpn/tasks/main.yml#L45 -# cron seems necessary on CentOS: -openvpn_cron_enabled: False -# General OpenVPN settings -openvpn_server: xscenet.net -openvpn_server_real_ip: 3.89.148.185 -openvpn_server_virtual_ip: 10.8.0.1 -openvpn_server_port: 1194 +# SECURITY WARNING: https://wiki.iiab.io/go/Security +# New VPN replaced OpenVPN in Sept 2024: +tailscale_install: True +tailscale_enabled: False # Stub var, doesn't yet do anything! # IIAB-ADMIN runs here - see its vars near top of this file: # e.g. iiab_admin_user, iiab_admin_user_install, iiab_admin_can_sudo, @@ -217,7 +242,7 @@ openvpn_server_port: 1194 # dnsmasq is installed here -- configure LATER in 'network', after Stage 9. # (The full network stage runs after 9-LOCAL-ADDONS. Or manually run -# "cd /opt/iiab/iiab; sudo ./iiab-network"). Design under discussion: #2876 +# "sudo iiab-network"). Design under discussion: #2876 # Some prefer 512MB for Zero W, others prefer 2048MB or higher for RPi 3 and 4. # Please see recommendations at: https://itsfoss.com/swap-size/ @@ -232,12 +257,13 @@ pi_swap_file_size: 1024 # 3-BASE-SERVER -# 2020-09-24: MySQL / MariaDB is MANDATORY but still evolving - please see: -# https://github.com/iiab/iiab/blob/master/roles/mysql/tasks/install.yml -# https://github.com/iiab/iiab/blob/master/roles/3-base-server/tasks/main.yml -# THESE 2 LEGACY VARS ARE PRESERVED BUT HAVE NO EFFECT: -mysql_install: True -mysql_enabled: True +# 2023-11-05: MySQL (actually MariaDB) had been mandatory, installed on every +# IIAB by 3-base-server. Now installed on demand -- as a dependency of Matomo, +# MediaWiki, Nextcloud, PBX (for FreePBX), WordPress &/or Admin Console. +# SO BOTH VALUES BELOW ARE INITIALLY IGNORED: +mysql_install: False +mysql_enabled: False +mysql_service: mariadb # 2020-09-24: NGINX is MANDATORY but still evolving - please see: # https://github.com/iiab/iiab/blob/master/roles/nginx/README.md @@ -248,15 +274,13 @@ nginx_port: 80 nginx_interface: 0.0.0.0 nginx_conf_dir: /etc/nginx/conf.d nginx_log_dir: /var/log/nginx -# SEE BELOW: nginx_high_php_limits, apache_allow_sudo +# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff # roles/www_base runs here (mandatory) # 4-SERVER-OPTIONS -# SSHD runs here & also above in 1-PREP - # DNS prep (named &/or dhcpd) used to run here. See dnsmasq in 1-PREP above. # Proxy Cache & basic site blocking using /etc/squid allowlists: (whitelists) @@ -266,6 +290,8 @@ squid_install: False squid_enabled: False # Enabling this ~= 'iiab_gateway_enabled: True' (ABOVE) gw_squid_whitelist: False # Works with HTTP sites, not HTTPS sites ! gw_block_https: False +proxy: squid # Admin Console uses +proxy_user: proxy # Could move to roles/network/defaults/main.yml # UNMAINTAINED as of July 2021 # DansGuardian REQUIRES Squid (above) be installed & enabled. @@ -281,11 +307,10 @@ bluetooth_term_enabled: False # USB_LIB usb_lib_install: True usb_lib_enabled: True -# Show entire contents of USB sticks/drives (at http://box/usb) -iiab_usb_lib_show_all: True -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +usb_lib_writable_sticks: True +systemd_location: /lib/systemd/system # 2-common iiab-startup also uses # Common UNIX Printing System (CUPS) cups_install: False @@ -298,19 +323,25 @@ samba_enabled: False samba_udp_ports: 137:138 samba_tcp_mports: 139,445 shared_dir : "{{ content_base }}/public" # /library/public +smb_service: smbd # Admin Console uses +nmb_service: nmbd # Could move to roles/samba/defaults/main.yml # roles/www_options HANDLES THE 3 VARS BELOW: -# For schools that use WordPress/Nextcloud/Moodle/PBX intensively: +# Set to True if intensively using Matomo/PBX/WordPress: nginx_high_php_limits: False -# WARNING: Enabling this might cause excess use of RAM/disk or other resources! -# roles/www_options & roles/moodle FORCE high limits if 'moodle_install: True' -# REGARDLESS: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... -# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L53-L133 +# SIMILARLY: 'moodle_install: True' and 'nextcloud_install: True' effectively +# force this, via roles/www_options & roles/moodle & roles/nextcloud +# WARNING: This might cause excess use of RAM/disk or other resources! +# WARNING: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... +# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml # ...ARE SUITABLE FOR YOUR HARDWARE, as saved in: /etc/php/<VERSION>/*/php.ini +# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf -# Make this False to disable http://box/common/services/power_off.php button: -apache_allow_sudo: True +# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php +allow_www_data_poweroff: False +apache_service: apache2 +apache_user: www-data # Admin Console uses # Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info) nodocs: False @@ -322,20 +353,20 @@ nodocs: False # http://lists.laptop.org/pipermail/server-devel/ if you're able to help test. # UNMAINTAINED since about 2012-2017 -xo_services_install: False # 2020-01-23: UNUSED -xo_services_enabled: False # 2020-01-23: Used in idmgr/tasks/main.yml & iiab-admin-console/roles/console/files/htmlf/20-configure.html +#xo_services_install: False # 2020-01-23: UNUSED +#xo_services_enabled: False # 2020-01-23: Used in idmgr/tasks/main.yml & iiab-admin-console/roles/console/files/htmlf/20-configure.html # UNMAINTAINED since about 2012-2017 -activity_server_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml (originally defined in activity-server/defaults/main.yml) -activity_server_enabled: False # 2020-01-23: Used in activity-server/tasks/main.yml (originally defined in activity-server/defaults/main.yml) +#activity_server_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml (originally defined in activity-server/defaults/main.yml) +#activity_server_enabled: False # 2020-01-23: Used in activity-server/tasks/main.yml (originally defined in activity-server/defaults/main.yml) # UNMAINTAINED since about 2012-2017: consider 'ejabberd' in Stage 6-GENERIC-APPS below? -ejabberd_xs_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml & roles/ejabberd_xs/tasks/main.yml -ejabberd_xs_enabled: False # 2020-01-23: Used in roles/ejabberd_xs/tasks/main.yml +#ejabberd_xs_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml & roles/ejabberd_xs/tasks/main.yml +#ejabberd_xs_enabled: False # 2020-01-23: Used in roles/ejabberd_xs/tasks/main.yml # UNMAINTAINED since about 2012-2017: change calibre_port from 8080 to 8010 below, if you use idmgr -idmgr_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml -idmgr_enabled: False # 2020-01-23: UNUSED +#idmgr_install: False # 2020-01-23: Used in 5-xo-services/tasks/main.yml +#idmgr_enabled: False # 2020-01-23: UNUSED # 6-GENERIC-APPS @@ -343,27 +374,27 @@ idmgr_enabled: False # 2020-01-23: UNUSED # Simple, Self-Hosted Web Radio - from AzuraCast.com azuracast_install: False azuracast_enabled: False # This var is currently IGNORED -azuracast_http_port: 10080 -azuracast_https_port: 10443 +azuracast_http_port: 12080 +azuracast_https_port: 12443 # -# AzuraCast needs many ports in the 8000:8100 range by default, but IIAB -# services conflict with those ports so this variable below sets a sane prefix. -# e.g. setting the below variable to 10 will result in port ranges 10000-10100 +# AzuraCast needs many ports in the 8000:8496 range by default, but IIAB +# services conflict, so this variable below sets a sane prefix. +# e.g. setting the below variable to 10 will result in port range 10000-10499 # being reserved for AzuraCast: azuracast_port_range_prefix: 10 # UNMAINTAINED as of January 2020: https://github.com/iiab/iiab/issues/2056 -dokuwiki_install: False -dokuwiki_enabled: False -dokuwiki_url: /dokuwiki +#dokuwiki_install: False +#dokuwiki_enabled: False +#dokuwiki_url: /dokuwiki # UNMAINTAINED as of November 2019 -ejabberd_install: False -ejabberd_enabled: False +#ejabberd_install: False +#ejabberd_enabled: False # UNMAINTAINED as of July 2021 -elgg_install: False -elgg_enabled: False +#elgg_install: False +#elgg_enabled: False # elgg_mysql_password: $6$iiab51$jeTwnATcbaa92xo0QBTgjLBU.5aVDDrbKeNyyC99R/TAWz6pvfzj.L7lfnOVVjD78nxqT.gkNn6XZmuRV0W3o1 elgg_mysql_password: elgg4kids @@ -379,9 +410,9 @@ jupyterhub_enabled: False jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 -# Lokole (email for rural communities) from https://ascoderu.ca -lokole_install: False -lokole_enabled: False +# UNMAINTAINED: Lokole (email for rural communities) from https://ascoderu.ca +lokole_install: False # 2022-03-13: Python 3.9+ work +lokole_enabled: False # https://github.com/iiab/iiab/issues/3132 # lokole_sim_type can be: 'hologram', 'Ethernet', 'LocalOnly', or 'mkwvconf' # Details: https://github.com/ascoderu/lokole/blob/master/install.py#L35 lokole_sim_type: LocalOnly @@ -401,7 +432,7 @@ mosquitto_port: 1883 # JupyterHub, nodered (Node-RED), pbx (Asterix, FreePBX) &/or Sugarizer: nodejs_install: False nodejs_enabled: False -nodejs_version: 16.x # was 8.x til 2019-02-02, 10.x til 2019-12-21, 12.x til 2020-10-29, 14.x til 2021-06-17 +nodejs_version: 22.x # was 8.x til 2019-02-02, 10.x til 2019-12-21, 12.x til 2020-10-29, 14.x til 2021-06-17, 16.x til 2022-04-20, 18.x til 2023-05-20, 20.x til 2024-05-03 # Flow-based visual programming for wiring together IoT hardware devices etc nodered_install: False @@ -423,7 +454,7 @@ nextcloud_enabled: False # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # Uncomment the following line to end that: (might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 # If using WordPress intensively, set nginx_high_php_limits further above. wordpress_install: False @@ -433,15 +464,17 @@ wordpress_enabled: False # 7-EDU-APPS # KA Lite - SEE THE "Transmission" BITTORRENT DOWNLOADER FURTHER BELOW, TO INSTALL THOUSANDS OF VIDEOS -kalite_install: True -kalite_enabled: True +kalite_install: False +kalite_enabled: False kalite_server_port: 8008 kalite_root: "{{ content_base }}/ka-lite" # /library/ka-lite # Successor to KA Lite, for offline-first teaching and learning - from learningequality.org -kolibri_install: False -kolibri_enabled: False -kolibri_language: en # See KOLIBRI_SUPPORTED_LANGUAGES at the bottom of https://github.com/learningequality/kolibri/blob/develop/kolibri/utils/i18n.py +kolibri_install: True +kolibri_enabled: True +kolibri_language: en # See KOLIBRI_SUPPORTED_LANGUAGES at the bottom of https://github.com/learningequality/kolibri/blob/develop/kolibri/utils/i18n.py +kolibri_home: "{{ content_base }}/kolibri" # /library/kolibri +kolibri_user: kolibri # WARNING: https://github.com/learningequality/kolibri-installer-debian/issues/115 kolibri_http_port: 8009 # kiwix_install: True is REQUIRED, if you install IIAB's Admin Console @@ -458,10 +491,11 @@ kiwix_apk_src: https://download.kiwix.org/release/kiwix-android/kiwix.apk postgresql_install: False postgresql_enabled: False -# Warning: Moodle is a serious LMS, that takes a while to install. +# Warning: Moodle is a serious LMS, that takes a while to install moodle_install: False moodle_enabled: False -# If using Moodle intensively, set nginx_high_php_limits further above. +# FYI 'nginx_high_php_limits: True' (explained above) is mandated with Moodle, +# as auto-enacted by roles/www_options/tasks/php-settings.yml # Regional OSM vector maps use far less disk space than bitmap/raster versions. # Instructions: https://github.com/iiab/iiab/wiki/IIAB-Maps @@ -469,7 +503,6 @@ osm_vector_maps_install: True osm_vector_maps_enabled: False # Set to "True" to download .mbtiles files from Archive.org (might be slow!) maps_from_internet_archive: False -iiab_map_url : http://download.iiab.io/content/OSM/vector-tiles/maplist/hidden vector_map_path: "{{ content_base }}/www/osm-vector-maps" # /library/www/osm-vector-maps # MongoDB (/library/dbdata/mongodb) greatly enhances the Sugarizer experience. @@ -499,6 +532,7 @@ sugarizer_port: 8089 # Transmission is a BitTorrent downloader for large Content Packs etc transmission_install: False transmission_enabled: False +transmission_compile_latest: False transmission_username: Admin transmission_password: changeme @@ -510,11 +544,11 @@ transmission_group: debian-transmission # Monitor downloads at http://box:9091 or http://box:9091/transmission using Admin/changeme transmission_http_port: 9091 transmission_url: /transmission/ -transmission_whitelist: 127.0.0.1,::1,192.168.*.*,172.18.96.*,10.8.0.* +transmission_whitelist: 127.0.0.1,::1,192.168.*.*,10.10.10,*,172.18.96.*,10.8.0.* transmission_whitelist_enabled: "false" # LOWERCASE STRING for settings.json transmission_peer_port: 51413 -# Provision Transmission with torrent(s) from http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# Provision Transmission with torrent(s) from https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ transmission_provision: True transmission_kalite_version: 0.17 @@ -539,6 +573,11 @@ transmission_kalite_languages: awstats_install: True awstats_enabled: True +# Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership. +matomo_install: True +matomo_enabled: True +# If using Matomo intensively, investigate nginx_high_php_limits further above. + # Process supervision tool - from https://mmonit.com/monit/ # 2020-09-22 WARNING: both vars are IGNORED on Debian 10 due to: iiab/iiab#1849 monit_install: False @@ -593,13 +632,18 @@ internetarchive_port: 4244 # for http://box:4244 minetest_install: False minetest_enabled: False minetest_port: 30000 +minetest_working_dir: /usr/share/games/minetest + minetest_server_admin: Admin -minetest_default_game: carbone-ng # only carbone-ng and minetest are supported +# minetest_default_game: carbone-ng # carbone-ng is not longer compatible so not supported +minetest_default_game: minetest +# minetest_default_game: dreambuilder - after 5.6 +minetest_game_dir: "{{ minetest_working_dir }}/games/{{ minetest_default_game }}_game" minetest_flat_world: False # Calibre-Web E-Book Library -- Alternative to Calibre, offers a clean/modern UX -calibreweb_install: False -calibreweb_enabled: False +calibreweb_install: True +calibreweb_enabled: True calibreweb_port: 8083 # PORT VARIABLE HAS NO EFFECT (as of January 2019) # http://box/books works. Add {box/libros, box/livres, box/livros, box/liv} etc? calibreweb_url1: /books # For SHORT URL http://box/books (English) @@ -628,13 +672,14 @@ calibre_web_path: calibre #NEEDS WORK: https://github.com/iiab/iiab/issues/529 # Avoid URL collisions w/ calibreweb_url1, calibreweb_url2, calibreweb_url3 below! # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# REQUIRES PHP 7.4 e.g. Ubuntu 20.04, Debian 11 -- RaspiOS 11 might also work. -# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#readme # If using PBX intensively, investigate nginx_high_php_limits further above. pbx_install: False pbx_enabled: False -pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +asterisk_rpi_patch: False asterisk_chan_dongle: False pbx_signaling_ports_chan_sip: 5160:5161 pbx_signaling_ports_chan_pjsip: 5060 @@ -660,7 +705,7 @@ pbx_http_port: 83 # authserver_install: False # authserver_enabled: False -# Unmaintained (better to install from http://teamviewer.com or prep scripts at http://download.iiab.io) +# Unmaintained (better to install from https://teamviewer.com or prep scripts at https://download.iiab.io) # teamviewer_install: False # teamviewer_enabled: False @@ -710,45 +755,55 @@ pbx_http_port: 83 # OS-DEPENDENT VARS: TURN OFF ALL VARS BELOW AND THEN THE CORRECT -# /opt/iiab/iiab/vars/<OS>.yml WILL TURN ON WHAT'S APPROPRIATE. See "How This -# Works" ~32 lines below, and https://github.com/iiab/iiab/wiki/IIAB-Platforms +# /opt/iiab/iiab/vars/<OS_VER>.yml WILL TURN ON WHAT'S APPROPRIATE. See +# "How This Works" below, and https://github.com/iiab/iiab/wiki/IIAB-Platforms # Wide to narrow (insofar as poss) is_debuntu: False # Covers all 4: Ubuntu, Linux Mint, Debian, Raspberry Pi OS (Raspbian) is_ubuntu: False # Covers: Ubuntu, Linux Mint +is_ubuntu_2504: False +is_ubuntu_2410: False +is_ubuntu_2404: False +is_ubuntu_2310: False +#is_ubuntu_2304: False +#is_ubuntu_2210: False is_ubuntu_2204: False -is_ubuntu_2110: False -is_ubuntu_2104: False -is_ubuntu_2004: False -is_ubuntu_19: False -is_ubuntu_18: False -is_ubuntu_17: False -is_ubuntu_16: False +#is_ubuntu_2110: False +#is_ubuntu_2104: False +#is_ubuntu_2004: False +#is_ubuntu_19: False +#is_ubuntu_18: False +#is_ubuntu_17: False +#is_ubuntu_16: False is_linuxmint: False # Subset of is_ubuntu -is_linuxmint_21: False -is_linuxmint_20: False +is_linuxmint_22: False +#is_linuxmint_21: False +#is_linuxmint_20: False is_debian: False # Covers both: Debian, Raspberry Pi OS (Raspbian) +is_debian_13: False is_debian_12: False -is_debian_11: False -is_debian_10: False -is_debian_9: False -is_debian_8: False +#is_debian_11: False +#is_debian_10: False +#is_debian_9: False +#is_debian_8: False is_raspbian: False # Covers both: RPi HW + non-RPi HW versions of Raspberry Pi OS (Raspbian) -is_raspbian_11: False -is_raspbian_10: False -is_raspbian_9: False -is_raspbian_8: False +is_raspbian_13: False +is_raspbian_12: False +#is_raspbian_11: False +#is_raspbian_10: False +#is_raspbian_9: False +#is_raspbian_8: False -is_redhat: False # Not well supported as of 2019, see: https://github.com/iiab/iiab/issues/1434 -is_centos: False -is_centos_7: False -is_fedora: False -is_fedora_22: False -is_fedora_18: False +#is_redhat: False # Unsupported as of 2019, see: https://github.com/iiab/iiab/issues/1434 +#is_centos: False +#is_centos_7: False +#is_fedora: False +#is_fedora_22: False +#is_fedora_18: False # How This Works: # diff --git a/vars/fedora-18.yml b/vars/fedora-18.yml.unused similarity index 100% rename from vars/fedora-18.yml rename to vars/fedora-18.yml.unused diff --git a/vars/fedora-22.yml b/vars/fedora-22.yml.unused similarity index 100% rename from vars/fedora-22.yml rename to vars/fedora-22.yml.unused diff --git a/vars/linuxmint-20.yml b/vars/linuxmint-20.yml deleted file mode 100644 index 0afc95bb0..000000000 --- a/vars/linuxmint-20.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Every is_<OS> var is initially set to 'False' at the bottom of -# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: -is_debuntu: True -is_ubuntu: True # Opposite of is_debian for now -is_ubuntu_20: True -is_linuxmint: True -is_linuxmint_20: True - -# 2019-03-23: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dns_user: bind -dhcp_service: isc-dhcp-server - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_user: www-data -apache_conf_dir: apache2/sites-available -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 7.4 -postgresql_version: 12 -systemd_location: /lib/systemd/system -python_ver: 3.8 diff --git a/vars/linuxmint-20.yml.unused b/vars/linuxmint-20.yml.unused new file mode 100644 index 000000000..3d1c4c7a9 --- /dev/null +++ b/vars/linuxmint-20.yml.unused @@ -0,0 +1,22 @@ +# Every is_<OS> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_20: True +is_linuxmint: True +is_linuxmint_20: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "7.4" +# postgresql_version: 12 +# python_version: "3.8" diff --git a/vars/linuxmint-21.yml b/vars/linuxmint-21.yml deleted file mode 100644 index 5a1e79131..000000000 --- a/vars/linuxmint-21.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Every is_<OS> var is initially set to 'False' at the bottom of -# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: -is_debuntu: True -is_ubuntu: True # Opposite of is_debian for now -is_ubuntu_22: True -is_linuxmint: True -is_linuxmint_21: True - -# 2019-03-23: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dns_user: bind -dhcp_service: isc-dhcp-server - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_user: www-data -apache_conf_dir: apache2/sites-available -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 8.1 -postgresql_version: 14 -systemd_location: /lib/systemd/system -python_ver: 3.10 diff --git a/vars/linuxmint-21.yml.unused b/vars/linuxmint-21.yml.unused new file mode 100644 index 000000000..85d2c51c1 --- /dev/null +++ b/vars/linuxmint-21.yml.unused @@ -0,0 +1,22 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2204: True +is_linuxmint: True +is_linuxmint_21: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "8.1" +# postgresql_version: 14 +# python_version: "3.10" diff --git a/vars/linuxmint-22.yml b/vars/linuxmint-22.yml new file mode 100644 index 000000000..53af5a21c --- /dev/null +++ b/vars/linuxmint-22.yml @@ -0,0 +1,7 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2404: True +is_linuxmint: True +is_linuxmint_22: True diff --git a/vars/local_vars_large.yml b/vars/local_vars_large.yml index 6ca05ce25..7228bb506 100644 --- a/vars/local_vars_large.yml +++ b/vars/local_vars_large.yml @@ -1,7 +1,7 @@ # This is local_vars_large.yml -- copy it to /etc/iiab/local_vars.yml then... # modify variables below, to override /opt/iiab/iiab/vars/default_vars.yml -# PLZ READ http://wiki.laptop.org/go/IIAB/local_vars.yml AND http://FAQ.IIAB.IO +# READ "What is local_vars.yml and how do I customize it?" AT http://FAQ.IIAB.IO # Orig Idea: branch github.com/xsce/xsce-local for your deployment/community # IIAB does NOT currently support uninstalling apps! So: if any IIAB app is @@ -54,17 +54,44 @@ iiab_domain: lan # YOU'LL PREVENT OLDER LAPTOPS/PHONES/TABLETS (WHICH REQUIRE 2.4 GHz) FROM # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. # -# Raspberry Pi OS requires Wi-Fi country since March 2018. Please set it here: +# Raspberry Pi OS requires WiFi country since March 2018. +# +# If you're running Raspberry Pi OS, you may have already set the country code +# in /etc/wpa_supplicant/wpa_supplicant.conf e.g. if you ran raspi-config or used +# the Wi-Fi widget in the top-right of its graphical desktop. +# +# If so, this detected value will be considered authoritative, and will be used +# to populate /etc/hostapd/hostapd.conf +# +# Finally, if IIAB does not detect a country code from your OS, the following +# fallback variable will be used instead: (to populate /etc/hostapd/hostapd.conf) host_country_code: US host_ssid: Internet in a Box host_wifi_mode: g host_channel: 6 -hostapd_secure: False # 2021-03-02 #2696 WiFi EAPOL fails if hotspot passwords, -hostapd_password: changeme # eg if firmware wifi_hotspot_capacity_rpi_fix: True -wifi_hotspot_capacity_rpi_fix: True # Restores the ability of RPi internal -# WiFi hotspots to service 30-to-32 client devices. Background explanation: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and PR #2472. -wifi_up_down: True # Creates a 2nd virtual WiFi adapter for upstream WiFi +hostapd_secure: False # 2021-03-02 WiFi EAPOL fails if hotspot passwords, +hostapd_password: changeme # espec if WiFi firmware patched below? #2696 + +# Raspberry Pi 3 B+ and 4 OS's don't allow more than ~4 students to use the +# internal WiFi hotspot. Increase this to 19 or 24 student WiFi devices (or +# 32 on older OS's from 2020) using EXACTLY 1 of the 5 lines below: +# +#rpi3bplus_rpi4_wifi_firmware: os # Use your OS's WiFi firmware e.g. 7.45.241 +#rpi3bplus_rpi4_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.234 +rpi3bplus_rpi4_wifi_firmware: 19 # SEE: github.com/iiab/iiab/issues/2853 +#rpi3bplus_rpi4_wifi_firmware: 24 # REQUIRES "wifi_up_down: False" BELOW! +#rpi3bplus_rpi4_wifi_firmware: 32 # UNRELIABLE (INTERMITTENT) with 2021+ OS's +# +# BACKGROUND: https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# +# Raspberry Pi Zero W and 3 OS's don't allow more than ~10 students to use the +# internal WiFi hotspot. Or try increasing this to 30 student WiFi devices: +# +rpizerow_rpi3_wifi_firmware: os # Use yr OS WiFi firmware e.g. 7.45.98 +#rpizerow_rpi3_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.98.118 +#rpizerow_rpi3_wifi_firmware: 30 # Or firmware 7.45.98.65 from 2018-09-28 + +wifi_up_down: True # AP+STA mode: Uses "ap0" WiFi adapter for upstream WiFi # (e.g. to Internet) in addition to downstream WiFi (e.g. classroom hotspot). # Set True if client machines should have "passthrough" access to WAN/Internet: @@ -77,7 +104,7 @@ wan_netmask: # wan_netmask: 255.255.255.0 wan_gateway: # wan_gateway: 192.168.1.254 # If nec wan_nameserver can override ISP-provided DNS servers via dnsmasq: # /etc/resolv.conf dictates which backend is used for the machine itself, so -# 127.0.0.1 means you get dnsmasq (so it works right away on RaspiOS) while +# 127.0.0.1 means you get dnsmasq (so it works right away on RasPiOS) while # 127.0.0.53 gives you systemd-networkd (so Ubuntu itself does NOT use this # dnsmasq-specified upstream DNS [e.g. wan_nameserver] but its LAN clients do!) wan_nameserver: # wan_nameserver: 192.168.1.254 or 8.8.8.8 or 1.1.1.1 @@ -97,34 +124,36 @@ ports_externally_visible: 3 # ssh + http-or-https + common IIAB services # # Or further customize your iptables firewall by editing: # /opt/iiab/iiab/roles/network/templates/gateway/iiab-gen-iptables -# And then run: cd /opt/iiab/iiab; ./iiab-network +# And then run: sudo iiab-network -# Enable AFTER installing IIAB! Then run "cd /opt/iiab/iiab; ./iiab-network" +# Enable AFTER installing IIAB! Then run: sudo iiab-network dns_jail_enabled: False # 1-PREP -# SSHD runs here & also below in 4-SERVER-OPTIONS -sshd_install: True # Required by OpenVPN +# OPENSSH-SERVER +sshd_install: True sshd_enabled: True # https://remote.it can help you remotely maintain an IIAB. +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/remoteit remoteit_install: True remoteit_enabled: False +# OPTION #1: Run 'sudo iiab-remoteit' later. OPTION #2: Set this now: +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 -# SECURITY WARNING: See http://wiki.laptop.org/go/IIAB/Security -openvpn_install: True -openvpn_enabled: False -# 2021-08-18 SSOT: Please set it here, no longer in /etc/iiab/openvpn_handle -openvpn_handle: LARGE - Put Your Name Here +# SECURITY WARNING: https://wiki.iiab.io/go/Security +# New VPN replaced OpenVPN in Sept 2024: +tailscale_install: True +tailscale_enabled: False # Stub var, doesn't yet do anything! # IIAB-ADMIN runs here - see its vars near top of this file: # e.g. iiab_admin_user, iiab_admin_user_install, iiab_admin_can_sudo # dnsmasq is installed here -- configure LATER in 'network', after Stage 9. # (The full network stage runs after 9-LOCAL-ADDONS. Or manually run -# "cd /opt/iiab/iiab; sudo ./iiab-network"). Design under discussion: #2876 +# "sudo iiab-network"). Design under discussion: #2876 # Some prefer 512MB for Zero W, others prefer 2048MB or higher for RPi 3 and 4. # Please see recommendations at: https://itsfoss.com/swap-size/ @@ -143,13 +172,11 @@ pi_swap_file_size: 1024 # roles/nginx runs here (mandatory) # roles/www_base runs here (mandatory) -# SEE BELOW: nginx_high_php_limits, apache_allow_sudo +# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff # 4-SERVER-OPTIONS -# SSHD runs here & also above in 1-PREP - # DNS prep (named &/or dhcpd) used to run here. See dnsmasq in 1-PREP above. # Proxy Cache & basic site blocking using /etc/squid allowlists: (whitelists) @@ -165,11 +192,9 @@ bluetooth_install: True bluetooth_enabled: False bluetooth_term_enabled: False -# Show entire contents of USB sticks/drives (at http://box/usb) -iiab_usb_lib_show_all: True -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +usb_lib_writable_sticks: True # Common UNIX Printing System (CUPS) cups_install: True @@ -181,16 +206,18 @@ samba_enabled: False # roles/www_options HANDLES THE 3 VARS BELOW: -# For schools that use WordPress/Nextcloud/Moodle/PBX intensively: +# Set to True if intensively using Matomo/PBX/WordPress: nginx_high_php_limits: False -# WARNING: Enabling this might cause excess use of RAM/disk or other resources! -# roles/www_options & roles/moodle FORCE high limits if 'moodle_install: True' -# REGARDLESS: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... -# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L53-L133 +# SIMILARLY: 'moodle_install: True' and 'nextcloud_install: True' effectively +# force this, via roles/www_options & roles/moodle & roles/nextcloud +# WARNING: This might cause excess use of RAM/disk or other resources! +# WARNING: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... +# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml # ...ARE SUITABLE FOR YOUR HARDWARE, as saved in: /etc/php/<VERSION>/*/php.ini +# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf -# Make this False to disable http://box/common/services/power_off.php button: -apache_allow_sudo: True +# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php +allow_www_data_poweroff: False # Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info) nodocs: False @@ -204,10 +231,6 @@ nodocs: False # 6-GENERIC-APPS -# Simple, Self-Hosted Web Radio - from AzuraCast.com -azuracast_install: False -azuracast_enabled: False # This var is currently IGNORED. - # Gitea (lightweight self-hosted "GitHub") from https://gitea.io gitea_install: True gitea_enabled: True @@ -216,9 +239,9 @@ gitea_enabled: True jupyterhub_install: True jupyterhub_enabled: True -# Lokole (email for rural communities) from https://ascoderu.ca -lokole_install: True -lokole_enabled: True +# UNMAINTAINED: Lokole (email for rural communities) from https://ascoderu.ca +lokole_install: False # 2023-09-06: wheel for mkwvconf still +lokole_enabled: False # missing from Ubuntu 23.10 (#3572) # Wikipedia's community editing platform - from MediaWiki.org mediawiki_install: True @@ -246,7 +269,7 @@ nextcloud_enabled: True # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # Uncomment the following line to end that: (might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 # If using WordPress intensively, set nginx_high_php_limits further above. wordpress_install: True @@ -262,7 +285,7 @@ kalite_enabled: True # Successor to KA Lite, for offline-first teaching and learning - from learningequality.org kolibri_install: True kolibri_enabled: True -kolibri_language: en # ar,bg-bg,bn-bd,de,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,hi-in,it,km,ko,mr,my,nyn,pt-br,sw-tz,te,ur-pk,vi,yo,zh-hans +kolibri_language: en # ar,bg-bg,bn-bd,de,el,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,ha,hi-in,ht,id,it,ka,km,ko,mr,my,nyn,pt-br,pt-mz,sw-tz,te,uk,ur-pk,vi,yo,zh-hans # kiwix_install: True is REQUIRED, if you install IIAB's Admin Console kiwix_install: True @@ -271,7 +294,8 @@ kiwix_enabled: True # Warning: Moodle is a serious LMS, that takes a while to install moodle_install: True moodle_enabled: True -# If using Moodle intensively, set nginx_high_php_limits further above. +# FYI 'nginx_high_php_limits: True' (explained above) is mandated with Moodle, +# as auto-enacted by roles/www_options/tasks/php-settings.yml # Regional OSM vector maps use far less disk space than bitmap/raster versions. # Instructions: https://github.com/iiab/iiab/wiki/IIAB-Maps @@ -292,8 +316,9 @@ sugarizer_enabled: True # BitTorrent downloader for large Content Packs etc transmission_install: True transmission_enabled: True +transmission_compile_latest: False # A. UNCOMMENT LANGUAGE(S) TO DOWNLOAD KA Lite VIDEOS TO /library/transmission -# using http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# using https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ transmission_kalite_languages: #- english #- french @@ -314,6 +339,11 @@ transmission_kalite_languages: awstats_install: True awstats_enabled: True +# Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership. +matomo_install: True +matomo_enabled: True +# If using Matomo intensively, investigate nginx_high_php_limits further above. + # Process supervision tool - from https://mmonit.com/monit/ # 2020-09-22 WARNING: both vars are IGNORED on Debian 10 due to: iiab/iiab#1849 monit_install: False @@ -335,6 +365,10 @@ vnstat_enabled: True # 9-LOCAL-ADDONS +# Simple, Self-Hosted Web Radio - from AzuraCast.com +azuracast_install: False +azuracast_enabled: False # This var is currently IGNORED. + # Python-based Captive Portal, that @m-anish & @jvonau experimented with in # July 2018 (https://github.com/iiab/iiab/pull/870) and that @georgejhunt # extensively later refined (PRs #1179, #1300, #1327, #2070). @@ -378,11 +412,12 @@ calibre_web_path: calibre #NEEDS WORK: https://github.com/iiab/iiab/issues/529 # Avoid URL collisions w/ calibreweb_url1, calibreweb_url2, calibreweb_url3 below! # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# REQUIRES PHP 7.4 e.g. Ubuntu 20.04, Debian 11 -- RaspiOS 11 might also work. -# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#readme # If using PBX intensively, investigate nginx_high_php_limits further above. pbx_install: False pbx_enabled: False -pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +asterisk_rpi_patch: False asterisk_chan_dongle: False diff --git a/vars/local_vars_medical.yml b/vars/local_vars_medical.yml index cd1dd354b..445c9bb2f 100644 --- a/vars/local_vars_medical.yml +++ b/vars/local_vars_medical.yml @@ -1,7 +1,7 @@ # Default overrides kiwix_incl_apk: True -kalite_install: False -kalite_enabled: False +kolibri_install: False +kolibri_enabled: False captiveportal_install: True captiveportal_enabled: True mediawiki_install: True @@ -12,8 +12,8 @@ munin_install: True munin_enabled: True vnstat_install: True vnstat_enabled: True -openvpn_handle: "MEDICAL - Put Your Name Here" -usb_lib_umask0000_for_kolibri: False +usb_lib_writable_sticks: False +allow_www_data_poweroff: False # By default # kiwix # awstats diff --git a/vars/local_vars_medium.yml b/vars/local_vars_medium.yml index 52d710ca2..153401d26 100644 --- a/vars/local_vars_medium.yml +++ b/vars/local_vars_medium.yml @@ -1,7 +1,7 @@ # This is local_vars_medium.yml -- copy it to /etc/iiab/local_vars.yml then... # modify variables below, to override /opt/iiab/iiab/vars/default_vars.yml -# PLZ READ http://wiki.laptop.org/go/IIAB/local_vars.yml AND http://FAQ.IIAB.IO +# READ "What is local_vars.yml and how do I customize it?" AT http://FAQ.IIAB.IO # Orig Idea: branch github.com/xsce/xsce-local for your deployment/community # IIAB does NOT currently support uninstalling apps! So: if any IIAB app is @@ -54,17 +54,44 @@ iiab_domain: lan # YOU'LL PREVENT OLDER LAPTOPS/PHONES/TABLETS (WHICH REQUIRE 2.4 GHz) FROM # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. # -# Raspberry Pi OS requires Wi-Fi country since March 2018. Please set it here: +# Raspberry Pi OS requires WiFi country since March 2018. +# +# If you're running Raspberry Pi OS, you may have already set the country code +# in /etc/wpa_supplicant/wpa_supplicant.conf e.g. if you ran raspi-config or used +# the Wi-Fi widget in the top-right of its graphical desktop. +# +# If so, this detected value will be considered authoritative, and will be used +# to populate /etc/hostapd/hostapd.conf +# +# Finally, if IIAB does not detect a country code from your OS, the following +# fallback variable will be used instead: (to populate /etc/hostapd/hostapd.conf) host_country_code: US host_ssid: Internet in a Box host_wifi_mode: g host_channel: 6 -hostapd_secure: False # 2021-03-02 #2696 WiFi EAPOL fails if hotspot passwords, -hostapd_password: changeme # eg if firmware wifi_hotspot_capacity_rpi_fix: True -wifi_hotspot_capacity_rpi_fix: True # Restores the ability of RPi internal -# WiFi hotspots to service 30-to-32 client devices. Background explanation: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and PR #2472. -wifi_up_down: True # Creates a 2nd virtual WiFi adapter for upstream WiFi +hostapd_secure: False # 2021-03-02 WiFi EAPOL fails if hotspot passwords, +hostapd_password: changeme # espec if WiFi firmware patched below? #2696 + +# Raspberry Pi 3 B+ and 4 OS's don't allow more than ~4 students to use the +# internal WiFi hotspot. Increase this to 19 or 24 student WiFi devices (or +# 32 on older OS's from 2020) using EXACTLY 1 of the 5 lines below: +# +#rpi3bplus_rpi4_wifi_firmware: os # Use your OS's WiFi firmware e.g. 7.45.241 +#rpi3bplus_rpi4_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.234 +rpi3bplus_rpi4_wifi_firmware: 19 # SEE: github.com/iiab/iiab/issues/2853 +#rpi3bplus_rpi4_wifi_firmware: 24 # REQUIRES "wifi_up_down: False" BELOW! +#rpi3bplus_rpi4_wifi_firmware: 32 # UNRELIABLE (INTERMITTENT) with 2021+ OS's +# +# BACKGROUND: https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# +# Raspberry Pi Zero W and 3 OS's don't allow more than ~10 students to use the +# internal WiFi hotspot. Or try increasing this to 30 student WiFi devices: +# +rpizerow_rpi3_wifi_firmware: os # Use yr OS WiFi firmware e.g. 7.45.98 +#rpizerow_rpi3_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.98.118 +#rpizerow_rpi3_wifi_firmware: 30 # Or firmware 7.45.98.65 from 2018-09-28 + +wifi_up_down: True # AP+STA mode: Uses "ap0" WiFi adapter for upstream WiFi # (e.g. to Internet) in addition to downstream WiFi (e.g. classroom hotspot). # Set True if client machines should have "passthrough" access to WAN/Internet: @@ -77,7 +104,7 @@ wan_netmask: # wan_netmask: 255.255.255.0 wan_gateway: # wan_gateway: 192.168.1.254 # If nec wan_nameserver can override ISP-provided DNS servers via dnsmasq: # /etc/resolv.conf dictates which backend is used for the machine itself, so -# 127.0.0.1 means you get dnsmasq (so it works right away on RaspiOS) while +# 127.0.0.1 means you get dnsmasq (so it works right away on RasPiOS) while # 127.0.0.53 gives you systemd-networkd (so Ubuntu itself does NOT use this # dnsmasq-specified upstream DNS [e.g. wan_nameserver] but its LAN clients do!) wan_nameserver: # wan_nameserver: 192.168.1.254 or 8.8.8.8 or 1.1.1.1 @@ -97,34 +124,36 @@ ports_externally_visible: 3 # ssh + http-or-https + common IIAB services # # Or further customize your iptables firewall by editing: # /opt/iiab/iiab/roles/network/templates/gateway/iiab-gen-iptables -# And then run: cd /opt/iiab/iiab; ./iiab-network +# And then run: sudo iiab-network -# Enable AFTER installing IIAB! Then run "cd /opt/iiab/iiab; ./iiab-network" +# Enable AFTER installing IIAB! Then run: sudo iiab-network dns_jail_enabled: False # 1-PREP -# SSHD runs here & also below in 4-SERVER-OPTIONS -sshd_install: True # Required by OpenVPN +# OPENSSH-SERVER +sshd_install: True sshd_enabled: True # https://remote.it can help you remotely maintain an IIAB. +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/remoteit remoteit_install: True remoteit_enabled: False +# OPTION #1: Run 'sudo iiab-remoteit' later. OPTION #2: Set this now: +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 -# SECURITY WARNING: See http://wiki.laptop.org/go/IIAB/Security -openvpn_install: True -openvpn_enabled: False -# 2021-08-18 SSOT: Please set it here, no longer in /etc/iiab/openvpn_handle -openvpn_handle: MEDIUM-sized - Put Your Name Here +# SECURITY WARNING: https://wiki.iiab.io/go/Security +# New VPN replaced OpenVPN in Sept 2024: +tailscale_install: True +tailscale_enabled: False # Stub var, doesn't yet do anything! # IIAB-ADMIN runs here - see its vars near top of this file: # e.g. iiab_admin_user, iiab_admin_user_install, iiab_admin_can_sudo # dnsmasq is installed here -- configure LATER in 'network', after Stage 9. # (The full network stage runs after 9-LOCAL-ADDONS. Or manually run -# "cd /opt/iiab/iiab; sudo ./iiab-network"). Design under discussion: #2876 +# "sudo iiab-network"). Design under discussion: #2876 # Some prefer 512MB for Zero W, others prefer 2048MB or higher for RPi 3 and 4. # Please see recommendations at: https://itsfoss.com/swap-size/ @@ -143,13 +172,11 @@ pi_swap_file_size: 1024 # roles/nginx runs here (mandatory) # roles/www_base runs here (mandatory) -# SEE BELOW: nginx_high_php_limits, apache_allow_sudo +# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff # 4-SERVER-OPTIONS -# SSHD runs here & also above in 1-PREP - # DNS prep (named &/or dhcpd) used to run here. See dnsmasq in 1-PREP above. # Proxy Cache & basic site blocking using /etc/squid allowlists: (whitelists) @@ -165,11 +192,9 @@ bluetooth_install: True bluetooth_enabled: False bluetooth_term_enabled: False -# Show entire contents of USB sticks/drives (at http://box/usb) -iiab_usb_lib_show_all: True -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +usb_lib_writable_sticks: True # Common UNIX Printing System (CUPS) cups_install: False @@ -181,16 +206,18 @@ samba_enabled: False # roles/www_options HANDLES THE 3 VARS BELOW: -# For schools that use WordPress/Nextcloud/Moodle/PBX intensively: +# Set to True if intensively using Matomo/PBX/WordPress: nginx_high_php_limits: False -# WARNING: Enabling this might cause excess use of RAM/disk or other resources! -# roles/www_options & roles/moodle FORCE high limits if 'moodle_install: True' -# REGARDLESS: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... -# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L53-L133 +# SIMILARLY: 'moodle_install: True' and 'nextcloud_install: True' effectively +# force this, via roles/www_options & roles/moodle & roles/nextcloud +# WARNING: This might cause excess use of RAM/disk or other resources! +# WARNING: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... +# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml # ...ARE SUITABLE FOR YOUR HARDWARE, as saved in: /etc/php/<VERSION>/*/php.ini +# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf -# Make this False to disable http://box/common/services/power_off.php button: -apache_allow_sudo: True +# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php +allow_www_data_poweroff: False # Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info) nodocs: False @@ -204,10 +231,6 @@ nodocs: False # 6-GENERIC-APPS -# Simple, Self-Hosted Web Radio - from AzuraCast.com -azuracast_install: False -azuracast_enabled: False # This var is currently IGNORED. - # Gitea (lightweight self-hosted "GitHub") from https://gitea.io gitea_install: False gitea_enabled: False @@ -216,9 +239,9 @@ gitea_enabled: False jupyterhub_install: False jupyterhub_enabled: False -# Lokole (email for rural communities) from https://ascoderu.ca -lokole_install: False -lokole_enabled: False +# UNMAINTAINED: Lokole (email for rural communities) from https://ascoderu.ca +lokole_install: False # 2022-03-13: Python 3.9+ work +lokole_enabled: False # https://github.com/iiab/iiab/issues/3132 # Wikipedia's community editing platform - from MediaWiki.org mediawiki_install: False @@ -246,7 +269,7 @@ nextcloud_enabled: True # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # Uncomment the following line to end that: (might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 # If using WordPress intensively, set nginx_high_php_limits further above. wordpress_install: True @@ -256,13 +279,13 @@ wordpress_enabled: True # 7-EDU-APPS # KA Lite - SEE THE "Transmission" BITTORRENT DOWNLOADER FURTHER BELOW, TO INSTALL THOUSANDS OF VIDEOS -kalite_install: True -kalite_enabled: True +kalite_install: False +kalite_enabled: False # Successor to KA Lite, for offline-first teaching and learning - from learningequality.org -kolibri_install: False -kolibri_enabled: False -kolibri_language: en # ar,bg-bg,bn-bd,de,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,hi-in,it,km,ko,mr,my,nyn,pt-br,sw-tz,te,ur-pk,vi,yo,zh-hans +kolibri_install: True +kolibri_enabled: True +kolibri_language: en # ar,bg-bg,bn-bd,de,el,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,ha,hi-in,ht,id,it,ka,km,ko,mr,my,nyn,pt-br,pt-mz,sw-tz,te,uk,ur-pk,vi,yo,zh-hans # kiwix_install: True is REQUIRED, if you install IIAB's Admin Console kiwix_install: True @@ -271,7 +294,8 @@ kiwix_enabled: True # Warning: Moodle is a serious LMS, that takes a while to install moodle_install: False moodle_enabled: False -# If using Moodle intensively, set nginx_high_php_limits further above. +# FYI 'nginx_high_php_limits: True' (explained above) is mandated with Moodle, +# as auto-enacted by roles/www_options/tasks/php-settings.yml # Regional OSM vector maps use far less disk space than bitmap/raster versions. # Instructions: https://github.com/iiab/iiab/wiki/IIAB-Maps @@ -292,8 +316,9 @@ sugarizer_enabled: True # BitTorrent downloader for large Content Packs etc transmission_install: True transmission_enabled: True +transmission_compile_latest: False # A. UNCOMMENT LANGUAGE(S) TO DOWNLOAD KA Lite VIDEOS TO /library/transmission -# using http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# using https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ transmission_kalite_languages: #- english #- french @@ -314,6 +339,11 @@ transmission_kalite_languages: awstats_install: True awstats_enabled: True +# Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership. +matomo_install: True +matomo_enabled: True +# If using Matomo intensively, investigate nginx_high_php_limits further above. + # Process supervision tool - from https://mmonit.com/monit/ # 2020-09-22 WARNING: both vars are IGNORED on Debian 10 due to: iiab/iiab#1849 monit_install: False @@ -335,6 +365,10 @@ vnstat_enabled: False # 9-LOCAL-ADDONS +# Simple, Self-Hosted Web Radio - from AzuraCast.com +azuracast_install: False +azuracast_enabled: False # This var is currently IGNORED. + # Python-based Captive Portal, that @m-anish & @jvonau experimented with in # July 2018 (https://github.com/iiab/iiab/pull/870) and that @georgejhunt # extensively later refined (PRs #1179, #1300, #1327, #2070). @@ -378,11 +412,12 @@ calibre_web_path: calibre #NEEDS WORK: https://github.com/iiab/iiab/issues/529 # Avoid URL collisions w/ calibreweb_url1, calibreweb_url2, calibreweb_url3 below! # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# REQUIRES PHP 7.4 e.g. Ubuntu 20.04, Debian 11 -- RaspiOS 11 might also work. -# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#readme # If using PBX intensively, investigate nginx_high_php_limits further above. pbx_install: False pbx_enabled: False -pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +asterisk_rpi_patch: False asterisk_chan_dongle: False diff --git a/vars/local_vars_none.yml b/vars/local_vars_none.yml new file mode 100644 index 000000000..1e5c03ead --- /dev/null +++ b/vars/local_vars_none.yml @@ -0,0 +1,15 @@ +# turn off defaults +remoteit_install: False +tailscale_install: False +kolibri_install: False +kolibri_enabled: False +kiwix_install: False +kiwix_enabled: False +osm_vector_maps_install: False +awstats_install: False +awstats_enabled: False +matomo_install: False +matomo_enabled: False +captiveportal_install: False +calibreweb_install: False +calibreweb_enabled: False diff --git a/vars/local_vars_small.yml b/vars/local_vars_small.yml index ffba2d848..b17fcc9ae 100644 --- a/vars/local_vars_small.yml +++ b/vars/local_vars_small.yml @@ -1,7 +1,7 @@ # This is local_vars_small.yml -- copy it to /etc/iiab/local_vars.yml then... # modify variables below, to override /opt/iiab/iiab/vars/default_vars.yml -# PLZ READ http://wiki.laptop.org/go/IIAB/local_vars.yml AND http://FAQ.IIAB.IO +# READ "What is local_vars.yml and how do I customize it?" AT http://FAQ.IIAB.IO # Orig Idea: branch github.com/xsce/xsce-local for your deployment/community # IIAB does NOT currently support uninstalling apps! So: if any IIAB app is @@ -54,17 +54,44 @@ iiab_domain: lan # YOU'LL PREVENT OLDER LAPTOPS/PHONES/TABLETS (WHICH REQUIRE 2.4 GHz) FROM # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. # -# Raspberry Pi OS requires Wi-Fi country since March 2018. Please set it here: +# Raspberry Pi OS requires WiFi country since March 2018. +# +# If you're running Raspberry Pi OS, you may have already set the country code +# in /etc/wpa_supplicant/wpa_supplicant.conf e.g. if you ran raspi-config or used +# the Wi-Fi widget in the top-right of its graphical desktop. +# +# If so, this detected value will be considered authoritative, and will be used +# to populate /etc/hostapd/hostapd.conf +# +# Finally, if IIAB does not detect a country code from your OS, the following +# fallback variable will be used instead: (to populate /etc/hostapd/hostapd.conf) host_country_code: US host_ssid: Internet in a Box host_wifi_mode: g host_channel: 6 -hostapd_secure: False # 2021-03-02 #2696 WiFi EAPOL fails if hotspot passwords, -hostapd_password: changeme # eg if firmware wifi_hotspot_capacity_rpi_fix: True -wifi_hotspot_capacity_rpi_fix: True # Restores the ability of RPi internal -# WiFi hotspots to service 30-to-32 client devices. Background explanation: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and PR #2472. -wifi_up_down: True # Creates a 2nd virtual WiFi adapter for upstream WiFi +hostapd_secure: False # 2021-03-02 WiFi EAPOL fails if hotspot passwords, +hostapd_password: changeme # espec if WiFi firmware patched below? #2696 + +# Raspberry Pi 3 B+ and 4 OS's don't allow more than ~4 students to use the +# internal WiFi hotspot. Increase this to 19 or 24 student WiFi devices (or +# 32 on older OS's from 2020) using EXACTLY 1 of the 5 lines below: +# +#rpi3bplus_rpi4_wifi_firmware: os # Use your OS's WiFi firmware e.g. 7.45.241 +#rpi3bplus_rpi4_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.234 +rpi3bplus_rpi4_wifi_firmware: 19 # SEE: github.com/iiab/iiab/issues/2853 +#rpi3bplus_rpi4_wifi_firmware: 24 # REQUIRES "wifi_up_down: False" BELOW! +#rpi3bplus_rpi4_wifi_firmware: 32 # UNRELIABLE (INTERMITTENT) with 2021+ OS's +# +# BACKGROUND: https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# +# Raspberry Pi Zero W and 3 OS's don't allow more than ~10 students to use the +# internal WiFi hotspot. Or try increasing this to 30 student WiFi devices: +# +rpizerow_rpi3_wifi_firmware: os # Use yr OS WiFi firmware e.g. 7.45.98 +#rpizerow_rpi3_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.98.118 +#rpizerow_rpi3_wifi_firmware: 30 # Or firmware 7.45.98.65 from 2018-09-28 + +wifi_up_down: True # AP+STA mode: Uses "ap0" WiFi adapter for upstream WiFi # (e.g. to Internet) in addition to downstream WiFi (e.g. classroom hotspot). # Set True if client machines should have "passthrough" access to WAN/Internet: @@ -77,7 +104,7 @@ wan_netmask: # wan_netmask: 255.255.255.0 wan_gateway: # wan_gateway: 192.168.1.254 # If nec wan_nameserver can override ISP-provided DNS servers via dnsmasq: # /etc/resolv.conf dictates which backend is used for the machine itself, so -# 127.0.0.1 means you get dnsmasq (so it works right away on RaspiOS) while +# 127.0.0.1 means you get dnsmasq (so it works right away on RasPiOS) while # 127.0.0.53 gives you systemd-networkd (so Ubuntu itself does NOT use this # dnsmasq-specified upstream DNS [e.g. wan_nameserver] but its LAN clients do!) wan_nameserver: # wan_nameserver: 192.168.1.254 or 8.8.8.8 or 1.1.1.1 @@ -97,34 +124,36 @@ ports_externally_visible: 3 # ssh + http-or-https + common IIAB services # # Or further customize your iptables firewall by editing: # /opt/iiab/iiab/roles/network/templates/gateway/iiab-gen-iptables -# And then run: cd /opt/iiab/iiab; ./iiab-network +# And then run: sudo iiab-network -# Enable AFTER installing IIAB! Then run "cd /opt/iiab/iiab; ./iiab-network" +# Enable AFTER installing IIAB! Then run: sudo iiab-network dns_jail_enabled: False # 1-PREP -# SSHD runs here & also below in 4-SERVER-OPTIONS -sshd_install: True # Required by OpenVPN +# OPENSSH-SERVER +sshd_install: True sshd_enabled: True # https://remote.it can help you remotely maintain an IIAB. +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/remoteit remoteit_install: True remoteit_enabled: False +# OPTION #1: Run 'sudo iiab-remoteit' later. OPTION #2: Set this now: +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 -# SECURITY WARNING: See http://wiki.laptop.org/go/IIAB/Security -openvpn_install: True -openvpn_enabled: False -# 2021-08-18 SSOT: Please set it here, no longer in /etc/iiab/openvpn_handle -openvpn_handle: SMALL - Put Your Name Here +# SECURITY WARNING: https://wiki.iiab.io/go/Security +# New VPN replaced OpenVPN in Sept 2024: +tailscale_install: True +tailscale_enabled: False # Stub var, doesn't yet do anything! # IIAB-ADMIN runs here - see its vars near top of this file: # e.g. iiab_admin_user, iiab_admin_user_install, iiab_admin_can_sudo # dnsmasq is installed here -- configure LATER in 'network', after Stage 9. # (The full network stage runs after 9-LOCAL-ADDONS. Or manually run -# "cd /opt/iiab/iiab; sudo ./iiab-network"). Design under discussion: #2876 +# "sudo iiab-network"). Design under discussion: #2876 # Some prefer 512MB for Zero W, others prefer 2048MB or higher for RPi 3 and 4. # Please see recommendations at: https://itsfoss.com/swap-size/ @@ -143,13 +172,11 @@ pi_swap_file_size: 1024 # roles/nginx runs here (mandatory) # roles/www_base runs here (mandatory) -# SEE BELOW: nginx_high_php_limits, apache_allow_sudo +# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff # 4-SERVER-OPTIONS -# SSHD runs here & also above in 1-PREP - # DNS prep (named &/or dhcpd) used to run here. See dnsmasq in 1-PREP above. # Proxy Cache & basic site blocking using /etc/squid allowlists: (whitelists) @@ -165,11 +192,9 @@ bluetooth_install: True bluetooth_enabled: False bluetooth_term_enabled: False -# Show entire contents of USB sticks/drives (at http://box/usb) -iiab_usb_lib_show_all: True -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +usb_lib_writable_sticks: True # Common UNIX Printing System (CUPS) cups_install: False @@ -181,16 +206,18 @@ samba_enabled: False # roles/www_options HANDLES THE 3 VARS BELOW: -# For schools that use WordPress/Nextcloud/Moodle/PBX intensively: +# Set to True if intensively using Matomo/PBX/WordPress: nginx_high_php_limits: False -# WARNING: Enabling this might cause excess use of RAM/disk or other resources! -# roles/www_options & roles/moodle FORCE high limits if 'moodle_install: True' -# REGARDLESS: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... -# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L53-L133 +# SIMILARLY: 'moodle_install: True' and 'nextcloud_install: True' effectively +# force this, via roles/www_options & roles/moodle & roles/nextcloud +# WARNING: This might cause excess use of RAM/disk or other resources! +# WARNING: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... +# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml # ...ARE SUITABLE FOR YOUR HARDWARE, as saved in: /etc/php/<VERSION>/*/php.ini +# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf -# Make this False to disable http://box/common/services/power_off.php button: -apache_allow_sudo: True +# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php +allow_www_data_poweroff: False # Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info) nodocs: False @@ -204,10 +231,6 @@ nodocs: False # 6-GENERIC-APPS -# Simple, Self-Hosted Web Radio - from AzuraCast.com -azuracast_install: False -azuracast_enabled: False # This var is currently IGNORED. - # Gitea (lightweight self-hosted "GitHub") from https://gitea.io gitea_install: False gitea_enabled: False @@ -216,9 +239,9 @@ gitea_enabled: False jupyterhub_install: False jupyterhub_enabled: False -# Lokole (email for rural communities) from https://ascoderu.ca -lokole_install: False -lokole_enabled: False +# UNMAINTAINED: Lokole (email for rural communities) from https://ascoderu.ca +lokole_install: False # 2022-03-13: Python 3.9+ work +lokole_enabled: False # https://github.com/iiab/iiab/issues/3132 # Wikipedia's community editing platform - from MediaWiki.org mediawiki_install: False @@ -246,7 +269,7 @@ nextcloud_enabled: False # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # Uncomment the following line to end that: (might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 # If using WordPress intensively, set nginx_high_php_limits further above. wordpress_install: False @@ -256,22 +279,23 @@ wordpress_enabled: False # 7-EDU-APPS # KA Lite - SEE THE "Transmission" BITTORRENT DOWNLOADER FURTHER BELOW, TO INSTALL THOUSANDS OF VIDEOS -kalite_install: True -kalite_enabled: True +kalite_install: False +kalite_enabled: False # Successor to KA Lite, for offline-first teaching and learning - from learningequality.org -kolibri_install: False -kolibri_enabled: False -kolibri_language: en # ar,bg-bg,bn-bd,de,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,hi-in,it,km,ko,mr,my,nyn,pt-br,sw-tz,te,ur-pk,vi,yo,zh-hans +kolibri_install: True +kolibri_enabled: True +kolibri_language: en # ar,bg-bg,bn-bd,de,el,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,ha,hi-in,ht,id,it,ka,km,ko,mr,my,nyn,pt-br,pt-mz,sw-tz,te,uk,ur-pk,vi,yo,zh-hans # kiwix_install: True is REQUIRED, if you install IIAB's Admin Console kiwix_install: True kiwix_enabled: True -# Warning: Moodle is a serious LMS, that takes a while to install. +# Warning: Moodle is a serious LMS, that takes a while to install moodle_install: False moodle_enabled: False -# If using Moodle intensively, set nginx_high_php_limits further above. +# FYI 'nginx_high_php_limits: True' (explained above) is mandated with Moodle, +# as auto-enacted by roles/www_options/tasks/php-settings.yml # Regional OSM vector maps use far less disk space than bitmap/raster versions. # Instructions: https://github.com/iiab/iiab/wiki/IIAB-Maps @@ -292,8 +316,9 @@ sugarizer_enabled: False # BitTorrent downloader for large Content Packs etc transmission_install: False transmission_enabled: False +transmission_compile_latest: False # A. UNCOMMENT LANGUAGE(S) TO DOWNLOAD KA Lite VIDEOS TO /library/transmission -# using http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# using https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ transmission_kalite_languages: #- english #- french @@ -314,6 +339,11 @@ transmission_kalite_languages: awstats_install: True awstats_enabled: True +# Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership. +matomo_install: True +matomo_enabled: True +# If using Matomo intensively, investigate nginx_high_php_limits further above. + # Process supervision tool - from https://mmonit.com/monit/ # 2020-09-22 WARNING: both vars are IGNORED on Debian 10 due to: iiab/iiab#1849 monit_install: False @@ -335,6 +365,10 @@ vnstat_enabled: False # 9-LOCAL-ADDONS +# Simple, Self-Hosted Web Radio - from AzuraCast.com +azuracast_install: False +azuracast_enabled: False # This var is currently IGNORED. + # Python-based Captive Portal, that @m-anish & @jvonau experimented with in # July 2018 (https://github.com/iiab/iiab/pull/870) and that @georgejhunt # extensively later refined (PRs #1179, #1300, #1327, #2070). @@ -354,8 +388,8 @@ minetest_install: False minetest_enabled: False # Calibre-Web E-Book Library -- Alternative to Calibre, offers a clean/modern UX -calibreweb_install: False -calibreweb_enabled: False +calibreweb_install: True +calibreweb_enabled: True calibreweb_port: 8083 # PORT VARIABLE HAS NO EFFECT (as of January 2019) # http://box/books works. Add {box/libros, box/livres, box/livros, box/liv} etc? calibreweb_url1: /books # For SHORT URL http://box/books (English) @@ -378,11 +412,12 @@ calibre_web_path: calibre #NEEDS WORK: https://github.com/iiab/iiab/issues/529 # Avoid URL collisions w/ calibreweb_url1, calibreweb_url2, calibreweb_url3 below! # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# REQUIRES PHP 7.4 e.g. Ubuntu 20.04, Debian 11 -- RaspiOS 11 might also work. -# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#readme # If using PBX intensively, investigate nginx_high_php_limits further above. pbx_install: False pbx_enabled: False -pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +asterisk_rpi_patch: False asterisk_chan_dongle: False diff --git a/vars/local_vars_unittest.yml b/vars/local_vars_unittest.yml index 02e928c90..840d0d9b8 100644 --- a/vars/local_vars_unittest.yml +++ b/vars/local_vars_unittest.yml @@ -1,7 +1,7 @@ # This is local_vars_unittest.yml -- copy it to /etc/iiab/local_vars.yml then... # modify variables below, to override /opt/iiab/iiab/vars/default_vars.yml -# PLZ READ http://wiki.laptop.org/go/IIAB/local_vars.yml AND http://FAQ.IIAB.IO +# READ "What is local_vars.yml and how do I customize it?" AT http://FAQ.IIAB.IO # Orig Idea: branch github.com/xsce/xsce-local for your deployment/community # IIAB does NOT currently support uninstalling apps! So: if any IIAB app is @@ -12,8 +12,14 @@ # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. +# We SKIP roles/network, for FASTER UNIT TESTING! (so IF an internal hotspot +# is later desired, change these two lines to 'True', then run 'iiab-network') +network_install: False +network_enabled: False + + # Ansible's default timeout for "get_url:" downloads (10 seconds) often fails -download_timeout: 200 +download_timeout: 100 # Real-time clock: set RTC chip family here. Future auto-detection plausible? rtc_id: none # Or ds3231 ? @@ -54,17 +60,44 @@ iiab_domain: lan # YOU'LL PREVENT OLDER LAPTOPS/PHONES/TABLETS (WHICH REQUIRE 2.4 GHz) FROM # CONNECTING TO YOUR IIAB'S INTERNAL HOTSPOT. See "wifi_up_down: True" below. # -# Raspberry Pi OS requires Wi-Fi country since March 2018. Please set it here: +# Raspberry Pi OS requires WiFi country since March 2018. +# +# If you're running Raspberry Pi OS, you may have already set the country code +# in /etc/wpa_supplicant/wpa_supplicant.conf e.g. if you ran raspi-config or used +# the Wi-Fi widget in the top-right of its graphical desktop. +# +# If so, this detected value will be considered authoritative, and will be used +# to populate /etc/hostapd/hostapd.conf +# +# Finally, if IIAB does not detect a country code from your OS, the following +# fallback variable will be used instead: (to populate /etc/hostapd/hostapd.conf) host_country_code: US host_ssid: unittest host_wifi_mode: g host_channel: 6 -hostapd_secure: False # 2021-03-02 #2696 WiFi EAPOL fails if hotspot passwords, -hostapd_password: changeme # eg if firmware wifi_hotspot_capacity_rpi_fix: True -wifi_hotspot_capacity_rpi_fix: True # Restores the ability of RPi internal -# WiFi hotspots to service 30-to-32 client devices. Background explanation: -# https://github.com/iiab/iiab/issues/823#issuecomment-662285202 and PR #2472. -wifi_up_down: True # Creates a 2nd virtual WiFi adapter for upstream WiFi +hostapd_secure: False # 2021-03-02 WiFi EAPOL fails if hotspot passwords, +hostapd_password: changeme # espec if WiFi firmware patched below? #2696 + +# Raspberry Pi 3 B+ and 4 OS's don't allow more than ~4 students to use the +# internal WiFi hotspot. Increase this to 19 or 24 student WiFi devices (or +# 32 on older OS's from 2020) using EXACTLY 1 of the 5 lines below: +# +#rpi3bplus_rpi4_wifi_firmware: os # Use your OS's WiFi firmware e.g. 7.45.241 +#rpi3bplus_rpi4_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.234 +rpi3bplus_rpi4_wifi_firmware: 19 # SEE: github.com/iiab/iiab/issues/2853 +#rpi3bplus_rpi4_wifi_firmware: 24 # REQUIRES "wifi_up_down: False" BELOW! +#rpi3bplus_rpi4_wifi_firmware: 32 # UNRELIABLE (INTERMITTENT) with 2021+ OS's +# +# BACKGROUND: https://github.com/iiab/iiab/issues/823#issuecomment-662285202 +# +# Raspberry Pi Zero W and 3 OS's don't allow more than ~10 students to use the +# internal WiFi hotspot. Or try increasing this to 30 student WiFi devices: +# +rpizerow_rpi3_wifi_firmware: os # Use yr OS WiFi firmware e.g. 7.45.98 +#rpizerow_rpi3_wifi_firmware: ub # Ubuntu-only OLD firmware e.g. 7.45.98.118 +#rpizerow_rpi3_wifi_firmware: 30 # Or firmware 7.45.98.65 from 2018-09-28 + +wifi_up_down: True # AP+STA mode: Uses "ap0" WiFi adapter for upstream WiFi # (e.g. to Internet) in addition to downstream WiFi (e.g. classroom hotspot). # Set True if client machines should have "passthrough" access to WAN/Internet: @@ -77,7 +110,7 @@ wan_netmask: # wan_netmask: 255.255.255.0 wan_gateway: # wan_gateway: 192.168.1.254 # If nec wan_nameserver can override ISP-provided DNS servers via dnsmasq: # /etc/resolv.conf dictates which backend is used for the machine itself, so -# 127.0.0.1 means you get dnsmasq (so it works right away on RaspiOS) while +# 127.0.0.1 means you get dnsmasq (so it works right away on RasPiOS) while # 127.0.0.53 gives you systemd-networkd (so Ubuntu itself does NOT use this # dnsmasq-specified upstream DNS [e.g. wan_nameserver] but its LAN clients do!) wan_nameserver: # wan_nameserver: 192.168.1.254 or 8.8.8.8 or 1.1.1.1 @@ -97,34 +130,36 @@ ports_externally_visible: 3 # ssh + http-or-https + common IIAB services # # Or further customize your iptables firewall by editing: # /opt/iiab/iiab/roles/network/templates/gateway/iiab-gen-iptables -# And then run: cd /opt/iiab/iiab; ./iiab-network +# And then run: sudo iiab-network -# Enable AFTER installing IIAB! Then run "cd /opt/iiab/iiab; ./iiab-network" +# Enable AFTER installing IIAB! Then run: sudo iiab-network dns_jail_enabled: False # 1-PREP -# SSHD runs here & also below in 4-SERVER-OPTIONS -sshd_install: True # Required by OpenVPN +# OPENSSH-SERVER +sshd_install: True sshd_enabled: True # https://remote.it can help you remotely maintain an IIAB. +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/remoteit remoteit_install: True remoteit_enabled: False +# OPTION #1: Run 'sudo iiab-remoteit' later. OPTION #2: Set this now: +# remoteit_license_key: 592AA9BB-XXXX-YYYY-ZZZZ-6E27654C3DF6 -# SECURITY WARNING: See http://wiki.laptop.org/go/IIAB/Security -openvpn_install: True -openvpn_enabled: True -# 2021-08-18 SSOT: Please set it here, no longer in /etc/iiab/openvpn_handle -openvpn_handle: UNITTEST - Put Your Name Here +# SECURITY WARNING: https://wiki.iiab.io/go/Security +# New VPN replaced OpenVPN in Sept 2024: +tailscale_install: True +tailscale_enabled: False # Stub var, doesn't yet do anything! # IIAB-ADMIN runs here - see its vars near top of this file: # e.g. iiab_admin_user, iiab_admin_user_install, iiab_admin_can_sudo # dnsmasq is installed here -- configure LATER in 'network', after Stage 9. # (The full network stage runs after 9-LOCAL-ADDONS. Or manually run -# "cd /opt/iiab/iiab; sudo ./iiab-network"). Design under discussion: #2876 +# "sudo iiab-network"). Design under discussion: #2876 # Some prefer 512MB for Zero W, others prefer 2048MB or higher for RPi 3 and 4. # Please see recommendations at: https://itsfoss.com/swap-size/ @@ -143,13 +178,11 @@ pi_swap_file_size: 1024 # roles/nginx runs here (mandatory) # roles/www_base runs here (mandatory) -# SEE BELOW: nginx_high_php_limits, apache_allow_sudo +# SEE BELOW: nginx_high_php_limits, allow_www_data_poweroff # 4-SERVER-OPTIONS -# SSHD runs here & also above in 1-PREP - # DNS prep (named &/or dhcpd) used to run here. See dnsmasq in 1-PREP above. # Proxy Cache & basic site blocking using /etc/squid allowlists: (whitelists) @@ -165,11 +198,9 @@ bluetooth_install: False bluetooth_enabled: False bluetooth_term_enabled: False -# Show entire contents of USB sticks/drives (at http://box/usb) -iiab_usb_lib_show_all: True -# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf so -# Kolibri can export & import channels to USB sticks/drive: -usb_lib_umask0000_for_kolibri: True +# Set umask=0000 for VFAT, NTFS and exFAT in /etc/usbmount/usbmount.conf for +# Kolibri exports, and student uploads to teacher's USB stick (http://box/usb) +usb_lib_writable_sticks: True # Common UNIX Printing System (CUPS) cups_install: False @@ -181,19 +212,21 @@ samba_enabled: False # roles/www_options HANDLES THE 3 VARS BELOW: -# For schools that use WordPress/Nextcloud/Moodle/PBX intensively: +# Set to True if intensively using Matomo/PBX/WordPress: nginx_high_php_limits: False -# WARNING: Enabling this might cause excess use of RAM/disk or other resources! -# roles/www_options & roles/moodle FORCE high limits if 'moodle_install: True' -# REGARDLESS: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... -# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/main.yml#L53-L133 +# SIMILARLY: 'moodle_install: True' and 'nextcloud_install: True' effectively +# force this, via roles/www_options & roles/moodle & roles/nextcloud +# WARNING: This might cause excess use of RAM/disk or other resources! +# WARNING: AFTER INSTALLING IIAB, PLEASE VERIFY THESE 6 SETTINGS... +# https://github.com/iiab/iiab/blob/master/roles/www_options/tasks/php-settings.yml # ...ARE SUITABLE FOR YOUR HARDWARE, as saved in: /etc/php/<VERSION>/*/php.ini +# ALSO: ADJUST "client_max_body_size 10000M;" AS NEC, IN: /etc/nginx/server.conf -# Make this False to disable http://box/common/services/power_off.php button: -apache_allow_sudo: True +# Make this True to enable http://box/js-menu/menu-files/services/power_off.php and set-server-time.php +allow_www_data_poweroff: False # Toggle iiab-refresh-wiki-docs scraping for offline docs (http://box/info) -nodocs: False +nodocs: True # 5-XO-SERVICES @@ -204,10 +237,6 @@ nodocs: False # 6-GENERIC-APPS -# Simple, Self-Hosted Web Radio - from AzuraCast.com -azuracast_install: False -azuracast_enabled: False # This var is currently IGNORED. - # Gitea (lightweight self-hosted "GitHub") from https://gitea.io gitea_install: False gitea_enabled: False @@ -216,9 +245,9 @@ gitea_enabled: False jupyterhub_install: False jupyterhub_enabled: False -# Lokole (email for rural communities) from https://ascoderu.ca -lokole_install: False -lokole_enabled: False +# UNMAINTAINED: Lokole (email for rural communities) from https://ascoderu.ca +lokole_install: False # 2022-03-13: Python 3.9+ work +lokole_enabled: False # https://github.com/iiab/iiab/issues/3132 # Wikipedia's community editing platform - from MediaWiki.org mediawiki_install: False @@ -246,7 +275,7 @@ nextcloud_enabled: False # 2020-01-07: If installing IIAB often, download.nextcloud.com may throttle # you to ~100 kbit/sec, delaying your IIAB install by an hour or more (#2112). # Uncomment the following line to end that: (might install an older Nextcloud!) -# nextcloud_dl_url: http://d.iiab.io/packages/latest.tar.bz2 +# nextcloud_dl_url: https://d.iiab.io/packages/latest.tar.bz2 # If using WordPress intensively, set nginx_high_php_limits further above. wordpress_install: False @@ -262,16 +291,17 @@ kalite_enabled: False # Successor to KA Lite, for offline-first teaching and learning - from learningequality.org kolibri_install: False kolibri_enabled: False -kolibri_language: en # ar,bg-bg,bn-bd,de,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,hi-in,it,km,ko,mr,my,nyn,pt-br,sw-tz,te,ur-pk,vi,yo,zh-hans +kolibri_language: en # ar,bg-bg,bn-bd,de,el,en,es-es,es-419,fa,fr-fr,ff-cm,gu-in,ha,hi-in,ht,id,it,ka,km,ko,mr,my,nyn,pt-br,pt-mz,sw-tz,te,uk,ur-pk,vi,yo,zh-hans # kiwix_install: True is REQUIRED, if you install IIAB's Admin Console kiwix_install: False kiwix_enabled: False -# Warning: Moodle is a serious LMS, that takes a while to install. +# Warning: Moodle is a serious LMS, that takes a while to install moodle_install: False moodle_enabled: False -# If using Moodle intensively, set nginx_high_php_limits further above. +# FYI 'nginx_high_php_limits: True' (explained above) is mandated with Moodle, +# as auto-enacted by roles/www_options/tasks/php-settings.yml # Regional OSM vector maps use far less disk space than bitmap/raster versions. # Instructions: https://github.com/iiab/iiab/wiki/IIAB-Maps @@ -292,8 +322,9 @@ sugarizer_enabled: False # BitTorrent downloader for large Content Packs etc transmission_install: False transmission_enabled: False +transmission_compile_latest: False # A. UNCOMMENT LANGUAGE(S) TO DOWNLOAD KA Lite VIDEOS TO /library/transmission -# using http://pantry.learningequality.org/downloads/ka-lite/0.17/content/ +# using https://pantry.learningequality.org/downloads/ka-lite/0.17/content/ transmission_kalite_languages: #- english #- french @@ -314,6 +345,11 @@ transmission_kalite_languages: awstats_install: False awstats_enabled: False +# Matomo is a web analytics alternative to Google Analytics, emphasizing privacy and data ownership. +matomo_install: False +matomo_enabled: False +# If using Matomo intensively, investigate nginx_high_php_limits further above. + # Process supervision tool - from https://mmonit.com/monit/ # 2020-09-22 WARNING: both vars are IGNORED on Debian 10 due to: iiab/iiab#1849 monit_install: False @@ -335,6 +371,10 @@ vnstat_enabled: False # 9-LOCAL-ADDONS +# Simple, Self-Hosted Web Radio - from AzuraCast.com +azuracast_install: False +azuracast_enabled: False # This var is currently IGNORED. + # Python-based Captive Portal, that @m-anish & @jvonau experimented with in # July 2018 (https://github.com/iiab/iiab/pull/870) and that @georgejhunt # extensively later refined (PRs #1179, #1300, #1327, #2070). @@ -378,11 +418,12 @@ calibre_web_path: calibre #NEEDS WORK: https://github.com/iiab/iiab/issues/529 # Avoid URL collisions w/ calibreweb_url1, calibreweb_url2, calibreweb_url3 below! # A full-featured PBX (for rural telephony, etc) based on Asterisk and FreePBX. -# REQUIRES PHP 7.4 e.g. Ubuntu 20.04, Debian 11 -- RaspiOS 11 might also work. -# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#pbx-readme +# INSTRUCTIONS: https://github.com/iiab/iiab/tree/master/roles/pbx#readme # If using PBX intensively, investigate nginx_high_php_limits further above. pbx_install: False pbx_enabled: False -pbx_use_apache: True # 2021-08-17: Set either to 'False' if nec -- please +pbx_use_apache: False # 2023-04-03: Set to 'True' if nec -- please also pbx_use_nginx: True # read github.com/iiab/iiab/issues/2914 & #2916, THX! +# 2023-04-03: For EXPERIMENTAL testing on Raspberry Pi... (#3489, PR #3523) +asterisk_rpi_patch: False asterisk_chan_dongle: False diff --git a/vars/raspbian-10.yml b/vars/raspbian-10.yml.unused similarity index 87% rename from vars/raspbian-10.yml rename to vars/raspbian-10.yml.unused index b2f3298d8..ed6b61e0f 100644 --- a/vars/raspbian-10.yml +++ b/vars/raspbian-10.yml.unused @@ -35,6 +35,6 @@ minetest_server_bin: /library/games/minetest/bin/minetestserver minetest_working_dir: /library/games/minetest minetest_game_dir: /library/games/minetest/games/minetest_game minetest_rpi_src_tar: minetest.5.1.1.tar.gz -#minetest_rpi_src_url: "http://www.nathansalapat.com/downloads/{{ minetest_rpi_src_tar }}" -minetest_rpi_src_url: "http://d.iiab.io/packages/{{ minetest_rpi_src_tar }}" +#minetest_rpi_src_url: "https://www.nathansalapat.com/downloads/{{ minetest_rpi_src_tar }}" +minetest_rpi_src_url: "{{ iiab_download_url }}/{{ minetest_rpi_src_tar }}" minetest_rpi_src_untarred: Minetest diff --git a/vars/raspbian-11.yml b/vars/raspbian-11.yml deleted file mode 100644 index d1d1d8672..000000000 --- a/vars/raspbian-11.yml +++ /dev/null @@ -1,40 +0,0 @@ -# Every is_<OS> var is initially set to 'False' at the bottom of -# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: -is_debuntu: True -is_debian: True # Opposite of is_ubuntu for now -is_debian_11: True -is_raspbian: True -is_raspbian_11: True - -# 2019-03-23: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dns_user: bind -dhcp_service: isc-dhcp-server - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_conf_dir: apache2/sites-available -apache_user: www-data -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: ssh -sshd_service: ssh -php_version: 7.4 -postgresql_version: 13 -systemd_location: /lib/systemd/system -python_ver: 3.9 - -# Minetest for RPi -minetest_server_bin: /library/games/minetest/bin/minetestserver -minetest_working_dir: /library/games/minetest -minetest_game_dir: /library/games/minetest/games/minetest_game -minetest_rpi_src_tar: minetest.5.1.1.tar.gz -#minetest_rpi_src_url: "http://www.nathansalapat.com/downloads/{{ minetest_rpi_src_tar }}" -minetest_rpi_src_url: "http://d.iiab.io/packages/{{ minetest_rpi_src_tar }}" -minetest_rpi_src_untarred: Minetest diff --git a/vars/raspbian-11.yml.unused b/vars/raspbian-11.yml.unused new file mode 100644 index 000000000..ff03dd183 --- /dev/null +++ b/vars/raspbian-11.yml.unused @@ -0,0 +1,22 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_debian: True # Opposite of is_ubuntu for now +is_debian_11: True +is_raspbian: True +is_raspbian_11: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: ssh +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "7.4" +# postgresql_version: 13 +# python_version: "3.9" diff --git a/vars/raspbian-12.yml b/vars/raspbian-12.yml new file mode 100644 index 000000000..53858b6af --- /dev/null +++ b/vars/raspbian-12.yml @@ -0,0 +1,7 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_debian: True # Opposite of is_ubuntu for now +is_debian_12: True +is_raspbian: True +is_raspbian_12: True diff --git a/vars/raspbian-13.yml b/vars/raspbian-13.yml new file mode 100644 index 000000000..74c906488 --- /dev/null +++ b/vars/raspbian-13.yml @@ -0,0 +1,7 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_debian: True # Opposite of is_ubuntu for now +is_debian_13: True +is_raspbian: True +is_raspbian_13: True diff --git a/vars/raspbian-8.yml b/vars/raspbian-8.yml.unused similarity index 100% rename from vars/raspbian-8.yml rename to vars/raspbian-8.yml.unused diff --git a/vars/raspbian-9.yml b/vars/raspbian-9.yml.unused similarity index 92% rename from vars/raspbian-9.yml rename to vars/raspbian-9.yml.unused index abf0acbd2..6d955a00c 100644 --- a/vars/raspbian-9.yml +++ b/vars/raspbian-9.yml.unused @@ -31,5 +31,5 @@ systemd_location: /lib/systemd/system minetest_server_bin: /library/games/minetest/bin/minetestserver minetest_working_dir: /library/games/minetest minetest_game_dir: /library/games/minetest/games/minetest_game -minetest_rpi_src_url: http://www.nathansalapat.com/downloads/0.4.17.1.tar.gz +minetest_rpi_src_url: https://www.nathansalapat.com/downloads/0.4.17.1.tar.gz minetest_rpi_src: minetest-0.4.17.1.tar.gz diff --git a/vars/ubuntu-2004.yml b/vars/ubuntu-2004.yml deleted file mode 100644 index 7e7e1a2ad..000000000 --- a/vars/ubuntu-2004.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Every is_<OS> var is initially set to 'False' at the bottom of -# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: -is_debuntu: True -is_ubuntu: True # Opposite of is_debian for now -is_ubuntu_2004: True - -# 2019-03-23: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dns_user: bind -dhcp_service: isc-dhcp-server - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_user: www-data -apache_conf_dir: apache2/sites-available -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 7.4 -postgresql_version: 12 -systemd_location: /lib/systemd/system -python_ver: 3.8 diff --git a/vars/ubuntu-2004.yml.unused b/vars/ubuntu-2004.yml.unused new file mode 100644 index 000000000..bdae9367d --- /dev/null +++ b/vars/ubuntu-2004.yml.unused @@ -0,0 +1,20 @@ +# Every is_<OS> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2004: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "7.4" +# postgresql_version: 12 +# python_ver: "3.8" diff --git a/vars/ubuntu-2104.yml b/vars/ubuntu-2104.yml.unused similarity index 100% rename from vars/ubuntu-2104.yml rename to vars/ubuntu-2104.yml.unused diff --git a/vars/ubuntu-2110.yml b/vars/ubuntu-2110.yml.unused similarity index 100% rename from vars/ubuntu-2110.yml rename to vars/ubuntu-2110.yml.unused diff --git a/vars/ubuntu-2204.yml b/vars/ubuntu-2204.yml index 45228126e..e619ed95a 100644 --- a/vars/ubuntu-2204.yml +++ b/vars/ubuntu-2204.yml @@ -1,29 +1,20 @@ -# Every is_<OS> var is initially set to 'False' at the bottom of +# Every is_<OS_VER> var is initially set to 'False' at the bottom of # /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: is_debuntu: True is_ubuntu: True # Opposite of is_debian for now is_ubuntu_2204: True -# 2019-03-23: These apply if-only-if named_install and/or dhcpd_install are True -# (This is quite rare now that vars/default_vars.yml sets dnsmasq_install: True) -dns_service: bind9 -dns_user: bind -dhcp_service: isc-dhcp-server - -proxy: squid -proxy_user: proxy -apache_service: apache2 -apache_user: www-data -apache_conf_dir: apache2/sites-available -apache_log_dir: /var/log/apache2 -smb_service: smbd -nmb_service: nmbd -systemctl_program: /bin/systemctl -mysql_service: mariadb -apache_log: /var/log/apache2/access.log -sshd_package: openssh-server -sshd_service: ssh -php_version: 8.1 -postgresql_version: 14 -systemd_location: /lib/systemd/system -python_ver: 3.10 +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "8.1" +# postgresql_version: 14 +# python_version: "3.10" diff --git a/vars/ubuntu-2210.yml.unused b/vars/ubuntu-2210.yml.unused new file mode 100644 index 000000000..cfe7706f9 --- /dev/null +++ b/vars/ubuntu-2210.yml.unused @@ -0,0 +1,20 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2210: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "8.1" +# postgresql_version: 14 +# python_version: "3.10" diff --git a/vars/ubuntu-2304.yml.unused b/vars/ubuntu-2304.yml.unused new file mode 100644 index 000000000..72bb3d960 --- /dev/null +++ b/vars/ubuntu-2304.yml.unused @@ -0,0 +1,20 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2304: True + +# proxy: squid +# proxy_user: proxy +# apache_service: apache2 +# apache_user: www-data +# smb_service: smbd +# nmb_service: nmbd +# systemctl_program: /bin/systemctl +# mysql_service: mariadb +# sshd_package: openssh-server +# sshd_service: ssh +# systemd_location: /lib/systemd/system +# php_version: "8.1" +# postgresql_version: 15 +# python_version: "3.11" diff --git a/vars/ubuntu-2310.yml.unused b/vars/ubuntu-2310.yml.unused new file mode 100644 index 000000000..165a64a46 --- /dev/null +++ b/vars/ubuntu-2310.yml.unused @@ -0,0 +1,5 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2310: True diff --git a/vars/ubuntu-2404.yml b/vars/ubuntu-2404.yml new file mode 100644 index 000000000..d5355dcd0 --- /dev/null +++ b/vars/ubuntu-2404.yml @@ -0,0 +1,5 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2404: True diff --git a/vars/ubuntu-2410.yml b/vars/ubuntu-2410.yml new file mode 100644 index 000000000..6120c89a9 --- /dev/null +++ b/vars/ubuntu-2410.yml @@ -0,0 +1,5 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2410: True diff --git a/vars/ubuntu-2504.yml b/vars/ubuntu-2504.yml new file mode 100644 index 000000000..a548ba9a1 --- /dev/null +++ b/vars/ubuntu-2504.yml @@ -0,0 +1,5 @@ +# Every is_<OS_VER> var is initially set to 'False' at the bottom of +# /opt/iiab/iiab/vars/default_vars.yml -- these 'True' lines override that: +is_debuntu: True +is_ubuntu: True # Opposite of is_debian for now +is_ubuntu_2504: True