diff --git a/.github/workflows/pending/compatibility.yml b/.github/workflows/pending/compatibility.yml index c38b725..cc87c3d 100644 --- a/.github/workflows/pending/compatibility.yml +++ b/.github/workflows/pending/compatibility.yml @@ -74,9 +74,9 @@ jobs: uses: actions/cache@v2 with: path: ~/.vagrant.d/boxes - key: ${{ runner.os }}-vagrant-${{ hashFiles('Vagrantfile') }} + key: "${{ runner.os }}-vagrant-${{ hashFiles('Vagrantfile') }}" restore-keys: | - ${{ runner.os }}-vagrant- + "${{ runner.os }}-vagrant-" - name: Run vagrant up run: | diff --git a/.github/workflows/pending/lint.yml b/.github/workflows/pending/lint.yml index ec98417..dd108d0 100644 --- a/.github/workflows/pending/lint.yml +++ b/.github/workflows/pending/lint.yml @@ -30,9 +30,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install yamllint diff --git a/.github/workflows/pending/molecule_all_on_one.yml b/.github/workflows/pending/molecule_all_on_one.yml index b569a88..cd5a1e4 100644 --- a/.github/workflows/pending/molecule_all_on_one.yml +++ b/.github/workflows/pending/molecule_all_on_one.yml @@ -36,9 +36,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/.github/workflows/pending/molecule_fts_core.yml b/.github/workflows/pending/molecule_fts_core.yml index 8fb5475..14a5d6d 100644 --- a/.github/workflows/pending/molecule_fts_core.yml +++ b/.github/workflows/pending/molecule_fts_core.yml @@ -11,7 +11,7 @@ name: FTS CORE (DOCKER) - '**.md' concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: "${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: true jobs: @@ -69,9 +69,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/.github/workflows/pending/molecule_multiple.yml b/.github/workflows/pending/molecule_multiple.yml index 3960884..fc15e62 100644 --- a/.github/workflows/pending/molecule_multiple.yml +++ b/.github/workflows/pending/molecule_multiple.yml @@ -36,9 +36,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/.github/workflows/pending/molecule_mumble.yml b/.github/workflows/pending/molecule_mumble.yml index 25a7029..4c7678a 100644 --- a/.github/workflows/pending/molecule_mumble.yml +++ b/.github/workflows/pending/molecule_mumble.yml @@ -69,9 +69,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/.github/workflows/pending/molecule_noderedserver.yml b/.github/workflows/pending/molecule_noderedserver.yml index 2ca997f..3e8fea5 100644 --- a/.github/workflows/pending/molecule_noderedserver.yml +++ b/.github/workflows/pending/molecule_noderedserver.yml @@ -68,9 +68,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/.github/workflows/pending/molecule_videoserver.yml b/.github/workflows/pending/molecule_videoserver.yml index c1bad0a..859f875 100644 --- a/.github/workflows/pending/molecule_videoserver.yml +++ b/.github/workflows/pending/molecule_videoserver.yml @@ -69,9 +69,9 @@ jobs: - uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + key: "${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}" restore-keys: | - ${{ runner.os }}-pip- + "${{ runner.os }}-pip-" - name: Install test dependencies run: pip3 install ansible molecule[docker] docker diff --git a/docs/fts-test.yml b/docs/fts-test.yml new file mode 100644 index 0000000..d3f4fc7 --- /dev/null +++ b/docs/fts-test.yml @@ -0,0 +1,21 @@ +description: "a VM for testing FTS" +version: "24.4.0" + +# see https://doc.qt.io/qt-5/qsysinfo.html#currentCpuArchitecture +runs-on: +- x86_64 + +instances: + fts-test: + image: 22.04 + limits: + min-cpu: 2 + min-mem: 4G + min-disk: 10G +# timeout: # maximum time for the instance to launch, and separately for cloud-init to complete +# cloud-init: +# vendor-data: | # cloud-init vendor data +# +# a health-check shell script ran by integration tests +health-check: | + lsb_release -a diff --git a/docs/ubuntu_rasppi_test.md b/docs/ubuntu_rasppi_test.md index e65c7f7..65bd51b 100644 --- a/docs/ubuntu_rasppi_test.md +++ b/docs/ubuntu_rasppi_test.md @@ -30,12 +30,12 @@ to get the `easy_install.sh` from the same repository and branch as the ZTI. The official GitHub is `FreeTAKTeam`, if you are working in a fork you will need to use that. ```bash -export MY_IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') +export MY_IPA=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') export MY_GITHUB=FreeTAKTeam ```` ```bash -wget -qO - https://raw.githubusercontent.com/${MY_GITHUB}/FreeTAKHub-Installation/main/scripts/easy_install.sh | sudo bash -s -- --verbose --repo https://github.com/${MY_GITHUB}/FreeTAKHub-Installation.git --branch main --ip-addr ${MY_IP} +wget -qO - https://raw.githubusercontent.com/${MY_GITHUB}/FreeTAKHub-Installation/main/scripts/easy_install.sh | sudo bash -s -- --verbose --repo https://github.com/${MY_GITHUB}/FreeTAKHub-Installation.git --branch main --ip-addr ${MY_IPA} ``` diff --git a/docs/ubuntu_vm_test.md b/docs/ubuntu_vm_test.md index ad4a945..0489126 100644 --- a/docs/ubuntu_vm_test.md +++ b/docs/ubuntu_vm_test.md @@ -44,20 +44,27 @@ Note: On Windows you will need to [enable privileged mounts](https://multipass.run/docs/privileged-mounts). ```shell multipass set local.privileged-mounts=true -```` +``` Make a mount point on the virtual machine. Mount the directory containing the working repository. ```shell multipass exec fts-test -- mkdir fts-zti multipass mount $HOME/fts-installer fts-test:/home/ubuntu/fts-zti -```` +``` We can verify the mount point on the image. ```shell multipass info fts-test ``` +Make a snapshot. +```shell +multipass stop fts-test +multipass snapshot fts-test +``` +This will create a snapshot and provide its name. + ### Run the ZTI Start the prepared virtual machine. @@ -70,7 +77,8 @@ You may change the configured IP address later, but it is easiest to handle it now. It is likely you will want interface `eth0`. ```bash -export MY_IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') +export MY_IPA=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') +echo "My IPA: ${MY_IPA}" ```` Install FTS using the candidate ZTI. @@ -81,7 +89,11 @@ Notice that in the following command the `easy_install.sh` is taken from a working tree, while the branch is from the committed repository. ```bash -cat /home/ubuntu/fts-zti/scripts/easy_install.sh | sudo bash -s -- --verbose --repo file:///home/ubuntu/fts-zti/.git --branch main --ip-addr ${MY_IP} +cat /home/ubuntu/fts-zti/scripts/easy_install.sh | sudo NO_COLOR=TRUE bash -s -- --verbose --repo file:///home/ubuntu/fts-zti/.git --branch main --ip-addr ${MY_IPA} +``` +If you want to use Python packages from the https://test.pypi.org repository. +```bash +cat /home/ubuntu/fts-zti/scripts/easy_install.sh | sudo bash -s -- --verbose --repo file:///home/ubuntu/fts-zti/.git --branch main --ip-addr ${MY_IPA} --pypi https://test.pypi.org ``` ### Configuration @@ -100,8 +112,18 @@ Those instructions will not be duplicated here. ## Resetting the `multipass` VM +### Hard Reset + ```shell multipass stop fts-test multipass delete fts-test multipass purge ``` + +### Soft Reset + +The soft reset rolls back to a previous snapshot. +(You did make a snapshot, right?) +```shell +multipass restore fts-test.snapshot1 +``` diff --git a/install_all.yml b/install_all.yml index be855b3..946d790 100644 --- a/install_all.yml +++ b/install_all.yml @@ -24,6 +24,7 @@ - name: Cleanup import_tasks: roles/common/tasks/cleanup.yml + post_tasks: - name: Reload Node-RED Server flows to ensure Video Server connection import_tasks: roles/nodered/tasks/reload-flows.yml diff --git a/roles/common/files/ansible-fts-user.sudo b/roles/common/files/ansible-fts-user.sudo new file mode 100644 index 0000000..2913c9a --- /dev/null +++ b/roles/common/files/ansible-fts-user.sudo @@ -0,0 +1 @@ +%fts ALL=(ALL) NOPASSWD: ALL diff --git a/roles/common/tasks/configure-Ubuntu.yml b/roles/common/tasks/configure-Ubuntu.yml new file mode 100644 index 0000000..bf3409a --- /dev/null +++ b/roles/common/tasks/configure-Ubuntu.yml @@ -0,0 +1,51 @@ +--- + +- name: Make sure we have an 'fts' group + ansible.builtin.group: + name: fts + state: present + +- name: Allow 'fts' group to have passwordless sudo + ansible.builtin.copy: + content: "%fts ALL=(ALL) NOPASSWD: ALL" + dest: /etc/sudoers.d/80-ansible-fts-user + validate: 'visudo -cf %s' + +- name: Add fts user to the fts group + ansible.builtin.user: + name: fts + groups: fts,sudo + group: fts + append: yes + state: present + create_home: true + generate_ssh_key: true + ssh_key_file: .ssh/id_rsa + system: true + +- name: Set up authorized keys for the installing user + ansible.posix.authorized_key: + user: fts + key: "{{ item }}" + state: present + with_file: + - /home/fts/.ssh/id_rsa.pub + +- name: Establish fts base folder {{ fts_base_path }} + ansible.builtin.file: + path: "{{ fts_base_path }}" + group: fts + owner: fts + recurse: true + state: directory + mode: u+rw,g+rw,o+r + +- name: Establish fts venv of {{ fts_venv }} + ansible.builtin.file: + path: "{{ fts_venv }}" + group: fts + owner: fts + recurse: true + state: directory + mode: u+rw,g+rw,o+r + diff --git a/roles/common/tasks/kill.yml b/roles/common/tasks/kill.yml index 6434822..d2ca1bc 100644 --- a/roles/common/tasks/kill.yml +++ b/roles/common/tasks/kill.yml @@ -1,5 +1,7 @@ --- - name: Get running processes + become: true + become_user: root ansible.builtin.shell: "ps -ef | grep -v grep | grep -w {{ process | string }}" register: running_process_var failed_when: false diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index d06acb0..7553812 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -1,6 +1,15 @@ --- -- name: "Include {{ ansible_distribution }}-specific variables" - include_vars: "{{ ansible_distribution }}.yml" +- name: "Include Common {{ ansible_distribution }}-specific variables" + ansible.builtin.include_vars: + file: "{{ ansible_distribution }}.yml" + +- name: Configure Path + ansible.builtin.include_tasks: + file: "configure-{{ ansible_distribution }}.yml" +# ansible.builtin.vars: +# fts_base_path: "{{ fts_base_path }}" +# fts_venv: "{{ fts_venv }}" - name: Setup - include_tasks: "setup-{{ ansible_distribution }}.yml" + ansible.builtin.include_tasks: + file: "setup-{{ ansible_distribution }}.yml" diff --git a/roles/common/tasks/service.yml b/roles/common/tasks/service.yml index 56a404a..0c131b5 100644 --- a/roles/common/tasks/service.yml +++ b/roles/common/tasks/service.yml @@ -1,5 +1,7 @@ --- - name: Enable service + become: true + become_user: root service: name: "{{ service_name }}" enabled: "{{ service_enabled }}" @@ -9,6 +11,8 @@ until: enable_service is success - name: Set service state + become: true + become_user: root service: name: "{{ service_name }}" state: "{{ service_state }}" diff --git a/roles/common/vars/Ubuntu.yml b/roles/common/vars/Ubuntu.yml index 08d1ab5..149b3e3 100644 --- a/roles/common/vars/Ubuntu.yml +++ b/roles/common/vars/Ubuntu.yml @@ -1,2 +1,4 @@ --- -unit_files_location: /etc/systemd/system +unit_files_location: "/etc/systemd/system" + +fts_base_path: "/opt/fts" diff --git a/roles/freetakserver/defaults/main.yml b/roles/freetakserver/defaults/main.yml index 85da100..a6ac56c 100644 --- a/roles/freetakserver/defaults/main.yml +++ b/roles/freetakserver/defaults/main.yml @@ -2,6 +2,9 @@ # system information fts_ipv4: 0.0.0.0 +# The URL of the python package repository. +pypi_url: "" + fts_pip_package_name: FreeTAKServer fts_service_name: fts @@ -9,7 +12,8 @@ fts_service_name: fts # Set initial service state. Recommended values: `started` or `stopped`. fts_state: started -# Enable service. Recommended values: `true` or `false` +# Enable service. Recommended values: `true` or `false`. fts_enabled: true +# The relative path to the MainConfig.py file (from the fts_install_path). cfg_rpath: "core/configuration" diff --git a/roles/freetakserver/tasks/configure-Ubuntu.yml b/roles/freetakserver/tasks/configure-Ubuntu.yml index 5ef431e..d94683e 100644 --- a/roles/freetakserver/tasks/configure-Ubuntu.yml +++ b/roles/freetakserver/tasks/configure-Ubuntu.yml @@ -1,27 +1,31 @@ --- + - name: Template FTSConfig.yaml config file + become: true + become_user: fts template: src: FTSConfig.yaml.j2 dest: "{{ fts_config_path }}" - owner: root - group: root - mode: 0644 + owner: fts + group: fts + mode: 0664 - name: Change FirstStart to False in MainConfig.py lineinfile: - # path: "{{ fts_install_path }}/controllers/configuration/MainConfig.py" path: "{{ fts_install_path }}/{{ cfg_rpath }}/MainConfig.py" regexp: '(\s+)first_start = True' line: '\1first_start = False' backrefs: true - name: Template unit file + become: true + become_user: root template: src: fts.service.j2 dest: "{{ unit_files_location }}/{{ fts_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Kill any currently running processes include_tasks: ../../common/tasks/kill.yml diff --git a/roles/freetakserver/tasks/main.yml b/roles/freetakserver/tasks/main.yml index 2176ea9..ae4243f 100644 --- a/roles/freetakserver/tasks/main.yml +++ b/roles/freetakserver/tasks/main.yml @@ -7,7 +7,7 @@ - name: Get public IPv4 uri: - url: http://ifconfig.me/ip + url: https://ifconfig.me/ip return_content: true register: ip_response diff --git a/roles/freetakserver/tasks/setup-Ubuntu.yml b/roles/freetakserver/tasks/setup-Ubuntu.yml index c1a0283..36e9bc1 100644 --- a/roles/freetakserver/tasks/setup-Ubuntu.yml +++ b/roles/freetakserver/tasks/setup-Ubuntu.yml @@ -1,5 +1,7 @@ --- - name: Delete PyYAML + become: true + become_user: fts shell: "{{ item }}" loop: - "rm -rf {{ fts_python_packages }}/site-packages/yaml" @@ -17,6 +19,10 @@ # - "pip install /FreeTakServer" - name: "Install {{ fts_pip_package_name }}" - pip: + become: true + become_user: fts + ansible.builtin.pip: name: "{{ fts_pip_package_name }}=={{ fts_version }}" virtualenv: "{{ fts_venv }}" + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" diff --git a/roles/freetakserver/tasks/uninstall-Ubuntu.yml b/roles/freetakserver/tasks/uninstall-Ubuntu.yml index 49403ab..7355f23 100644 --- a/roles/freetakserver/tasks/uninstall-Ubuntu.yml +++ b/roles/freetakserver/tasks/uninstall-Ubuntu.yml @@ -6,17 +6,25 @@ ignore_errors: true - name: Remove unit file + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ fts_service_name }}.service" state: absent - name: Uninstall - pip: + become: true + become_user: fts + ansible.builtin.pip: name: "{{ fts_pip_package_name }}" state: absent virtualenv: "{{ fts_venv }}" + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" - name: Remove files + become: true + become_user: fts file: path: "{{ item }}" state: absent diff --git a/roles/freetakserver/templates/fts.service.j2 b/roles/freetakserver/templates/fts.service.j2 index f8dda80..c60fb69 100644 --- a/roles/freetakserver/templates/fts.service.j2 +++ b/roles/freetakserver/templates/fts.service.j2 @@ -7,6 +7,8 @@ StartLimitIntervalSec=0 Type=simple Restart=always RestartSec=1 +User=fts +Group=fts StandardOutput=append:/var/log/{{ fts_service_name }}/{{ fts_service_name }}-stdout.log StandardError=append:/var/log/{{ fts_service_name }}/{{ fts_service_name }}-stderr.log Environment="FTS_FIRST_START=false" diff --git a/roles/freetakserver/vars/Ubuntu.yml b/roles/freetakserver/vars/Ubuntu.yml index 1376fec..ae6ef3a 100644 --- a/roles/freetakserver/vars/Ubuntu.yml +++ b/roles/freetakserver/vars/Ubuntu.yml @@ -1,6 +1,6 @@ --- -fts_config_path: /opt/FTSConfig.yaml -fts_db_path: /opt/FreeTAKServer.db +fts_config_path: "{{ fts_base_path }}/FTSConfig.yaml" +fts_db_path: "{{ fts_base_path }}/FreeTAKServer.db" fts_python_packages: "{{ fts_venv }}/lib/python{{ python3_version }}" fts_install_path: "{{ fts_python_packages }}/site-packages/FreeTAKServer" diff --git a/roles/freetakserver_ui/handlers/main.yml b/roles/freetakserver_ui/handlers/main.yml index 8755a18..e17f492 100644 --- a/roles/freetakserver_ui/handlers/main.yml +++ b/roles/freetakserver_ui/handlers/main.yml @@ -16,7 +16,7 @@ - name: print fts_ui url debug: - msg: "FreeTAKServer-UI URL: http://{{ fts_ui_ipv4 }}:5000/" + msg: "FreeTAKServer-UI URL: https://{{ fts_ui_ipv4 }}:5000/" - name: print fts_ui credentials debug: diff --git a/roles/freetakserver_ui/tasks/configure-Ubuntu.yml b/roles/freetakserver_ui/tasks/configure-Ubuntu.yml index 105856a..c94aeec 100644 --- a/roles/freetakserver_ui/tasks/configure-Ubuntu.yml +++ b/roles/freetakserver_ui/tasks/configure-Ubuntu.yml @@ -1,19 +1,23 @@ --- - name: Template config file - template: + become: true + become_user: fts + ansible.builtin.template: src: config.py.j2 dest: "{{ fts_ui_install_path }}/config.py" - owner: root - group: root - mode: 0644 + owner: fts + group: fts + mode: 0664 - name: Template unit file - template: + become: true + become_user: root + ansible.builtin.template: src: fts-ui.service.j2 dest: "{{ unit_files_location }}/{{ fts_ui_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Kill any currently running processes include_tasks: ../../common/tasks/kill.yml @@ -21,6 +25,8 @@ process: "{{ fts_ui_install_path }}/run.py" - name: Enable service + become: true + become_user: root service: name: "{{ fts_ui_service_name }}" enabled: "{{ fts_ui_enabled }}" @@ -30,6 +36,8 @@ until: enable_fts_ui is success - name: Set service state + become: true + become_user: root service: name: "{{ fts_ui_service_name }}" state: "{{ fts_ui_state }}" diff --git a/roles/freetakserver_ui/tasks/setup-Ubuntu.yml b/roles/freetakserver_ui/tasks/setup-Ubuntu.yml index 79158cb..f756dd8 100644 --- a/roles/freetakserver_ui/tasks/setup-Ubuntu.yml +++ b/roles/freetakserver_ui/tasks/setup-Ubuntu.yml @@ -10,11 +10,19 @@ name: "{{ fts_ui_apt_packages }}" - name: "Install pip packages" - pip: + become: true + become_user: fts + ansible.builtin.pip: name: "{{ fts_ui_pip_packages }}" virtualenv: "{{ fts_venv }}" + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" - name: "Install {{ fts_ui_pip_package_name }}" - pip: + become: true + become_user: fts + ansible.builtin.pip: name: "{{ fts_ui_pip_package_name }}" virtualenv: "{{ fts_venv }}" + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" diff --git a/roles/freetakserver_ui/tasks/uninstall-Ubuntu.yml b/roles/freetakserver_ui/tasks/uninstall-Ubuntu.yml index 7e14199..734b866 100644 --- a/roles/freetakserver_ui/tasks/uninstall-Ubuntu.yml +++ b/roles/freetakserver_ui/tasks/uninstall-Ubuntu.yml @@ -6,12 +6,19 @@ ignore_errors: true - name: Remove unit file + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ fts_ui_service_name }}.service" state: absent - name: Uninstall - pip: + become: true + become_user: fts + ansible.builtin.pip: name: "{{ fts_ui_pip_package_name }}" state: absent virtualenv: "{{ fts_venv }}" + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" + diff --git a/roles/freetakserver_ui/templates/config.py.j2 b/roles/freetakserver_ui/templates/config.py.j2 index 9bfb367..72321d1 100644 --- a/roles/freetakserver_ui/templates/config.py.j2 +++ b/roles/freetakserver_ui/templates/config.py.j2 @@ -15,7 +15,7 @@ class Config(object): SECRET_KEY = 'key' # This will connect to the FTS db - SQLALCHEMY_DATABASE_URI = 'sqlite:///' + '/opt/FTSServer-UI.db' + SQLALCHEMY_DATABASE_URI = 'sqlite:///' + '/opt/fts/FTSServer-UI.db' # certificates path certpath = "{{ fts_python_packages }}/site-packages/FreeTAKServer/certs/" diff --git a/roles/freetakserver_ui/templates/fts-ui.service.j2 b/roles/freetakserver_ui/templates/fts-ui.service.j2 index 73026d0..37cd8cb 100644 --- a/roles/freetakserver_ui/templates/fts-ui.service.j2 +++ b/roles/freetakserver_ui/templates/fts-ui.service.j2 @@ -7,6 +7,8 @@ StartLimitIntervalSec=0 Type=simple Restart=always RestartSec=1 +User=fts +Group=fts StandardOutput=append:/var/log/{{ fts_ui_service_name }}/{{ fts_ui_service_name }}-stdout.log StandardError=append:/var/log/{{ fts_ui_service_name }}/{{ fts_ui_service_name }}-stderr.log ExecStart={{ fts_venv }}/bin/python3 {{ fts_ui_install_path }}/run.py diff --git a/roles/freetakserver_ui/vars/Ubuntu.yml b/roles/freetakserver_ui/vars/Ubuntu.yml index 893c0a0..c566c07 100644 --- a/roles/freetakserver_ui/vars/Ubuntu.yml +++ b/roles/freetakserver_ui/vars/Ubuntu.yml @@ -1,5 +1,5 @@ --- -fts_ui_sqlachemy_db_uri: /opt/FTSServer-UI.db +fts_ui_sqlachemy_db_uri: /opt/fts/FTSServer-UI.db fts_ui_python_packages: "{{ fts_venv }}/lib/python{{ python3_version }}" fts_ui_install_path: "{{ fts_ui_python_packages }}/site-packages/FreeTAKServer-UI" diff --git a/roles/mumble_web/tasks/configure-Ubuntu.yml b/roles/mumble_web/tasks/configure-Ubuntu.yml index 156eb26..8dccdb3 100644 --- a/roles/mumble_web/tasks/configure-Ubuntu.yml +++ b/roles/mumble_web/tasks/configure-Ubuntu.yml @@ -6,15 +6,17 @@ dest: "/var/www/mumble-web/config.local.js" owner: www-data group: www-data - mode: 0644 + mode: 0664 - name: Template unit file + become: true + become_user: root template: src: mumble-web.service.j2 dest: "{{ unit_files_location }}/{{ mumble_web_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Kill any currently running processes include_tasks: ../../common/tasks/kill.yml diff --git a/roles/mumble_web/tasks/uninstall-Ubuntu.yml b/roles/mumble_web/tasks/uninstall-Ubuntu.yml index 7dd170f..2603341 100644 --- a/roles/mumble_web/tasks/uninstall-Ubuntu.yml +++ b/roles/mumble_web/tasks/uninstall-Ubuntu.yml @@ -1,11 +1,15 @@ --- - name: Stop service + become: true + become_user: root service: name: "{{ mumble_web_service_name }}" state: stopped ignore_errors: true - name: Remove unit file + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ mumble_web_service_name }}.service" state: absent diff --git a/roles/mumble_web/templates/mumble-web.service.j2 b/roles/mumble_web/templates/mumble-web.service.j2 index 40c5a4b..fcd0a90 100644 --- a/roles/mumble_web/templates/mumble-web.service.j2 +++ b/roles/mumble_web/templates/mumble-web.service.j2 @@ -6,6 +6,7 @@ After=network.target mumble-server.service [Service] Type=simple User=www-data +# Group=root StandardOutput=append:/var/log/{{ mumble_web_service_name }}/{{ mumble_web_service_name }}-stdout.log StandardError=append:/var/log/{{ mumble_web_service_name }}/{{ mumble_web_service_name }}-stderr.log ExecStart=/usr/bin/websockify --web=/usr/lib/node_modules/mumble-web/dist --ssl-target {{ mumble_web_ipv4 }}:64737 {{ mumble_web_ipv4 }}:64738 diff --git a/roles/murmur/tasks/configure-Ubuntu.yml b/roles/murmur/tasks/configure-Ubuntu.yml index 08cfc07..40a6fbf 100644 --- a/roles/murmur/tasks/configure-Ubuntu.yml +++ b/roles/murmur/tasks/configure-Ubuntu.yml @@ -5,7 +5,7 @@ dest: /etc/mumble-server.ini owner: root group: mumble-server - mode: 0640 + mode: 0660 - name: Enable and set service include_tasks: ../../common/tasks/service.yml @@ -24,7 +24,7 @@ dest: /etc/mumble-superuser owner: root group: root - mode: 0600 + mode: 0660 - name: set superuser password command: murmurd -ini /etc/mumble-server.ini -supw "{{ murmur_superuser_password }}" diff --git a/roles/nodered/tasks/main.yml b/roles/nodered/tasks/main.yml index b32d7af..086b021 100644 --- a/roles/nodered/tasks/main.yml +++ b/roles/nodered/tasks/main.yml @@ -16,7 +16,7 @@ - name: Get public IPv4 tags: nodered uri: - url: http://ifconfig.me/ip + url: https://ifconfig.me/ip return_content: true register: ip_response diff --git a/roles/nodered/tasks/setup-Ubuntu.yml b/roles/nodered/tasks/setup-Ubuntu.yml index b2e5b6d..4b6613a 100644 --- a/roles/nodered/tasks/setup-Ubuntu.yml +++ b/roles/nodered/tasks/setup-Ubuntu.yml @@ -37,16 +37,20 @@ - name: Template unit file tags: nodered + become: true + become_user: root template: src: nodered.service.j2 dest: "{{ unit_files_location }}/{{ nodered_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Enable service tags: nodered + become: true + become_user: root service: name: "{{ nodered_service_name }}" enabled: true @@ -62,7 +66,7 @@ dest: "{{ nodered_install_folder }}/{{ nodered_settings_file }}" owner: root group: root - mode: 0644 + mode: 0664 - name: Set service state tags: nodered @@ -83,7 +87,7 @@ dest: "{{ nodered_install_folder }}/lib/flows/{{ item }}" owner: root group: root - mode: 0644 + mode: 0664 loop: "{{ nodered_flows }}" - name: "Template flows.json to /tmp/flows.json" @@ -93,4 +97,4 @@ dest: "/tmp/flows.json" owner: root group: root - mode: 0644 + mode: 0664 diff --git a/roles/nodered/tasks/uninstall-Ubuntu.yml b/roles/nodered/tasks/uninstall-Ubuntu.yml index 87e7293..87be838 100644 --- a/roles/nodered/tasks/uninstall-Ubuntu.yml +++ b/roles/nodered/tasks/uninstall-Ubuntu.yml @@ -1,6 +1,8 @@ --- - name: Stop service tags: nodered + become: true + become_user: root service: name: "{{ nodered_service_name }}" state: stopped @@ -8,6 +10,8 @@ - name: Remove unit file tags: nodered + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ nodered_service_name }}.service" state: absent diff --git a/roles/python3/tasks/setup-Ubuntu.yml b/roles/python3/tasks/setup-Ubuntu.yml index 1c3dcf3..7753bde 100644 --- a/roles/python3/tasks/setup-Ubuntu.yml +++ b/roles/python3/tasks/setup-Ubuntu.yml @@ -7,7 +7,9 @@ name: "{{ python3_apt_packages }}" - name: "Install pip packages" - pip: + ansible.builtin.pip: name: "{{ pip3_packages }}" virtualenv: "{{ fts_venv }}" # extra_args: --force-reinstall + environment: + PIP_EXTRA_INDEX_URL: "{{ pypi_url }}" diff --git a/roles/videoserver/tasks/configure-Ubuntu.yml b/roles/videoserver/tasks/configure-Ubuntu.yml index 9983d5a..df28f11 100644 --- a/roles/videoserver/tasks/configure-Ubuntu.yml +++ b/roles/videoserver/tasks/configure-Ubuntu.yml @@ -5,15 +5,17 @@ dest: "{{ videoserver_config_location }}" owner: root group: root - mode: 0644 + mode: 0664 - name: Template unit file + become: true + become_user: root template: src: rtsp-simple-server.service.j2 dest: "{{ unit_files_location }}/{{ videoserver_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Kill any currently running processes include_tasks: ../../common/tasks/kill.yml diff --git a/roles/videoserver/tasks/uninstall-Ubuntu.yml b/roles/videoserver/tasks/uninstall-Ubuntu.yml index 3903cb5..c213d6c 100644 --- a/roles/videoserver/tasks/uninstall-Ubuntu.yml +++ b/roles/videoserver/tasks/uninstall-Ubuntu.yml @@ -6,6 +6,8 @@ ignore_errors: true - name: Remove unit file + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ videoserver_service_name }}.service" state: absent diff --git a/roles/videoserver/templates/rtsp-simple-server.service.j2 b/roles/videoserver/templates/rtsp-simple-server.service.j2 index df7be62..baa3452 100644 --- a/roles/videoserver/templates/rtsp-simple-server.service.j2 +++ b/roles/videoserver/templates/rtsp-simple-server.service.j2 @@ -2,6 +2,8 @@ After=network.target [Service] +User=root +Group=root StandardOutput=append:/var/log/{{ videoserver_service_name }}/{{ videoserver_service_name }}-stdout.log StandardError=append:/var/log/{{ videoserver_service_name }}/{{ videoserver_service_name }}-stderr.log ExecStart={{ videoserver_executable_location }} {{ videoserver_config_location }} diff --git a/roles/webmap/tasks/configure-Ubuntu.yml b/roles/webmap/tasks/configure-Ubuntu.yml index 9df7bb1..5d6044b 100644 --- a/roles/webmap/tasks/configure-Ubuntu.yml +++ b/roles/webmap/tasks/configure-Ubuntu.yml @@ -5,15 +5,17 @@ dest: "{{ webmap_config_location }}" owner: root group: root - mode: 0644 + mode: 0664 - name: Template unit file + become: true + become_user: root template: src: webmap.service.j2 dest: "{{ unit_files_location }}/{{ webmap_service_name }}.service" owner: root group: root - mode: 0644 + mode: 0664 - name: Kill any currently running processes include_tasks: ../../common/tasks/kill.yml diff --git a/roles/webmap/tasks/uninstall-Ubuntu.yml b/roles/webmap/tasks/uninstall-Ubuntu.yml index 8dc72bb..eb903c8 100644 --- a/roles/webmap/tasks/uninstall-Ubuntu.yml +++ b/roles/webmap/tasks/uninstall-Ubuntu.yml @@ -1,11 +1,15 @@ --- - name: Stop service + become: true + become_user: root service: name: "{{ webmap_service_name }}" state: stopped ignore_errors: true - name: Remove unit file + become: true + become_user: root file: path: "{{ unit_files_location }}/{{ webmap_service_name }}.service" state: absent diff --git a/roles/webmap/templates/webmap.service.j2 b/roles/webmap/templates/webmap.service.j2 index 454602b..f38cd7a 100644 --- a/roles/webmap/templates/webmap.service.j2 +++ b/roles/webmap/templates/webmap.service.j2 @@ -7,6 +7,8 @@ StartLimitIntervalSec=0 Type=simple Restart=always RestartSec=1 +User=root +Group=root StandardOutput=append:/var/log/{{ webmap_service_name }}/{{ webmap_service_name }}-stdout.log StandardError=append:/var/log/{{ webmap_service_name }}/{{ webmap_service_name }}-stderr.log ExecStart={{ webmap_executable_location }} {{ webmap_config_location }} diff --git a/scripts/easy_install.backup.sh b/scripts/easy_install.backup.sh deleted file mode 100644 index 441ec7b..0000000 --- a/scripts/easy_install.backup.sh +++ /dev/null @@ -1,762 +0,0 @@ -#!/usr/bin/env bash - -# check if user is root -if [[ "$EUID" -ne 0 ]]; then - printf "$0 is not running as root (use sudo).\n" - exit 1 -fi - -# save the time started to calculate install time -start=$(date +%s) || false - -# set failfast -set -o errexit - -############################################################ MAIN BUSINESS LOGIC - -main() { - - identify_system - setup_virtual_environment - install_components - start_services - - end=$(date +%s) - total_seconds=$((end - start)) - printf "SUCCESS! INSTALLED IN %ss.\n" "$total_seconds" - -} - -readonly user_exec="sudo -i -u $SUDO_USER" -readonly unit_files_dir="/lib/systemd/system" -readonly fts_install_repo="FreeTAKHub-Installation" -readonly fts_repo="FreeTakServer" -readonly base_repo="https://github.com/FreeTAKTeam" -readonly group_name="fts" -readonly env_name="fts" -readonly python_version="3.8" -readonly fts_package="FreeTAKServer" -readonly fts_service=fts -readonly fts_ui_package="FreeTAKServer-UI" -readonly fts_ui_service=fts-ui -readonly webmap_name="FTH-webmap-linux" -readonly webmap_version="0.2.5" -readonly webmap_filename="$webmap_name-$webmap_version.zip" -readonly webmap_executable="$webmap_name-$webmap_version" -readonly webmap_url="https://github.com/FreeTAKTeam/FreeTAKHub/releases/download/v$webmap_version/$webmap_name-$webmap_version.zip" -readonly webmap_sha256="11afcde545cc4c2119c0ff7c89d23ebff286c99c6e0dfd214eae6e16760d6723" -readonly webmap_install_dir="/usr/local/bin" -readonly webmap_config="webMAP_config.json" -readonly webmap_service=webmap - -SYSTEM_NAME=$(uname) -SYSTEM_DIST="Unknown" -SYSTEM_DIST_BASED_ON="Unknown" -SYSTEM_PSEUDO_NAME="Unknown" -SYSTEM_VERSION="Unknown" -SYSTEM_ARCH=$(uname -m) -SYSTEM_ARCH_NAME="Unknown" -SYSTEM_KERNEL=$(uname -r) -SYSTEM_CONTAINER=false -CLOUD_PROVIDER=false - -trap cleanup SIGINT SIGTERM - -cleanup() { - rm -f "$conda_installer" - rm -f "$webmap_zip" -} - -# override localization settings to ensure English output -export LC_ALL=C - -# home directory of user running this script -user_home=$(getent passwd "$SUDO_USER" | cut -d: -f6) || false - -# unless specified, default target IPv4 is localhost -my_ipv4="127.0.0.1" -fts_ip=$my_ipv4 -fts_ui_ip=$my_ipv4 -webmap_ip=$my_ipv4 - -no_color="0" -COLOR_BOLD="\033[1m" -COLOR_RED="\033[0;31m" -COLOR_GREEN="\033[0;32m" -COLOR_YELLOW="\033[0;33m" -COLOR_BLUE="\033[0;34m" -COLOR_OFF="\033[0m" - - -declare -a supported_os=( - "ubuntu 20.04" -) - -usage() { - cat <] - -Install Free TAK Server and components. - -Available options: --h, --help print help --v, --verbose print script debug info --l, --log log output to file named fts.log (in running directory) - --no-color turn off console colors - -=============================================================================== -INSTALLATION OPTIONS -=============================================================================== -The default installation is the fts core installation, which consists of: - 1. fts - 2. ui - 3. webmap - -Installation of other components requires passing parameters to the command. - --a, --ansible install using ansible - -If any of the below switches are set, only the specified component will be -installed. - - --all install all components (default is only fts, ui & webmap) - --fts install fts - --ui install fts user interface - --map install webmap - --nodered install node-red server - --video install video server - --mumble install murmur server voip and mumble client - -=============================================================================== -NETWORKING OPTIONS -=============================================================================== -If none of the below options are set, the IPv4 will be localhost. - - -i, --ipv4=IPV4 If set, all services installed will use this IPv4. - -If you would like to use specific IPs for components, use the options below: - - --fts_ip=IPV4 Set fts ipv4, defaults to localhost. - --map_ip=IPV4 Set webmap ipv4, defaults to localhost. - -=============================================================================== -EXAMPLES -=============================================================================== -Install freetakserver (fts) core components fts, user interface, and webmap: - - sudo ./easy_install - -Install all components (fts, ui, webmap, video server, mumble/murmur voip): - - sudo ./easy_install --all - -Install using a specific ipv4: - - sudo ./easy_install --ipv4 209.85.231.104 - -Install fts core components with log and verbosity: - - sudo ./easy_install -v -l - -Install all components only the video server: - - sudo ./easy_install --video - -USAGE_TEXT - exit 1 -} - -####################################################################### LOGGING - -# main logging functions - - -print_error() { - { - printf "$COLOR_RED" - printf "ERROR: " - printf "$COLOR_OFF" - printf '%s\n' "$@" - } >&2 -} - -print_warn() { - printf "$COLOR_YELLOW" - printf "WARN: " - printf "$COLOR_OFF" - printf '%s\n' "$@" -} - -print_info() { - printf "$COLOR_BLUE" - printf "INFO: " - printf "$COLOR_OFF" - printf '%s\n' "$@" -} - -print_success() { - printf "$COLOR_GREEN" - printf "SUCCESS: " - printf "$COLOR_OFF" - printf '%s\n' "$@" -} - -print_bold() { - printf "$COLOR_BOLD" - printf '%b\n' "$@" - printf "$COLOR_OFF" -} - -print_msg() { - printf '%s\n' "$@" -} - -setup_log() { - exec > >(tee fts.log) 2>&1 -} - -validate_ipv4() { - # check if $candidate_ip is a valid my_ipv4 address - # return 0 if true, 1 otherwise - local arr element candidate_ip="$1" - IFS=. read -r -a arr <<<"$candidate_ip" - [[ ${#arr[@]} != 4 ]] && return 1 - for element in "${arr[@]}"; do - [[ (! $element =~ ^[0-9]+$) || $element =~ ^0[1-9]+$ ]] && return 1 - ((element < 0 || element > 255)) && return 1 - done - return 0 -} - -check_ipv4_arg() { - local candidate_ipv4=$1 - set +e # don't failfast when validating - result="$(validate_ipv4 $candidate_ipv4)" - set -e # turn on failfast - if [[ ("$result" -eq "0") ]]; then - print_error "INVALID IPv4" "$candidate_ipv4" - exit 1 - fi -} - -# parse arguments - -parse_args() { - - while true; do - case "${1-}" in - --help | -h) - usage - exit 0 - shift - ;; - --no-color) - no_color=1 - shift - ;; - --log | -l) - setup_log - shift - ;; - --verbose | -v) - set -x - shift - ;; - *) - break - ;; - esac - done - - if [ -z $no_color ]; then - unset COLOR_BOLD - unset COLOR_RED - unset COLOR_GREEN - unset COLOR_YELLOW - unset COLOR_BLUE - unset COLOR_OFF - fi - - # parse arguments - while true; do - case "${1-}" in - --ansible | -a) - use_ansible=1 - shift - ;; - --ipv4) - candidate_ipv4=$2 - check_ipv4_arg "$candidate_ipv4" - my_ipv4="$candidate_ipv4" - shift - shift - ;; - --fts_ip) - candidate_ipv4=$2 - check_ipv4_arg "$candidate_ipv4" - fts_ip="$candidate_ipv4" - shift - shift - ;; - --map_ip) - candidate_ipv4=$2 - check_ipv4_arg "$candidate_ipv4" - webmap_ip="$candidate_ipv4" - shift - shift - ;; - -?*) - "FAIL: unknown option $1" - exit 1 - ;; - *) - break - ;; - esac - done - - print_info "IPv4 ADDRESS=$my_ipv4" - -} - -replace() { - # global replacement of string in file - local file=$1 search=$2 replace=$3 - print_info "attempting to replace string: $search" - print_info " with string: $replace" - print_info " in file: $file" - sed -i "s/$search/$replace/g" "$file" -} - -download() { - local url=$1 file="$2" - print_info "downloading $file" - print_info "from URL: $url" - wget $url -qO "$file" -} - -check_file_integrity() { - local checksum=$1 file=$2 - SHA256SUM_RESULT=$(printf "%s %s" "$checksum" "$file" | sha256sum -c) - if [ "${SHA256SUM_RESULT}" = "${file}: OK" ]; then - print_info "checking sha256sum of file: $file" - else - print_error "sha256sum check failed: $file" - exit 0 - fi - print_success "sha256sum check passed: $file" -} - -setup_service() { - local name="$1" command="$2" - create_start_script "$name" "$command" - create_unit_file "$name" - mv -f "${name}.sh" "$unit_files_dir/${name}.sh" - mv -f "${name}.service" "$unit_files_dir/${name}.service" - enable_service "$name" -} - -enable_service() { - local name=$1 - chown -R "$SUDO_USER":"$group_name" "$conda_install_dir" - systemctl daemon-reload - systemctl enable "$name" -} - -create_start_script() { - local name="$1" command="$2" - cat >"${name}.sh" <"${name}.service" <"/tmp/FTSConfig.yaml" -System: - #FTS_DATABASE_TYPE: SQLite - FTS_CONNECTION_MESSAGE: Welcome to FreeTAKServer {MainConfig.version}. The Parrot is not dead. It's just resting - #FTS_OPTIMIZE_API: True - #FTS_MAINLOOP_DELAY: 1 -Addresses: - #FTS_COT_PORT: 8087 - #FTS_SSLCOT_PORT: 8089 - FTS_DP_ADDRESS: $fts_ip - FTS_USER_ADDRESS: $fts_ip - #FTS_API_PORT: 19023 - #FTS_FED_PORT: 9000 - #FTS_API_ADDRESS: $fts_ip -FileSystem: - FTS_DB_PATH: /opt/FreeTAKServer.db - #FTS_COT_TO_DB: True - FTS_MAINPATH: $sitepackages/$fts_package - #FTS_CERTS_PATH: $sitepackages/$fts_package/certs - #FTS_EXCHECK_PATH: $sitepackages/$fts_package/ExCheck - #FTS_EXCHECK_TEMPLATE_PATH: $sitepackages/$fts_package/ExCheck/template - #FTS_EXCHECK_CHECKLIST_PATH: $sitepackages/$fts_package/ExCheck/checklist - #FTS_DATAPACKAGE_PATH: $sitepackages/$fts_package/FreeTAKServerDataPackageFolder - #FTS_LOGFILE_PATH: $sitepackages/$fts_package/Logs -Certs: - #FTS_SERVER_KEYDIR: $sitepackages/$fts_package/certs/server.key - #FTS_SERVER_PEMDIR: $sitepackages/$fts_package/certs/server.pem - #FTS_TESTCLIENT_PEMDIR: $sitepackages/$fts_package/certs/Client.pem - #FTS_TESTCLIENT_KEYDIR: $sitepackages/$fts_package/certs/Client.key - #FTS_UNENCRYPTED_KEYDIR: $sitepackages/$fts_package/certs/server.key.unencrypted - #FTS_SERVER_P12DIR: $sitepackages/$fts_package/certs/server.p12 - #FTS_CADIR: $sitepackages/$fts_package/certs/ca.pem - #FTS_CAKEYDIR: $sitepackages/$fts_package/certs/ca.key - #FTS_FEDERATION_CERTDIR: $sitepackages/$fts_package/certs/server.pem - #FTS_FEDERATION_KEYDIR: $sitepackages/$fts_package/certs/server.key - #FTS_CRLDIR: $sitepackages/$fts_package/certs/FTS_CRL.json - #FTS_FEDERATION_KEYPASS: demopassfed - #FTS_CLIENT_CERT_PASSWORD: demopasscert - #FTS_WEBSOCKET_KEY: YourWebsocketKey - -EOF -} - -initialize_fts_ui_config() { - cat <"/tmp/config.py" -# -*- encoding: utf-8 -*- -""" -License: MIT -Copyright (c) 2019 - present AppSeed.us -""" -import os -from os import environ - - -class Config(object): - - basedir = os.path.abspath(os.path.dirname(__file__)) - - SECRET_KEY = 'key' - - # This will connect to the FTS db - SQLALCHEMY_DATABASE_URI = 'sqlite:///' + '/opt/FTSServer-UI.db' - - # certificates path - certpath = "$sitepackages/$fts_package/certs/" - - # crt file path - crtfilepath = f"{certpath}pubserver.pem" - - # key file path - keyfilepath = f"{certpath}pubserver.key.unencrypted" - - # this IP will be used to connect with the FTS API - IP = '$fts_ip' - - # Port the UI uses to communicate with the API - PORT = '19023' - - # the public IP your server is exposing - APPIP = '$fts_ip' - - # webmap IP - WEBMAPIP = '$webmap_ip' - - # webmap port - WEBMAPPORT = 8000 - - # this port will be used to listen - APPPort = 5000 - - # the webSocket key used by the UI to communicate with FTS. - WEBSOCKETKEY = 'YourWebsocketKey' - - # the API key used by the UI to comunicate with FTS. generate a new system user and then set it - APIKEY = 'Bearer token' - - # For 'in memory' database, please use: - # SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' - - SQLALCHEMY_TRACK_MODIFICATIONS = False - - # THEME SUPPORT - # if set then url_for('static', filename='', theme='') - # will add the theme name to the static URL: - # /static//filename - # DEFAULT_THEME = "themes/dark" - DEFAULT_THEME = None - - -class ProductionConfig(Config): - DEBUG = False - - # Security - SESSION_COOKIE_HTTPONLY = True - REMEMBER_COOKIE_HTTPONLY = True - REMEMBER_COOKIE_DURATION = 3600 - - # PostgreSQL database - SQLALCHEMY_DATABASE_URI = 'postgresql://{}:{}@{}:{}/{}'.format( - environ.get('APPSEED_DATABASE_USER', 'appseed'), - environ.get('APPSEED_DATABASE_PASSWORD', 'appseed'), - environ.get('APPSEED_DATABASE_HOST', 'db'), - environ.get('APPSEED_DATABASE_PORT', 5432), - environ.get('APPSEED_DATABASE_NAME', 'appseed') - ) - - -class DebugConfig(Config): - DEBUG = True - - -config_dict = { - 'Production': ProductionConfig, - 'Debug': DebugConfig -} - -EOF -} - -clone_fts_installer_repo() { - if [[ ! -d ~/$fts_install_repo ]]; then - $conda_run git clone "$base_repo/$fts_install_repo" "$user_home/$fts_install_repo" - else - $conda_run git -C "$user_home/$fts_install_repo" pull - fi -} - -run_playbook() { - conda install --name "$env_name" --channel conda-forge ansible - EXTRA_VARS=-e "CONDA_PREFIX=$CONDA_PREFIX" -e "env_name=$env_name" - if [[ -n "${CORE}" ]]; then - $conda_run ansible-playbook -u "$SUDO_USER", "$IP_ARG", --connection=local "$EXTRA_VARS" install_mainserver.yml -vvv - else - $conda_run ansible-playbook -u "$SUDO_USER", "$IP_ARG", --connection=local "$EXTRA_VARS" install_all.yml -vvv - fi -} - -manual_fts_build() { - # TODO: currently unused, kept for resiliency - if [[ ! -d "$CONDA_PREFIX/$fts_repo" ]]; then - $user_exec $conda_run git clone "$base_repo/$fts_repo" "$CONDA_PREFIX/$fts_repo" - else - cd "$CONDA_PREFIX/$fts_repo" && $conda_run git pull - fi - $user_exec $conda_run python "$CONDA_PREFIX/$fts_repo/setup.py" install - chown -R "$SUDO_USER":"$group_name" "$CONDA_PREFIX/$fts_repo/$fts_package" - mv -f "$CONDA_PREFIX/$fts_repo/$fts_package" "$sitepackages" -} - -identify_system() { - # detect Debian-family OS (Ubuntu) - if [ -f /etc/debian_version ]; then - id="$(grep "^ID=" /etc/os-release | awk -F= '{ print $2 }')" - SYSTEM_DIST="$id" - if [ "$SYSTEM_DIST" = "debian" ]; then - SYSTEM_PSEUDO_NAME=$(grep "^VERSION=" /etc/os-release | awk -F= '{ print $2 }' | grep -oEi '[a-z]+') - SYSTEM_VERSION=$(cat /etc/debian_version) - elif [ "$SYSTEM_DIST" = "ubuntu" ]; then - SYSTEM_PSEUDO_NAME=$(grep '^DISTRIB_CODENAME' /etc/lsb-release | awk -F= '{ print $2 }') - SYSTEM_VERSION=$(grep '^DISTRIB_RELEASE' /etc/lsb-release | awk -F= '{ print $2 }') - fi - fi - - # Detect if inside Docker - if grep -iq docker /proc/1/cgroup 2>/dev/null || head -n 1 /proc/1/sched 2>/dev/null | grep -Eq '^(bash|sh) ' || [ -f /.dockerenv ]; then - SYSTEM_CONTAINER="true" - fi - - # lowercase vars - SYSTEM_NAME=$(echo "$SYSTEM_NAME" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_DIST=$(echo "$SYSTEM_DIST" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_DIST_BASED_ON=$(echo "$SYSTEM_DIST_BASED_ON" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_PSEUDO_NAME=$(echo "$SYSTEM_PSEUDO_NAME" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_VERSION=$(echo "$SYSTEM_VERSION" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_ARCH=$(echo "$SYSTEM_ARCH" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_ARCH_NAME=$(echo "$SYSTEM_ARCH_NAME" | tr "[:upper:]" "[:lower:]" | tr " " "_") - SYSTEM_KERNEL=$(echo "$SYSTEM_KERNEL" | tr "[:upper:]" "[:lower:]" | tr " " "_") - - # report detected system information - print_info "SYSTEM_NAME=$SYSTEM_NAME" - print_info "SYSTEM_DIST=$SYSTEM_DIST" - print_info "SYSTEM_DIST_BASED_ON=$SYSTEM_DIST_BASED_ON" - print_info "SYSTEM_PSEUDO_NAME=$SYSTEM_PSEUDO_NAME" - print_info "SYSTEM_VERSION=$SYSTEM_VERSION" - print_info "SYSTEM_ARCH=$SYSTEM_ARCH" - print_info "SYSTEM_ARCH_NAME=$SYSTEM_ARCH_NAME" - print_info "SYSTEM_KERNEL=$SYSTEM_KERNEL" - - local is_supported=false - - print_info "list of supported operating systems: " - - # check for supported os - for candidate_os in "${supported_os[@]}"; do - local supported_os_version="$SYSTEM_DIST $SYSTEM_VERSION" - print_info " $supported_os_version" - if [[ "$SYSTEM_DIST $SYSTEM_VERSION" = "$candidate_os" ]]; then - is_supported=true - fi - done - - # if not a supported operating system, warn the user - if [ $is_supported = false ]; then - print_warn "DID NOT DETECT A SUPPORTED OPERATING SYSTEM\n" - read -r -e -p "Do you want to continue? [y/n]: " PROCEED - if [[ "${PROCEED:-n}" != "y" ]]; then - print_warn "Answer was not y (yes). Exiting." - exit 1 - fi - fi - - print_success "found supported operating system: $candidate_os" -} - -setup_virtual_environment() { - local conda_filename="Miniconda3-py38_4.11.0-Linux-x86_64.sh" - local conda_installer=$(mktemp --suffix ".$conda_filename") || false - local conda_url="https://repo.anaconda.com/miniconda/$conda_filename" - local conda_sha256="4bb91089ecc5cc2538dece680bfe2e8192de1901e5e420f63d4e78eb26b0ac1a" - - # download conda - conda_install_dir="$user_home/conda" - download $conda_url "$conda_installer" - check_file_integrity "$conda_sha256" "$conda_installer" - - print_info "installing conda virtual environment" - mkdir -p "$conda_install_dir" - bash "$conda_installer" -u -b -p "$conda_install_dir" >/dev/null 2>&1 - - print_info "setting permissions for conda virtual environment" - groupadd -f "$group_name" - usermod -a -G "$group_name" "$SUDO_USER" - chgrp "$group_name" "/usr/local/bin" - ln -sf "$conda_install_dir/bin/conda" "/usr/local/bin/conda" - - print_info "configuring conda virtual environment" - source "$conda_install_dir/etc/profile.d/conda.sh" - conda update --yes --name base conda >/dev/null 2>&1 - conda config --set auto_activate_base true --set always_yes yes --set changeps1 yes - - print_info "creating virtual environment: $env_name" - conda create --name "$env_name" python="$python_version" >/dev/null 2>&1 - - print_info "activating virtual environment" - $user_exec conda init bash >/dev/null 2>&1 - eval "$(conda shell.bash hook)" - conda activate "$env_name" - - # ensure permissions after activate - chown -R "$SUDO_USER":"$group_name" "$conda_install_dir" - - # set conda variables to facilitate later installation steps - conda_run="conda run -n $env_name" - python_exec=$($conda_run which python${python_version}) - sitepackages="$CONDA_PREFIX/lib/python${python_version}/site-packages" - - print_success "done installing virtual environment" -} - -fts_shell_install() { - print_info "installing Free TAK Server (FTS)" - $user_exec $conda_run python -m pip install --no-input "$fts_package" >/dev/null 2>&1 - - print_info "configuring FTS" - - # setup MainConfig.py file - local search=" first_start = True" - local replace=" first_start = False" - replace "$sitepackages/$fts_package/controllers/configuration/MainConfig.py" "$search" "$replace" - - # setup FTSConfig.yaml file - initialize_fts_yaml - chgrp "$group_name" "/tmp/FTSConfig.yaml" - mv -f "/tmp/FTSConfig.yaml" "/opt/FTSConfig.yaml" - - print_info "setting up FTS to automatically start" - local fts_command="$python_exec -m FreeTAKServer.controllers.services.FTS" - setup_service "$fts_service" "$fts_command" -} - -fts_ui_shell_install() { - print_info "installing FTS User Interface" - $user_exec $conda_run python -m pip install --no-input "$fts_ui_package" - - print_info "configuring FTS User Interface" - initialize_fts_ui_config - chgrp "$group_name" "/tmp/config.py" - mv -f "/tmp/config.py" "$sitepackages/$fts_ui_package/config.py" - - print_info "setting up FTS User Interface to automatically start" - local fts_ui_command="$python_exec $sitepackages/$fts_ui_package/run.py" - setup_service "$fts_ui_service" "$fts_ui_command" -} - -webmap_shell_install() { - print_info "downloading webmap" - wget $webmap_url -qO "/tmp/$webmap_filename" - check_file_integrity "$webmap_sha256" "/tmp/$webmap_filename" - - print_info "installing webmap" - - # unzip webmap - chmod 777 "/tmp/$webmap_filename" - $user_exec conda install -y --name "$env_name" unzip >/dev/null 2>&1 - $conda_run unzip -o "/tmp/$webmap_filename" -d /tmp >/dev/null 2>&1 - - # remove version string - mv -f "/tmp/$webmap_executable" "/tmp/$webmap_name" - - # move to destination directory - chgrp "$group_name" "/tmp/$webmap_name" - mv -f "/tmp/$webmap_name" "$webmap_install_dir/$webmap_name" - - print_info "configuring webmap" - - # configure ip in webMAP_config.json - local search="\"FTH_FTS_URL\": \"204.48.30.216\"," - local replace="\"FTH_FTS_URL\": \"$my_ipv4\"," - replace "/tmp/$webmap_config" "$search" "$replace" - chgrp "$group_name" "/tmp/$webmap_config" - mv -f "/tmp/$webmap_config" "/opt/$webmap_config" - - print_info "setting up webmap to automatically start" - local webmap_command="/usr/local/bin/$webmap_name /opt/$webmap_config" - setup_service "$webmap_service" "$webmap_command" -} - -install_components() { - if [[ -n "$use_ansible" ]]; then - clone_fts_installer_repo - run_playbook - else - fts_shell_install - fts_ui_shell_install - webmap_shell_install - fi -} - -start_services() { - systemctl start "$fts_service" - systemctl start "$fts_ui_service" - systemctl start "$webmap_service" -} - -main "$@" diff --git a/scripts/easy_install.sh b/scripts/easy_install.sh index 9dded64..a9dddd0 100755 --- a/scripts/easy_install.sh +++ b/scripts/easy_install.sh @@ -24,6 +24,9 @@ DEFAULT_BRANCH="main" BRANCH=${BRANCH:-$DEFAULT_BRANCH} CBRANCH=${CBRANCH:-} +DEFAULT_PYPI_URL="https://pypi.org" +TEST_PYPI_URL="https://test.pypi.org" + STABLE_OS_REQD="Ubuntu" STABLE_OS_VER_REQD="22.04" STABLE_CODENAME_REQD="jammy" @@ -40,9 +43,13 @@ PY3_VER_STABLE="3.11" STABLE_FTS_VERSION="2.0.66" LEGACY_FTS_VERSION="1.9.9.6" -LATEST_FTS_VERSION=$(curl -s https://pypi.org/pypi/FreeTAKServer/json | python3 -c "import sys, json; print(json.load(sys.stdin)['info']['version'])") +function set_latest_fts_version() { + local pypi_url=$1 + export LATEST_FTS_VERSION=$(curl -s ${pypi_url}/pypi/FreeTAKServer/json | python3 -c "import sys, json; print(json.load(sys.stdin)['info']['version'])") +} +set_latest_fts_version ${DEFAULT_PYPI_URL} -FTS_VENV="${HOME}/fts.venv" +FTS_VENV="/opt/fts.venv" DRY_RUN=0 @@ -95,7 +102,9 @@ Available options: -h, --help Print help -v, --verbose Print script debug info --c, --check Check for compatibility issues while installing +-c, --check Check for compatibility issues while installing [DEFAULT 'os'], may be repeated + --no-check Suppress check for compatibility issues while installing, may be repeated +-w, --warn Convert errors into warnings --core Install FreeTAKServer, UI, and Web Map --latest [DEFAULT] Install latest version (v$LATEST_FTS_VERSION) -s, --stable Install latest stable version (v$STABLE_FTS_VERSION) @@ -104,7 +113,14 @@ Available options: --branch Use specified ZT Installer repository branch [DEFAULT main] --dev-test Sets TEST Envar to 1 --dry-run Sets up dependencies but exits before running any playbooks - --ip-addr Explicitly set IP address (when http://ifconfig.me/ip is wrong) + --ip-addr Explicitly set IP address (when https://ifconfig.me/ip is wrong) + --pypi Explicitly set the URL for PYPI repository (e.g. https://test.pypi.org) + +The supported checks are: +- root is the install being run under root authority +- os is a recommended operating system being used +- arch is this a supported hardware architecture + USAGE_TEXT exit } @@ -145,13 +161,31 @@ function die() { } +############################################################################### +# If the situation is dire then panic. +############################################################################### +function panic() { + + if [[ "${WARN_LEVEL:-0}" -eq 1 ]]; then + echo $1 + else + die $@ + fi +} + ############################################################################### # Parse parameters ############################################################################### + +WARN_LEVEL=0 +CHECK_OS=1 +CHECK_ROOT=0 +CHECK_ARCH=0 + function parse_params() { - # The default 'apt verbosity' is verbose. Set it to quiet, since that's what our script assumes - # unset this later if we want verbosity + # The default 'apt verbosity' is verbose. + # Set it to quiet, since that's what our script assumes unset this later if we want verbosity APT_VERBOSITY="-qq" while true; do @@ -178,7 +212,43 @@ function parse_params() { ;; --check | -c) - CHECK=1 + case "${2-}" in + 'os') + CHECK_OS=1 + ;; + 'root') + CHECK_ROOT=1 + ;; + 'arch') + CHECK_ARCH=1 + ;; + *) + echo "Invalid check type: $2" + ;; + esac + shift 2 + ;; + + --no-check) + case "${2-}" in + 'os') + CHECK_OS=0 + ;; + 'root') + CHECK_ROOT=0 + ;; + 'arch') + CHECK_ARCH=0 + ;; + *) + echo "Invalid check type: $2" + ;; + esac + shift 2 + ;; + + --warn | -w) + WARN_LEVEL=1 shift ;; @@ -245,6 +315,17 @@ function parse_params() { echo "Using the IP of ${FTS_IP_CUSTOM}" ;; + --pypi) + # PIP_EXTRA_INDEX_URL is special. + # If after pip checks the primary index-url; + # it does not find the source, + # it will check the extra-index.url repositories. + export PIP_EXTRA_INDEX_URL=$2 + shift 2 + echo "Using the extra pypi URL of ${PIP_EXTRA_INDEX_URL}" + set_latest_fts_version ${PIP_EXTRA_INDEX_URL} + ;; + --no-color) NO_COLOR=1 shift @@ -294,7 +375,7 @@ function set_versions() { export CODENAME=$STABLE_CODENAME_REQD ;; *) - die "Unsupport install type: $INSTALL_TYPE" + die "Unsupported install type: $INSTALL_TYPE" ;; esac @@ -304,17 +385,18 @@ function set_versions() { ############################################################################### function do_checks() { - check_root + if [[ "${CHECK_ROOT:-0}" -eq 1 ]]; then + check_root + fi - if [[ -n "${CHECK-}" ]]; then + if [[ "${CHECK_OS:-0}" -eq 1 ]]; then check_os - # check_architecture else WEBMAP_FORCE_INSTALL="webmap_force_install=true" fi - if [[ -n "${TEST-}" ]]; then - REPO="https://github.com/janseptaugust/FreeTAKHub-Installation.git" + if [[ "${CHECK_ARCH:-0}" -eq 1 ]]; then + check_architecture fi } @@ -330,7 +412,7 @@ function check_root() { if [[ "$EUID" -ne 0 ]]; then echo -e "${RED}ERROR${NOFORMAT}" - die "This script requires running as root. Use sudo before the command." + panic "This script requires running as root. Use sudo before the command." else @@ -346,7 +428,7 @@ function check_os() { which apt-get >/dev/null if [[ $? -ne 0 ]]; then - die "Could not locate apt... this installation method will not work" + panic "Could not locate apt... this installation method will not work" fi echo -e -n "${BLUE}Checking for supported OS...${NOFORMAT}" @@ -407,7 +489,7 @@ function check_os() { # Check user input to proceed or not. if [[ "${PROCEED}" != "y" ]]; then - die "Answer was not y. Not proceeding." + panic "Answer was not y. Not proceeding." else echo -e "${GREEN}Proceeding...${NOFORMAT}" fi @@ -611,7 +693,9 @@ function run_playbook() { env_vars="python3_version=$PY3_VER codename=$CODENAME itype=$INSTALL_TYPE" env_vars="$env_vars fts_version=$FTS_VERSION cfg_rpath=$CFG_RPATH fts_venv=${FTS_VENV}" [[ -n "${FTS_IP_CUSTOM:-}" ]] && env_vars="$env_vars fts_ip_addr_extra=$FTS_IP_CUSTOM" + [[ -n "${PYPI_URL:-}" ]] && env_vars="$env_vars pypi_url=$PYPI_URL" [[ -n "${WEBMAP_FORCE_INSTALL:-}" ]] && env_vars="$env_vars $WEBMAP_FORCE_INSTALL" + [[ -n "${CORE:-}" ]] && pb=install_mainserver || pb=install_all echo -e "${BLUE}Running Ansible Playbook ${GREEN}$pb${BLUE}...${NOFORMAT}" ansible-playbook -u root ${pb}.yml \ @@ -627,6 +711,16 @@ function cleanup() { cp $HOME/nr-conf-temp $NEEDRESTART fi } + +########################################## +# Add the current user to the fts group. +########################################## +function join_fts_group() { + if [ -n "${SUDO_USER}" ]; then + adduser $SUDO_USER fts + fi +} + ############################################################################### # MAIN BUSINESS LOGIC HERE ############################################################################### @@ -634,8 +728,8 @@ function cleanup() { setup_colors parse_params "${@}" set_versions -check_os -# do_checks + +do_checks download_dependencies [[ "$DEFAULT_INSTALL_TYPE" == "$INSTALL_TYPE" ]] && install_python_environment handle_git_repository @@ -644,4 +738,6 @@ generate_key_pair [[ 0 -eq $DRY_RUN ]] || die "Dry run complete. Not running Ansible" 0 run_playbook + +join_fts_group cleanup