From 872b23be741665e31a677a2611512d93b54091b0 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 14 Feb 2024 17:30:09 -0800 Subject: [PATCH 01/27] BUG: make this work better from fresh install by expanding bootstrapping --- group_vars/tcbsd_plcs/vars.yml | 6 +- group_vars/tcbsd_vms/vars.yml | 6 +- .../{plc-tst-bsd => plc-tst-bsd1}/vars.yml | 9 +- host_vars/plc-tst-bsd2/vars.yml | 107 ++++++++++++++++++ inventory/plcs.yaml | 3 +- remote_bootstrap.sh | 50 ++++++++ tcbsd-bootstrap-playbook.yaml | 2 +- tcbsd-plc.yaml.template | 6 +- templates/home/Administrator/.bashrc | 17 ++- 9 files changed, 177 insertions(+), 29 deletions(-) rename host_vars/{plc-tst-bsd => plc-tst-bsd1}/vars.yml (95%) create mode 100644 host_vars/plc-tst-bsd2/vars.yml create mode 100644 remote_bootstrap.sh diff --git a/group_vars/tcbsd_plcs/vars.yml b/group_vars/tcbsd_plcs/vars.yml index 65ce6de..909e162 100644 --- a/group_vars/tcbsd_plcs/vars.yml +++ b/group_vars/tcbsd_plcs/vars.yml @@ -5,10 +5,8 @@ ansible_become_method: doas ansible_become_password: 1 # TODO: vault ansible_python_interpreter: /usr/local/bin/python3 -# FreeBSD packages are *required* at the moment for py39-lxml. -# Beckhoff may re-add py39-lxml in the future, so re-evaluate this at that -# point. -enable_freebsd_packages: true +# FreeBSD packages are no longer required, beckhoff added py39-lxml again. +enable_freebsd_packages: false # psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks use_psproxy: true diff --git a/group_vars/tcbsd_vms/vars.yml b/group_vars/tcbsd_vms/vars.yml index a1feeae..24ce2f8 100644 --- a/group_vars/tcbsd_vms/vars.yml +++ b/group_vars/tcbsd_vms/vars.yml @@ -5,10 +5,8 @@ ansible_become_method: doas ansible_become_password: 1 # TODO: vault ansible_python_interpreter: /usr/local/bin/python3 -# FreeBSD packages are *required* at the moment for py39-lxml. -# Beckhoff may re-add py39-lxml in the future, so re-evaluate this at that -# point. -enable_freebsd_packages: true +# FreeBSD packages are no longer required, beckhoff added py39-lxml again. +enable_freebsd_packages: false # psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks use_psproxy: false diff --git a/host_vars/plc-tst-bsd/vars.yml b/host_vars/plc-tst-bsd1/vars.yml similarity index 95% rename from host_vars/plc-tst-bsd/vars.yml rename to host_vars/plc-tst-bsd1/vars.yml index e6c1233..574f2e3 100644 --- a/host_vars/plc-tst-bsd/vars.yml +++ b/host_vars/plc-tst-bsd1/vars.yml @@ -9,22 +9,19 @@ tc_ams_net_id: 172.21.148.81.1.1 #ansible_become_password: 1 # TODO: vault #ansible_python_interpreter: /usr/local/bin/python3 # -## FreeBSD packages are *required* at the moment for py39-lxml. -## Beckhoff may re-add py39-lxml in the future, so re-evaluate this at that -## point. -#enable_freebsd_packages: true +## FreeBSD packages are no longer required, beckhoff added py39-lxml again. +#enable_freebsd_packages: false # ## psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks #use_psproxy: true #use_psntp: true # -# set static IP on x000 (mac id 2) +## set static IP on x000 (mac id 2) #x000_set_static_ip: true #x000_static_ip: 192.168.1.10 # ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options -#set_plc_timezone: true #plc_timezone: America/Los_Angeles # ## This is the default of 32MB. Set to 67108864 for 64MB of router memory. diff --git a/host_vars/plc-tst-bsd2/vars.yml b/host_vars/plc-tst-bsd2/vars.yml new file mode 100644 index 0000000..125f3a5 --- /dev/null +++ b/host_vars/plc-tst-bsd2/vars.yml @@ -0,0 +1,107 @@ +--- +ansible_host: 172.21.148.94 +tc_ams_net_id: 172.21.148.94.1.1 + +# Uncomment any setting below to override a default setting +#ansible_user: Administrator +#ansible_become: true +#ansible_become_method: doas +#ansible_become_password: 1 # TODO: vault +#ansible_python_interpreter: /usr/local/bin/python3 +# +## FreeBSD packages are no longer required, beckhoff added py39-lxml again. +#enable_freebsd_packages: false +# +## psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks +#use_psproxy: true +#use_psntp: true +# +## set static IP on x000 (mac id 2) +#x000_set_static_ip: true +#x000_static_ip: 192.168.1.10 +# +## We can set the PLC's timezone, which is largely cosmetic +## See /usr/share/zoneinfo/ on the PLC for options +#plc_timezone: America/Los_Angeles +# +## This is the default of 32MB. Set to 67108864 for 64MB of router memory. +#tc_locked_memory_size_bytes: 33554432 +# +## Heap memory size is not specified by default. If you wish to change the +## default, set this to greater than 0 (e.g., 1024). This must be +## greater than the locked memory size for the router, above. +#tc_heap_memory_size_mb: 2048 +## Install and use bash in place of sh: +#tc_use_bash: true +## Install C/C++ development tools (approximately 1.8GB): +#tc_install_cpp_dev_tools: true +# +## Packages to install: +#tc_libraries: +## - TC31-OrderNo # Mapping of TwinCAT order numbers to TC/BSD package names +## - TC31-TcIoPtp # TcIoPtp | TC3 Precise Time Protocol +## - TC31-TcOsSys # TwinCAT runtime component TcOsSys.dll and TwinCAT license text +## - TC31-XAR # TwinCAT System Service +## - TC31-XAR-EtherCATSlave # TwinCAT EtherCATSlave driver +## - TCBSD-CrossBuildSDK # SDK for TC/BSD cross-compilation +## - TCBSD-Install-Scripts # TCBSD installer scripts +## - TF1810-PLC-HMI-Web # TF1810 | TC3 PLC HMI Web +## - TF2000-HMI-Server # TF2000-HMI-Server +## - TF3300-Scope-Server-IoT # +## - TF3500-Analytics-Logger # TF3500 | TC3 Analytics Logger +## - TF360x-Condition-Monitoring # TF360x | TC3 Condition Monitoring +## - TF3650-Power-Monitoring # TF3650 | TC3 Power Monitoring +## - TF3800-Machine-Learning # TF3800 | TC3 Machine Learning +## - TF5000-NC-PTP # TwinCAT NC PTP driver +## - TF5100-NCI # TF5100 | TC3 NC I +## - TF5210-CNC-E # TF5210 | TC3 CNC E +## - TF5850-XTS-Technology # TF5850 | XTS Technology +## - TF6000-ADS-Comm-Lib # TF6000 | TC3 ADS Communication Library +## - TF6100-OPC-UA-beta # TF6100 | TC3 OPC UA +## - TF6230-Parallel-Redundancy-Protocol # TF6230 | TC3 Parallel Redundancy Protocol +## - TF6250-Modbus-TCP # TF6250 | TC3 Modbus TCP +## - TF627x-PROFINET-RT # TwinCAT PROFINET RT driver +## - TF6280-EtherNetIP # This package was replaces by TF628x-EthernetIP +## - TF628x-EtherNetIP # TwinCAT EtherNet/IP driver +#- TF6310-TCP-IP # TF6310 | TC3 TCP/IP +## - TF6340-Serial-Communication-beta # TF6340 | TC3 Serial Communication +## - TF6420-Database-Server # TF6420 | TC3 Database Server +## - TF6421-XML-Server # TF6421 | TC3 XML Server +## - TF6620-S7-Comm # TF6620 | S7 Communication +## - TF8020-BACnet # TwinCAT BACnet driver +## - TF8310-Wind-Framework # TF8310 | TC3 Wind Framework +# +#tc_tools_packages: +# - TcAdsTool # TcAdsTool | Use the power of ADS from your command line +# - TcAmsLogger # TwinCAT ADS Monitor - AMS Logger +# # - TcBackup # Tools to easily create and restore full system backups +# # - TcBackup-Gui-Installer # Tools to easily create and restore full system backups +# # - TcCoreConf # TwinCAT CPU core configuration tool +# # - TcCppUtils2.0 # +# # - TcEventLoggerAdsProxy # TcEventLoggerAdsProxy +# # - TcImportCert # TcImportCert | Import TwinCAT OEM certificate data into TwinCAT registry +# # - TcPalDrv # TwinCAT PAL driver +# # - TcTypeSystem2.7 # +# # - TcTypeSystem2.8 # +# # - TcUsb # TwinCAT USB driver +# +#tc_packages_to_install: +# - git +# - vim +# - ripgrep +# +## Packages only available via pip can be installed using this. +## py39-pip will only be installed if you marked it here. +## As far as the security implications go: well, that's up to you! +#tc_install_pip_packages: +## - pytmc +## Uninstall pip after using it? +#tc_uninstall_pip: true +# +## Configure the following static routes (and only those): +## NOTE: if you don't want to run my arbitrary module, use this instead +## of tc_add_missing_static_routes below +#tc_set_fixed_static_routes: [] +# +## Alternatively, only add missing routes from the list: +#tc_add_missing_static_routes: [] diff --git a/inventory/plcs.yaml b/inventory/plcs.yaml index 11ff64f..05106bb 100644 --- a/inventory/plcs.yaml +++ b/inventory/plcs.yaml @@ -9,7 +9,8 @@ tcbsd_plcs: tst_all: hosts: - plc-tst-bsd: + plc-tst-bsd1: + plc-tst-bsd2: vms_all: hosts: diff --git a/remote_bootstrap.sh b/remote_bootstrap.sh new file mode 100644 index 0000000..12d08fc --- /dev/null +++ b/remote_bootstrap.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# shellcheck disable=SC1078,SC1079,SC2140 +# Exit early if python 3 already installed +if test -e /usr/local/bin/python3; then + echo "python3 already installed" + exit +fi +# Exit early if running on linux by accident +if ! test -e /bin/freebsd-version; then + echo "not on bsd, whoops!" + exit +fi + +# setup psproxy if needed +if ! grep ANSIBLE /usr/local/etc/pkg.conf; then + echo " +# BEGIN ANSIBLE MANAGED BLOCK +PKG_ENV { + http_proxy: "http://psproxy:3128", + https_proxy: "http://psproxy:3128", +} +# END ANSIBLE MANAGED BLOCK +" >> /usr/local/etc/pkg.conf +fi + +# setup ntp if needed +if ! grep ANSIBLE /etc/ntp.conf; then + echo " +# BEGIN ANSIBLE MANAGED BLOCK +disable monitor + +# Permit time synchronization with our time source, but do not +# permit the source to query or modify the service on this system. +restrict default kod nomodify notrap nopeer noquery +restrict 127.0.0.1 + +server psntp1.pcdsn iburst +server psntp2.pcdsn iburst +server psntp3.pcdsn iburst +# END ANSIBLE MANAGED BLOCK +" >> /etc/ntp.conf + + # Stop ntp service, force a sync, start it again + service ntpd stop + ntpd -g -q + service ntpd start +fi + +# Install python 3 +pkg install -y python3 diff --git a/tcbsd-bootstrap-playbook.yaml b/tcbsd-bootstrap-playbook.yaml index 6ddbf67..238659f 100644 --- a/tcbsd-bootstrap-playbook.yaml +++ b/tcbsd-bootstrap-playbook.yaml @@ -4,4 +4,4 @@ tasks: - name: Bootstrap dependencies for ansible - ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg install -y python3 + ansible.builtin.script: remote_bootstrap.sh diff --git a/tcbsd-plc.yaml.template b/tcbsd-plc.yaml.template index 2279404..24d5c8b 100644 --- a/tcbsd-plc.yaml.template +++ b/tcbsd-plc.yaml.template @@ -9,10 +9,8 @@ tc_ams_net_id: ${PLC_NET_ID} #ansible_become_password: 1 # TODO: vault #ansible_python_interpreter: /usr/local/bin/python3 # -## FreeBSD packages are *required* at the moment for py39-lxml. -## Beckhoff may re-add py39-lxml in the future, so re-evaluate this at that -## point. -#enable_freebsd_packages: true +## FreeBSD packages are no longer required, beckhoff added py39-lxml again. +#enable_freebsd_packages: false # ## psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks #use_psproxy: true diff --git a/templates/home/Administrator/.bashrc b/templates/home/Administrator/.bashrc index 5409f35..31cf5ce 100644 --- a/templates/home/Administrator/.bashrc +++ b/templates/home/Administrator/.bashrc @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2139 # If not running interactively, don't do anything case $- in @@ -7,15 +8,13 @@ case $- in esac # Include Beckhoff defaults from sh: -# This has these aliases: -# alias h='fc -l' -# alias j=jobs -# alias m="$PAGER" -# alias ll='ls -laFo' -# alias l='ls -l' -# alias g='egrep -i' -# alias sudo=doas -[ -f "$HOME/.shrc" ] && source "$HOME/.shrc" +alias h='fc -l' +alias j=jobs +alias m="$PAGER" +alias ll='ls -laFo' +alias l='ls -l' +alias g='egrep -i' +alias sudo=doas # Include bash tab completion: [ -f " /usr/local/share/bash-completion/bash_completion.sh" ] && \ From 0fd4ae478da2d4f392ab99e8da1a560e383e6738 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 14:49:05 -0800 Subject: [PATCH 02/27] WIP: various improvements and other attempts --- host_vars/plc-tst-bsd1/vars.yml | 2 +- host_vars/plc-tst-bsd2/vars.yml | 2 +- inventory/plcs.yaml | 4 ++++ remote_bootstrap.sh | 2 ++ scripts/first_time_setup.sh | 10 ++++---- scripts/provision_plcs.sh | 3 ++- tcbsd-bootstrap-playbook.yaml | 41 +++++++++++++++++++++++++++++++-- 7 files changed, 55 insertions(+), 9 deletions(-) diff --git a/host_vars/plc-tst-bsd1/vars.yml b/host_vars/plc-tst-bsd1/vars.yml index 574f2e3..247c7a9 100644 --- a/host_vars/plc-tst-bsd1/vars.yml +++ b/host_vars/plc-tst-bsd1/vars.yml @@ -1,5 +1,5 @@ --- -ansible_host: 172.21.148.81 +ansible_host: plc-tst-bsd1 tc_ams_net_id: 172.21.148.81.1.1 # Uncomment any setting below to override a default setting diff --git a/host_vars/plc-tst-bsd2/vars.yml b/host_vars/plc-tst-bsd2/vars.yml index 125f3a5..bb7fe91 100644 --- a/host_vars/plc-tst-bsd2/vars.yml +++ b/host_vars/plc-tst-bsd2/vars.yml @@ -1,5 +1,5 @@ --- -ansible_host: 172.21.148.94 +ansible_host: plc-tst-bsd2 tc_ams_net_id: 172.21.148.94.1.1 # Uncomment any setting below to override a default setting diff --git a/inventory/plcs.yaml b/inventory/plcs.yaml index 05106bb..96d75e0 100644 --- a/inventory/plcs.yaml +++ b/inventory/plcs.yaml @@ -7,6 +7,10 @@ tcbsd_plcs: children: tst_all: +tmo_all: + hosts: + plc-tmo-tmp-vac: + tst_all: hosts: plc-tst-bsd1: diff --git a/remote_bootstrap.sh b/remote_bootstrap.sh index 12d08fc..c8c31cd 100644 --- a/remote_bootstrap.sh +++ b/remote_bootstrap.sh @@ -11,6 +11,8 @@ if ! test -e /bin/freebsd-version; then exit fi +set -e + # setup psproxy if needed if ! grep ANSIBLE /usr/local/etc/pkg.conf; then echo " diff --git a/scripts/first_time_setup.sh b/scripts/first_time_setup.sh index 60671f2..678e7d4 100755 --- a/scripts/first_time_setup.sh +++ b/scripts/first_time_setup.sh @@ -15,6 +15,7 @@ if [ -z "${1}" ]; then fi HOSTNAME="${1}" +shift THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" @@ -33,9 +34,10 @@ fi # Create vars, if they do not already exist VARS_PATH="${ANSIBLE_ROOT}/host_vars/${HOSTNAME}/vars.yml" if [ ! -f "${VARS_PATH}" ]; then - # Get the variables that the template is expecting - PLC_IP="$(getent hosts "${HOSTNAME}" | cut -f 1 -d " ")" - PLC_NET_ID="${PLC_IP}.1.1" + # Template uses IP, but hostname is also valid + PLC_IP="${HOSTNAME}" + RAW_IP="$(getent hosts "${HOSTNAME}" | cut -f 1 -d " ")" + PLC_NET_ID="${RAW_IP}.1.1" export PLC_IP export PLC_NET_ID mkdir -p "$(dirname "${VARS_PATH}")" @@ -64,4 +66,4 @@ fi # Run the bootstrap playbook TARGET="${HOSTNAME}" -ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" +ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" diff --git a/scripts/provision_plcs.sh b/scripts/provision_plcs.sh index 966d85b..d659dab 100755 --- a/scripts/provision_plcs.sh +++ b/scripts/provision_plcs.sh @@ -16,6 +16,7 @@ if [ -z "${1}" ]; then fi TARGET="${1}" +shift THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" @@ -29,4 +30,4 @@ if [ ! -x ansible-playbook ]; then fi # Run the provision playbook -ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" +ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" diff --git a/tcbsd-bootstrap-playbook.yaml b/tcbsd-bootstrap-playbook.yaml index 238659f..48071a0 100644 --- a/tcbsd-bootstrap-playbook.yaml +++ b/tcbsd-bootstrap-playbook.yaml @@ -3,5 +3,42 @@ gather_facts: False tasks: - - name: Bootstrap dependencies for ansible - ansible.builtin.script: remote_bootstrap.sh + - name: Configure psproxy if needed + ansible.builtin.raw: | + if ! grep ANSIBLE /usr/local/etc/pkg.conf; then + echo " + # BEGIN ANSIBLE MANAGED BLOCK + PKG_ENV { + http_proxy: "http://psproxy:3128", + https_proxy: "http://psproxy:3128", + } + # END ANSIBLE MANAGED BLOCK + " >> /usr/local/etc/pkg.conf + fi + + - name: Configure ntp if needed + ansible.builtin.raw: | + if ! grep ANSIBLE /etc/ntp.conf; then + echo " + # BEGIN ANSIBLE MANAGED BLOCK + disable monitor + + # Permit time synchronization with our time source, but do not + # permit the source to query or modify the service on this system. + restrict default kod nomodify notrap nopeer noquery + restrict 127.0.0.1 + + server psntp1.pcdsn iburst + server psntp2.pcdsn iburst + server psntp3.pcdsn iburst + # END ANSIBLE MANAGED BLOCK + " >> /etc/ntp.conf + + # Stop ntp service, force a sync, start it again + service ntpd stop + ntpd -g -q + service ntpd start + fi + + - name: Install Python3 if needed + ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg install -y python3 From 7672f1482b5bf3ce62d42e91f89842587885b877 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 14:52:35 -0800 Subject: [PATCH 03/27] REV: revert bootstrap playbook to only install python --- tcbsd-bootstrap-playbook.yaml | 39 +---------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/tcbsd-bootstrap-playbook.yaml b/tcbsd-bootstrap-playbook.yaml index 48071a0..6ddbf67 100644 --- a/tcbsd-bootstrap-playbook.yaml +++ b/tcbsd-bootstrap-playbook.yaml @@ -3,42 +3,5 @@ gather_facts: False tasks: - - name: Configure psproxy if needed - ansible.builtin.raw: | - if ! grep ANSIBLE /usr/local/etc/pkg.conf; then - echo " - # BEGIN ANSIBLE MANAGED BLOCK - PKG_ENV { - http_proxy: "http://psproxy:3128", - https_proxy: "http://psproxy:3128", - } - # END ANSIBLE MANAGED BLOCK - " >> /usr/local/etc/pkg.conf - fi - - - name: Configure ntp if needed - ansible.builtin.raw: | - if ! grep ANSIBLE /etc/ntp.conf; then - echo " - # BEGIN ANSIBLE MANAGED BLOCK - disable monitor - - # Permit time synchronization with our time source, but do not - # permit the source to query or modify the service on this system. - restrict default kod nomodify notrap nopeer noquery - restrict 127.0.0.1 - - server psntp1.pcdsn iburst - server psntp2.pcdsn iburst - server psntp3.pcdsn iburst - # END ANSIBLE MANAGED BLOCK - " >> /etc/ntp.conf - - # Stop ntp service, force a sync, start it again - service ntpd stop - ntpd -g -q - service ntpd start - fi - - - name: Install Python3 if needed + - name: Bootstrap dependencies for ansible ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg install -y python3 From b562126023a1f7eb2a141492a4f9b6dfdfa5122c Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 17:36:28 -0800 Subject: [PATCH 04/27] ENH: bootstrap by manually sending and installing python --- scripts/first_time_setup.sh | 36 +++++++++++++++++++----- scripts/provision_plcs.sh | 3 +- tcbsd-bootstrap-from-local-playbook.yaml | 7 +++++ 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 tcbsd-bootstrap-from-local-playbook.yaml diff --git a/scripts/first_time_setup.sh b/scripts/first_time_setup.sh index 678e7d4..862770b 100755 --- a/scripts/first_time_setup.sh +++ b/scripts/first_time_setup.sh @@ -9,11 +9,14 @@ # Expected usage, e.g. on the bsd test plc: # # $ ./first_time_setup.sh plc-tst-bsd +set -e + if [ -z "${1}" ]; then echo "Error: PLC name required" exit 1 fi +USERNAME="${PLC_USERNAME:=Administrator}" HOSTNAME="${1}" shift @@ -53,17 +56,36 @@ if [ ! -f "${SSH_KEY_FILENAME}" ]; then fi # Send the public key to the plc, if it has not already been done -ssh-copy-id -i "${SSH_KEY_FILENAME}" "${PLC_USERNAME:=Administrator}@${HOSTNAME}" +ssh-copy-id -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" # Check if we can log in using the key -ssh -i "${SSH_KEY_FILENAME}" "${PLC_USERNAME:=Administrator}@${HOSTNAME}" "echo key-based login test successful" +ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "echo key-based login test successful" + +# Check if python3 is installed +HAS_PYTHON="$(ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e /usr/local/bin/python3 && echo yes || echo no")" +if [ "${HAS_PYTHON}" == "yes" ]; then + echo "Already has python3, exiting" + exit +fi + +# Check the bsd os version +BSD_VER="$(ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "freebsd-version" | cut -d . -f 1)" +if [ "${BSD_VER}" == "13" ]; then + SOURCE_DIR="/cds/group/pcds/tcbsd/bootstrap/bsd13" +elif [ "${BSD_VER}" == "14" ]; then + SOURCE_DIR="/cds/group/pcds/tcbsd/bootstrap/bsd14" +else + echo "BSD version ${BSD_VER} not supported" + exit +fi + +# Copy the python packages over +scp -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then - # You should create a reasonable venv here, it just needs ansible - source "${THIS_DIR}/venv/bin/activate" + source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate fi -# Run the bootstrap playbook -TARGET="${HOSTNAME}" -ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" +# Run the local install version of the bootstrap playbook +ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" diff --git a/scripts/provision_plcs.sh b/scripts/provision_plcs.sh index d659dab..fe61bb6 100755 --- a/scripts/provision_plcs.sh +++ b/scripts/provision_plcs.sh @@ -25,8 +25,7 @@ SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then - # You should create a reasonable venv here, it just needs ansible - source "${THIS_DIR}/venv/bin/activate" + source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate fi # Run the provision playbook diff --git a/tcbsd-bootstrap-from-local-playbook.yaml b/tcbsd-bootstrap-from-local-playbook.yaml new file mode 100644 index 0000000..b6c9407 --- /dev/null +++ b/tcbsd-bootstrap-from-local-playbook.yaml @@ -0,0 +1,7 @@ +--- +- hosts: "{{ target }}" + gather_facts: False + + tasks: + - name: Bootstrap dependencies for ansible + ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg add /home/Administrator/bootstrap/python39-3.9.18.pkg /home/Administrator/bootstrap/python3-3_3.pkg From c4e5ff467aee80ef7bab8a38f355da0db4232ceb Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 18:16:54 -0800 Subject: [PATCH 05/27] ENH: fill out the inventory groups, generalize the bootstrap for all deps --- inventory/plcs.yaml | 37 ++++++++++++++++++++++++ tcbsd-bootstrap-from-local-playbook.yaml | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/inventory/plcs.yaml b/inventory/plcs.yaml index 96d75e0..cd4b9cd 100644 --- a/inventory/plcs.yaml +++ b/inventory/plcs.yaml @@ -5,12 +5,49 @@ plcs: tcbsd_plcs: children: + kfe_all: + tmo_all: + rix_all: + txi_all: + lfe_all: + xpp_all: + xcs_all: + mfx_all: + cxi_all: + mec_all: tst_all: +kfe_all: + hosts: + tmo_all: hosts: plc-tmo-tmp-vac: +rix_all: + hosts: + +txi_all: + hosts: + +lfe_all: + hosts: + +xpp_all: + hosts: + +xcs_all: + hosts: + +mfx_all: + hosts: + +cxi_all: + hosts: + +mec_all: + hosts: + tst_all: hosts: plc-tst-bsd1: diff --git a/tcbsd-bootstrap-from-local-playbook.yaml b/tcbsd-bootstrap-from-local-playbook.yaml index b6c9407..d048b51 100644 --- a/tcbsd-bootstrap-from-local-playbook.yaml +++ b/tcbsd-bootstrap-from-local-playbook.yaml @@ -4,4 +4,4 @@ tasks: - name: Bootstrap dependencies for ansible - ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg add /home/Administrator/bootstrap/python39-3.9.18.pkg /home/Administrator/bootstrap/python3-3_3.pkg + ansible.builtin.raw: test -e /usr/local/bin/python3 || pkg add /home/Administrator/bootstrap/*.pkg From b653793bcd4d09d0c1b8d7d258593b2fd5a4179b Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 18:17:25 -0800 Subject: [PATCH 06/27] WIP: include temporary tmo plc, for now --- host_vars/plc-tmo-tmp-vac/vars.yml | 107 +++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 host_vars/plc-tmo-tmp-vac/vars.yml diff --git a/host_vars/plc-tmo-tmp-vac/vars.yml b/host_vars/plc-tmo-tmp-vac/vars.yml new file mode 100644 index 0000000..6de5033 --- /dev/null +++ b/host_vars/plc-tmo-tmp-vac/vars.yml @@ -0,0 +1,107 @@ +--- +ansible_host: plc-tmo-tmp-vac +tc_ams_net_id: 172.21.132.78.1.1 + +# Uncomment any setting below to override a default setting +#ansible_user: Administrator +#ansible_become: true +#ansible_become_method: doas +#ansible_become_password: 1 # TODO: vault +#ansible_python_interpreter: /usr/local/bin/python3 +# +## FreeBSD packages are no longer required, beckhoff added py39-lxml again. +#enable_freebsd_packages: false +# +## psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks +#use_psproxy: true +#use_psntp: true +# +## set static IP on x000 (mac id 2) +#x000_set_static_ip: true +#x000_static_ip: 192.168.1.10 +# +## We can set the PLC's timezone, which is largely cosmetic +## See /usr/share/zoneinfo/ on the PLC for options +#plc_timezone: America/Los_Angeles +# +## This is the default of 32MB. Set to 67108864 for 64MB of router memory. +#tc_locked_memory_size_bytes: 33554432 +# +## Heap memory size is not specified by default. If you wish to change the +## default, set this to greater than 0 (e.g., 1024). This must be +## greater than the locked memory size for the router, above. +#tc_heap_memory_size_mb: 2048 +## Install and use bash in place of sh: +#tc_use_bash: true +## Install C/C++ development tools (approximately 1.8GB): +#tc_install_cpp_dev_tools: true +# +## Packages to install: +#tc_libraries: +## - TC31-OrderNo # Mapping of TwinCAT order numbers to TC/BSD package names +## - TC31-TcIoPtp # TcIoPtp | TC3 Precise Time Protocol +## - TC31-TcOsSys # TwinCAT runtime component TcOsSys.dll and TwinCAT license text +## - TC31-XAR # TwinCAT System Service +## - TC31-XAR-EtherCATSlave # TwinCAT EtherCATSlave driver +## - TCBSD-CrossBuildSDK # SDK for TC/BSD cross-compilation +## - TCBSD-Install-Scripts # TCBSD installer scripts +## - TF1810-PLC-HMI-Web # TF1810 | TC3 PLC HMI Web +## - TF2000-HMI-Server # TF2000-HMI-Server +## - TF3300-Scope-Server-IoT # +## - TF3500-Analytics-Logger # TF3500 | TC3 Analytics Logger +## - TF360x-Condition-Monitoring # TF360x | TC3 Condition Monitoring +## - TF3650-Power-Monitoring # TF3650 | TC3 Power Monitoring +## - TF3800-Machine-Learning # TF3800 | TC3 Machine Learning +## - TF5000-NC-PTP # TwinCAT NC PTP driver +## - TF5100-NCI # TF5100 | TC3 NC I +## - TF5210-CNC-E # TF5210 | TC3 CNC E +## - TF5850-XTS-Technology # TF5850 | XTS Technology +## - TF6000-ADS-Comm-Lib # TF6000 | TC3 ADS Communication Library +## - TF6100-OPC-UA-beta # TF6100 | TC3 OPC UA +## - TF6230-Parallel-Redundancy-Protocol # TF6230 | TC3 Parallel Redundancy Protocol +## - TF6250-Modbus-TCP # TF6250 | TC3 Modbus TCP +## - TF627x-PROFINET-RT # TwinCAT PROFINET RT driver +## - TF6280-EtherNetIP # This package was replaces by TF628x-EthernetIP +## - TF628x-EtherNetIP # TwinCAT EtherNet/IP driver +#- TF6310-TCP-IP # TF6310 | TC3 TCP/IP +## - TF6340-Serial-Communication-beta # TF6340 | TC3 Serial Communication +## - TF6420-Database-Server # TF6420 | TC3 Database Server +## - TF6421-XML-Server # TF6421 | TC3 XML Server +## - TF6620-S7-Comm # TF6620 | S7 Communication +## - TF8020-BACnet # TwinCAT BACnet driver +## - TF8310-Wind-Framework # TF8310 | TC3 Wind Framework +# +#tc_tools_packages: +# - TcAdsTool # TcAdsTool | Use the power of ADS from your command line +# - TcAmsLogger # TwinCAT ADS Monitor - AMS Logger +# # - TcBackup # Tools to easily create and restore full system backups +# # - TcBackup-Gui-Installer # Tools to easily create and restore full system backups +# # - TcCoreConf # TwinCAT CPU core configuration tool +# # - TcCppUtils2.0 # +# # - TcEventLoggerAdsProxy # TcEventLoggerAdsProxy +# # - TcImportCert # TcImportCert | Import TwinCAT OEM certificate data into TwinCAT registry +# # - TcPalDrv # TwinCAT PAL driver +# # - TcTypeSystem2.7 # +# # - TcTypeSystem2.8 # +# # - TcUsb # TwinCAT USB driver +# +#tc_packages_to_install: +# - git +# - vim +# - ripgrep +# +## Packages only available via pip can be installed using this. +## py39-pip will only be installed if you marked it here. +## As far as the security implications go: well, that's up to you! +#tc_install_pip_packages: +## - pytmc +## Uninstall pip after using it? +#tc_uninstall_pip: true +# +## Configure the following static routes (and only those): +## NOTE: if you don't want to run my arbitrary module, use this instead +## of tc_add_missing_static_routes below +#tc_set_fixed_static_routes: [] +# +## Alternatively, only add missing routes from the list: +#tc_add_missing_static_routes: [] From f1d65c320ed14286654a9cf2a445748f4557b1a5 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 22 Feb 2024 18:40:06 -0800 Subject: [PATCH 07/27] ENH: add helpful new_plc_all.sh script --- scripts/first_time_setup.sh | 8 +++++--- scripts/new_plc_all.sh | 20 ++++++++++++++++++++ scripts/provision_plcs.sh | 4 ++-- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100755 scripts/new_plc_all.sh diff --git a/scripts/first_time_setup.sh b/scripts/first_time_setup.sh index 862770b..00c9b48 100755 --- a/scripts/first_time_setup.sh +++ b/scripts/first_time_setup.sh @@ -6,9 +6,9 @@ # - and set us up for ssh key authentication with the plc # - run the bootstrap playbook, so that the provision playbook can run properly # -# Expected usage, e.g. on the bsd test plc: +# Expected usage, e.g. on a bsd test plc: # -# $ ./first_time_setup.sh plc-tst-bsd +# $ ./first_time_setup.sh plc-tst-bsd1 set -e if [ -z "${1}" ]; then @@ -79,7 +79,9 @@ else exit fi -# Copy the python packages over +# Remove any existing previous bootstrap folder +ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e ~/bootstrap && rm -rf ~/bootstrap" +# Copy the python packages and their dependencies over scp -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" # Activate python env if we don't have ansible on the path diff --git a/scripts/new_plc_all.sh b/scripts/new_plc_all.sh new file mode 100755 index 0000000..43f38b4 --- /dev/null +++ b/scripts/new_plc_all.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Run this script to prepare a plc and do the initial provisioning all in one go. +# This is more convenient for setting up a new PLC but cannot be run on inventory +# groups. +# +# Expected usage, e.g. on a bsd test plc: +# +# $ ./new_plc_all.sh plc-tst-bsd1 +set -e + +if [ -z "${1}" ]; then + echo "Error: PLC name required" + exit 1 +fi + +THIS_SCRIPT="$(realpath "${0}")" +THIS_DIR="$(dirname "${THIS_SCRIPT}")" + +"${THIS_DIR}"/first_time_setup.sh "${1}" +"${THIS_DIR}"/provision_plcs.sh "${1}" diff --git a/scripts/provision_plcs.sh b/scripts/provision_plcs.sh index fe61bb6..026a9af 100755 --- a/scripts/provision_plcs.sh +++ b/scripts/provision_plcs.sh @@ -1,9 +1,9 @@ #!/bin/bash # Run the ansible provision script on the designated plc or group of plcs. # -# To run on a single plc, e.g. the bsd test plc: +# To run on a single plc, e.g. a bsd test plc: # -# $ ./provision_plcs.sh plc-tst-bsd +# $ ./provision_plcs.sh plc-tst-bsd1 # # To run on a group of plcs, e.g. all of the tst plcs: # From 10961ffc76e4f98d2764654d8c51ce865aba60e7 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 23 Feb 2024 09:54:32 -0800 Subject: [PATCH 08/27] MAINT: remove no longer used script --- remote_bootstrap.sh | 52 --------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 remote_bootstrap.sh diff --git a/remote_bootstrap.sh b/remote_bootstrap.sh deleted file mode 100644 index c8c31cd..0000000 --- a/remote_bootstrap.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# shellcheck disable=SC1078,SC1079,SC2140 -# Exit early if python 3 already installed -if test -e /usr/local/bin/python3; then - echo "python3 already installed" - exit -fi -# Exit early if running on linux by accident -if ! test -e /bin/freebsd-version; then - echo "not on bsd, whoops!" - exit -fi - -set -e - -# setup psproxy if needed -if ! grep ANSIBLE /usr/local/etc/pkg.conf; then - echo " -# BEGIN ANSIBLE MANAGED BLOCK -PKG_ENV { - http_proxy: "http://psproxy:3128", - https_proxy: "http://psproxy:3128", -} -# END ANSIBLE MANAGED BLOCK -" >> /usr/local/etc/pkg.conf -fi - -# setup ntp if needed -if ! grep ANSIBLE /etc/ntp.conf; then - echo " -# BEGIN ANSIBLE MANAGED BLOCK -disable monitor - -# Permit time synchronization with our time source, but do not -# permit the source to query or modify the service on this system. -restrict default kod nomodify notrap nopeer noquery -restrict 127.0.0.1 - -server psntp1.pcdsn iburst -server psntp2.pcdsn iburst -server psntp3.pcdsn iburst -# END ANSIBLE MANAGED BLOCK -" >> /etc/ntp.conf - - # Stop ntp service, force a sync, start it again - service ntpd stop - ntpd -g -q - service ntpd start -fi - -# Install python 3 -pkg install -y python3 From e68da61059bb48dac9dce706a2c00574aea5a95d Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 27 Feb 2024 17:08:46 -0800 Subject: [PATCH 09/27] WIP: not quite working script to add new plcs to inventory --- scripts/add_to_inventory.py | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 scripts/add_to_inventory.py diff --git a/scripts/add_to_inventory.py b/scripts/add_to_inventory.py new file mode 100644 index 0000000..ff73e15 --- /dev/null +++ b/scripts/add_to_inventory.py @@ -0,0 +1,79 @@ +""" +Helper for adding new plc hosts to the inventory. +""" +from __future__ import annotations + +import argparse +from pathlib import Path +from ruamel import yaml + +Inventory = dict[str, dict] + +def get_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + prog="add_to_inventory.py", + description=__doc__, + ) + parser.add_argument("hostname", type=str) + parser.add_argument("--group", type=str, default="") + return parser + + +def load_inventory(path: str | Path) -> Inventory: + with Path(path).open("r") as fd: + return yaml.load(fd, Loader=yaml.RoundTripLoader) + + +def write_inventory(path: str | Path, inventory: Inventory) -> None: + with Path(path).open("w") as fd: + fd.write("---\n") + yaml.indent(mapping=2, sequence=4, offset=2) + yaml.dump( + inventory, + fd, + Dumper=yaml.RoundTripDumper, + ) + + +def host_in_inventory(hostname: str, inventory: Inventory) -> bool: + for dct in inventory.values(): + try: + if hostname in dct["hosts"]: + return True + except KeyError: + pass + return False + + +def add_host_to_group(hostname: str, group: str, inventory: Inventory) -> None: + hosts_in_group = list(inventory[group]["hosts"]) + hosts_in_group.append(hostname) + hosts_in_group.sort() + inventory[group]["hosts"] = {name: None for name in hosts_in_group} + + +def get_group_options(inventory: Inventory) -> list[str]: + return [key for key in inventory if key not in ("plcs", "tcbsd_plcs")] + + +def main(hostname: str, group: str = "") -> int: + inventory_path = Path(__file__).parent.parent / "inventory" / "plcs.yaml" + inventory = load_inventory(path=inventory_path) + options = get_group_options(inventory=inventory) + text_options = "\n".join(options) + while group not in options: + print(f"Please select a group from the following options:\n{text_options}") + group = input().strip() + print(f"Adding {hostname} to group {group}") + add_host_to_group(hostname=hostname, group=group, inventory=Inventory) + write_inventory(path=inventory_path, inventory=inventory) + return 0 + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + exit(main( + hostname=args.hostname, + group=args.group, + )) From 16214f1befd4ebe1cd9760f0bdbad0dd28b2c226 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 5 Mar 2024 16:15:30 -0800 Subject: [PATCH 10/27] ENH: finish inventory update script --- inventory/plcs.yaml | 13 ------------- scripts/add_to_inventory.py | 17 ++++++++--------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/inventory/plcs.yaml b/inventory/plcs.yaml index cd4b9cd..940be89 100644 --- a/inventory/plcs.yaml +++ b/inventory/plcs.yaml @@ -2,7 +2,6 @@ plcs: children: tcbsd_plcs: - tcbsd_plcs: children: kfe_all: @@ -16,43 +15,31 @@ tcbsd_plcs: cxi_all: mec_all: tst_all: - kfe_all: hosts: - tmo_all: hosts: plc-tmo-tmp-vac: - rix_all: hosts: - txi_all: hosts: - lfe_all: hosts: - xpp_all: hosts: - xcs_all: hosts: - mfx_all: hosts: - cxi_all: hosts: - mec_all: hosts: - tst_all: hosts: plc-tst-bsd1: plc-tst-bsd2: - vms_all: hosts: test-plc-01: diff --git a/scripts/add_to_inventory.py b/scripts/add_to_inventory.py index ff73e15..fc1797e 100644 --- a/scripts/add_to_inventory.py +++ b/scripts/add_to_inventory.py @@ -7,7 +7,7 @@ from pathlib import Path from ruamel import yaml -Inventory = dict[str, dict] +_Inventory = dict[str, dict] def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( @@ -19,15 +19,14 @@ def get_parser() -> argparse.ArgumentParser: return parser -def load_inventory(path: str | Path) -> Inventory: +def load_inventory(path: str | Path) -> _Inventory: with Path(path).open("r") as fd: return yaml.load(fd, Loader=yaml.RoundTripLoader) -def write_inventory(path: str | Path, inventory: Inventory) -> None: +def write_inventory(path: str | Path, inventory: _Inventory) -> None: with Path(path).open("w") as fd: fd.write("---\n") - yaml.indent(mapping=2, sequence=4, offset=2) yaml.dump( inventory, fd, @@ -35,7 +34,7 @@ def write_inventory(path: str | Path, inventory: Inventory) -> None: ) -def host_in_inventory(hostname: str, inventory: Inventory) -> bool: +def host_in_inventory(hostname: str, inventory: _Inventory) -> bool: for dct in inventory.values(): try: if hostname in dct["hosts"]: @@ -45,14 +44,14 @@ def host_in_inventory(hostname: str, inventory: Inventory) -> bool: return False -def add_host_to_group(hostname: str, group: str, inventory: Inventory) -> None: +def add_host_to_group(hostname: str, group: str, inventory: _Inventory) -> None: hosts_in_group = list(inventory[group]["hosts"]) hosts_in_group.append(hostname) hosts_in_group.sort() inventory[group]["hosts"] = {name: None for name in hosts_in_group} -def get_group_options(inventory: Inventory) -> list[str]: +def get_group_options(inventory: _Inventory) -> list[str]: return [key for key in inventory if key not in ("plcs", "tcbsd_plcs")] @@ -62,10 +61,10 @@ def main(hostname: str, group: str = "") -> int: options = get_group_options(inventory=inventory) text_options = "\n".join(options) while group not in options: - print(f"Please select a group from the following options:\n{text_options}") + print(f"Please select a group from the following options:\n{text_options}\n") group = input().strip() print(f"Adding {hostname} to group {group}") - add_host_to_group(hostname=hostname, group=group, inventory=Inventory) + add_host_to_group(hostname=hostname, group=group, inventory=inventory) write_inventory(path=inventory_path, inventory=inventory) return 0 From 84f72c6e3ac7304e937bfd04a8392c8a7781a892 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 5 Mar 2024 16:20:12 -0800 Subject: [PATCH 11/27] ENH: include add to inventory in new_plc_all --- scripts/new_plc_all.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/new_plc_all.sh b/scripts/new_plc_all.sh index 43f38b4..a7a2a9b 100755 --- a/scripts/new_plc_all.sh +++ b/scripts/new_plc_all.sh @@ -13,8 +13,14 @@ if [ -z "${1}" ]; then exit 1 fi +# Activate python env if we don't have ansible on the path +if [ ! -x ansible-playbook ]; then + source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate +fi + THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" +python "${THIS_DIR}"/add_to_inventory.py "${1}" "${THIS_DIR}"/first_time_setup.sh "${1}" "${THIS_DIR}"/provision_plcs.sh "${1}" From 3c0a88e4e845b5185433830672958dcfddb81fd1 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 5 Mar 2024 16:59:29 -0800 Subject: [PATCH 12/27] ENH: include an ssh config for plc connections --- ansible.cfg | 2 +- ssh_config | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 ssh_config diff --git a/ansible.cfg b/ansible.cfg index faaf123..6e60817 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -4,4 +4,4 @@ deprecation_warnings = True role_path = ./roles [ssh_connection] -ssh_args = +ssh_args = -F ./ssh_config diff --git a/ssh_config b/ssh_config new file mode 100644 index 0000000..bf9d5dc --- /dev/null +++ b/ssh_config @@ -0,0 +1,6 @@ +Host * + ForwardAgent no + ForwardX11 no + ForwardX11Trusted no + PreferredAuthentications=publickey,keyboard-interactive + User Administrator From a6142f4c6bfa30190a53f56a1c70e9e3e00a88df Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 5 Mar 2024 17:33:20 -0800 Subject: [PATCH 13/27] ENH: update script for newest ruamel.yaml API --- scripts/add_to_inventory.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/add_to_inventory.py b/scripts/add_to_inventory.py index fc1797e..5230481 100644 --- a/scripts/add_to_inventory.py +++ b/scripts/add_to_inventory.py @@ -5,10 +5,12 @@ import argparse from pathlib import Path -from ruamel import yaml +from ruamel.yaml import YAML +yaml = None _Inventory = dict[str, dict] + def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="add_to_inventory.py", @@ -19,18 +21,26 @@ def get_parser() -> argparse.ArgumentParser: return parser +def init_yaml(): + global yaml + yaml = YAML(typ="rt") + + def load_inventory(path: str | Path) -> _Inventory: + if yaml is None: + init_yaml() with Path(path).open("r") as fd: - return yaml.load(fd, Loader=yaml.RoundTripLoader) + return yaml.load(fd) def write_inventory(path: str | Path, inventory: _Inventory) -> None: + if yaml is None: + raise RuntimeError("Must load before dumping") with Path(path).open("w") as fd: fd.write("---\n") yaml.dump( inventory, fd, - Dumper=yaml.RoundTripDumper, ) From 892d830feb2179f17f9306ca47c0d71b2f18304e Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Tue, 5 Mar 2024 18:05:27 -0800 Subject: [PATCH 14/27] BUG: various fixes until the script runs through from nothing with no issues --- scripts/add_to_inventory.py | 5 ++++- scripts/first_time_setup.sh | 13 +++++++------ ssh_config | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/add_to_inventory.py b/scripts/add_to_inventory.py index 5230481..bba3bc3 100644 --- a/scripts/add_to_inventory.py +++ b/scripts/add_to_inventory.py @@ -49,7 +49,7 @@ def host_in_inventory(hostname: str, inventory: _Inventory) -> bool: try: if hostname in dct["hosts"]: return True - except KeyError: + except (KeyError, TypeError): pass return False @@ -68,6 +68,9 @@ def get_group_options(inventory: _Inventory) -> list[str]: def main(hostname: str, group: str = "") -> int: inventory_path = Path(__file__).parent.parent / "inventory" / "plcs.yaml" inventory = load_inventory(path=inventory_path) + if host_in_inventory(hostname=hostname, inventory=inventory): + print(f"{hostname} already in inventory, skipping!") + return 0 options = get_group_options(inventory=inventory) text_options = "\n".join(options) while group not in options: diff --git a/scripts/first_time_setup.sh b/scripts/first_time_setup.sh index 00c9b48..f7c3ae6 100755 --- a/scripts/first_time_setup.sh +++ b/scripts/first_time_setup.sh @@ -25,6 +25,7 @@ THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" INVENTORY_PATH="${ANSIBLE_ROOT}/inventory/plcs.yaml" +SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" # Check the inventory for your plc if grep -q "${HOSTNAME}:" "${INVENTORY_PATH}"; then @@ -56,20 +57,20 @@ if [ ! -f "${SSH_KEY_FILENAME}" ]; then fi # Send the public key to the plc, if it has not already been done -ssh-copy-id -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" +ssh-copy-id -i "${SSH_KEY_FILENAME}" -o PreferredAuthentications=keyboard-interactive "${USERNAME}@${HOSTNAME}" # Check if we can log in using the key -ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "echo key-based login test successful" +ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "echo key-based login test successful" # Check if python3 is installed -HAS_PYTHON="$(ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e /usr/local/bin/python3 && echo yes || echo no")" +HAS_PYTHON="$(ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e /usr/local/bin/python3 && echo yes || echo no")" if [ "${HAS_PYTHON}" == "yes" ]; then echo "Already has python3, exiting" exit fi # Check the bsd os version -BSD_VER="$(ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "freebsd-version" | cut -d . -f 1)" +BSD_VER="$(ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "freebsd-version" | cut -d . -f 1)" if [ "${BSD_VER}" == "13" ]; then SOURCE_DIR="/cds/group/pcds/tcbsd/bootstrap/bsd13" elif [ "${BSD_VER}" == "14" ]; then @@ -80,9 +81,9 @@ else fi # Remove any existing previous bootstrap folder -ssh -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e ~/bootstrap && rm -rf ~/bootstrap" +ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e ~/bootstrap && rm -rf ~/bootstrap || true" # Copy the python packages and their dependencies over -scp -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" +scp -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then diff --git a/ssh_config b/ssh_config index bf9d5dc..dc0d433 100644 --- a/ssh_config +++ b/ssh_config @@ -2,5 +2,5 @@ Host * ForwardAgent no ForwardX11 no ForwardX11Trusted no - PreferredAuthentications=publickey,keyboard-interactive + PreferredAuthentications=publickey User Administrator From 8d9eeafd3460e4f08dbd4a986925b0315db0c25f Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 14:46:17 -0800 Subject: [PATCH 15/27] ENH: automate default-templating host vars, rename scripts for clarity --- host_vars/plc-tmo-tmp-vac/vars.yml | 3 +- host_vars/plc-tst-bsd1/vars.yml | 3 +- host_vars/plc-tst-bsd2/vars.yml | 3 +- inventory/plcs.yaml | 2 +- scripts/add_to_inventory.py | 11 ++ .../{first_time_setup.sh => bootstrap_plc.sh} | 28 ++-- scripts/make_vars.py | 127 ++++++++++++++++++ .../{provision_plcs.sh => provision_plc.sh} | 0 scripts/{new_plc_all.sh => setup_new_plc.sh} | 7 +- tcbsd-plc.yaml.template | 104 -------------- 10 files changed, 158 insertions(+), 130 deletions(-) rename scripts/{first_time_setup.sh => bootstrap_plc.sh} (85%) create mode 100644 scripts/make_vars.py rename scripts/{provision_plcs.sh => provision_plc.sh} (100%) rename scripts/{new_plc_all.sh => setup_new_plc.sh} (76%) diff --git a/host_vars/plc-tmo-tmp-vac/vars.yml b/host_vars/plc-tmo-tmp-vac/vars.yml index 6de5033..b79e2d2 100644 --- a/host_vars/plc-tmo-tmp-vac/vars.yml +++ b/host_vars/plc-tmo-tmp-vac/vars.yml @@ -2,7 +2,7 @@ ansible_host: plc-tmo-tmp-vac tc_ams_net_id: 172.21.132.78.1.1 -# Uncomment any setting below to override a default setting +# Uncomment any setting below and change it to override a default setting. #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas @@ -22,6 +22,7 @@ tc_ams_net_id: 172.21.132.78.1.1 # ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options +#set_plc_timezone: true #plc_timezone: America/Los_Angeles # ## This is the default of 32MB. Set to 67108864 for 64MB of router memory. diff --git a/host_vars/plc-tst-bsd1/vars.yml b/host_vars/plc-tst-bsd1/vars.yml index 247c7a9..c91e554 100644 --- a/host_vars/plc-tst-bsd1/vars.yml +++ b/host_vars/plc-tst-bsd1/vars.yml @@ -2,7 +2,7 @@ ansible_host: plc-tst-bsd1 tc_ams_net_id: 172.21.148.81.1.1 -# Uncomment any setting below to override a default setting +# Uncomment any setting below and change it to override a default setting. #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas @@ -22,6 +22,7 @@ tc_ams_net_id: 172.21.148.81.1.1 # ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options +#set_plc_timezone: true #plc_timezone: America/Los_Angeles # ## This is the default of 32MB. Set to 67108864 for 64MB of router memory. diff --git a/host_vars/plc-tst-bsd2/vars.yml b/host_vars/plc-tst-bsd2/vars.yml index bb7fe91..edd6811 100644 --- a/host_vars/plc-tst-bsd2/vars.yml +++ b/host_vars/plc-tst-bsd2/vars.yml @@ -2,7 +2,7 @@ ansible_host: plc-tst-bsd2 tc_ams_net_id: 172.21.148.94.1.1 -# Uncomment any setting below to override a default setting +# Uncomment any setting below and change it to override a default setting. #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas @@ -22,6 +22,7 @@ tc_ams_net_id: 172.21.148.94.1.1 # ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options +#set_plc_timezone: true #plc_timezone: America/Los_Angeles # ## This is the default of 32MB. Set to 67108864 for 64MB of router memory. diff --git a/inventory/plcs.yaml b/inventory/plcs.yaml index 940be89..d2edd21 100644 --- a/inventory/plcs.yaml +++ b/inventory/plcs.yaml @@ -40,6 +40,6 @@ tst_all: hosts: plc-tst-bsd1: plc-tst-bsd2: -vms_all: +tcbsd_vms: hosts: test-plc-01: diff --git a/scripts/add_to_inventory.py b/scripts/add_to_inventory.py index bba3bc3..3a0337e 100644 --- a/scripts/add_to_inventory.py +++ b/scripts/add_to_inventory.py @@ -1,10 +1,14 @@ """ Helper for adding new plc hosts to the inventory. + +Hosts must be in the inventory to be managed with the ansible scripts. +Hosts can be assigned a group for batch operations. """ from __future__ import annotations import argparse from pathlib import Path + from ruamel.yaml import YAML yaml = None @@ -12,6 +16,7 @@ def get_parser() -> argparse.ArgumentParser: + """Return the parser used for CLI argument parsing.""" parser = argparse.ArgumentParser( prog="add_to_inventory.py", description=__doc__, @@ -22,11 +27,13 @@ def get_parser() -> argparse.ArgumentParser: def init_yaml(): + """Setup a reusable global yaml instance for round-trip reading and writing.""" global yaml yaml = YAML(typ="rt") def load_inventory(path: str | Path) -> _Inventory: + """Load the inventory from the inventory file.""" if yaml is None: init_yaml() with Path(path).open("r") as fd: @@ -34,6 +41,7 @@ def load_inventory(path: str | Path) -> _Inventory: def write_inventory(path: str | Path, inventory: _Inventory) -> None: + """Write the updated inventory back to the inventory file.""" if yaml is None: raise RuntimeError("Must load before dumping") with Path(path).open("w") as fd: @@ -45,6 +53,7 @@ def write_inventory(path: str | Path, inventory: _Inventory) -> None: def host_in_inventory(hostname: str, inventory: _Inventory) -> bool: + """Return True if hostname is in the inventory, and False otherwise.""" for dct in inventory.values(): try: if hostname in dct["hosts"]: @@ -55,6 +64,7 @@ def host_in_inventory(hostname: str, inventory: _Inventory) -> bool: def add_host_to_group(hostname: str, group: str, inventory: _Inventory) -> None: + """Add hostname to the inventory under the selected group.""" hosts_in_group = list(inventory[group]["hosts"]) hosts_in_group.append(hostname) hosts_in_group.sort() @@ -62,6 +72,7 @@ def add_host_to_group(hostname: str, group: str, inventory: _Inventory) -> None: def get_group_options(inventory: _Inventory) -> list[str]: + """Get a list of acceptable inventory options for group.""" return [key for key in inventory if key not in ("plcs", "tcbsd_plcs")] diff --git a/scripts/first_time_setup.sh b/scripts/bootstrap_plc.sh similarity index 85% rename from scripts/first_time_setup.sh rename to scripts/bootstrap_plc.sh index f7c3ae6..a500ba5 100755 --- a/scripts/first_time_setup.sh +++ b/scripts/bootstrap_plc.sh @@ -8,7 +8,7 @@ # # Expected usage, e.g. on a bsd test plc: # -# $ ./first_time_setup.sh plc-tst-bsd1 +# $ ./bootstrap_plc.sh plc-tst-bsd1 set -e if [ -z "${1}" ]; then @@ -16,10 +16,15 @@ if [ -z "${1}" ]; then exit 1 fi -USERNAME="${PLC_USERNAME:=Administrator}" HOSTNAME="${1}" shift +# Activate python env if we don't have ansible on the path +if [ ! -x ansible-playbook ]; then + source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate +fi + +USERNAME="${PLC_USERNAME:=Administrator}" THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" @@ -31,22 +36,14 @@ SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" if grep -q "${HOSTNAME}:" "${INVENTORY_PATH}"; then echo "Found ${HOSTNAME} in ${INVENTORY_PATH}." else - echo "Please add ${HOSTNAME} to ${INVENTORY_PATH} and re-run this script." - exit 1 + # Add PLC to inventory + python "${THIS_DIR}"/add_to_inventory.py "${1}" fi # Create vars, if they do not already exist VARS_PATH="${ANSIBLE_ROOT}/host_vars/${HOSTNAME}/vars.yml" if [ ! -f "${VARS_PATH}" ]; then - # Template uses IP, but hostname is also valid - PLC_IP="${HOSTNAME}" - RAW_IP="$(getent hosts "${HOSTNAME}" | cut -f 1 -d " ")" - PLC_NET_ID="${RAW_IP}.1.1" - export PLC_IP - export PLC_NET_ID - mkdir -p "$(dirname "${VARS_PATH}")" - envsubst < "${ANSIBLE_ROOT}/tcbsd-plc.yaml.template" > "${VARS_PATH}" - echo "Created ${VARS_PATH}, please edit this as needed for plc-specific settings." + python "${THIS_DIR}"/make_vars.py "${HOSTNAME}" else echo "${VARS_PATH} already exists, skipping creation." fi @@ -85,10 +82,5 @@ ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test # Copy the python packages and their dependencies over scp -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" -# Activate python env if we don't have ansible on the path -if [ ! -x ansible-playbook ]; then - source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate -fi - # Run the local install version of the bootstrap playbook ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" diff --git a/scripts/make_vars.py b/scripts/make_vars.py new file mode 100644 index 0000000..619d3af --- /dev/null +++ b/scripts/make_vars.py @@ -0,0 +1,127 @@ +""" +Script to make a host-specific vars.yml from the tcbsd-plc.yaml.template + +Includes the defaults for all variables as a commented-out section below, +for easy per-host reconfiguration. +""" +from __future__ import annotations + +import argparse +import socket +from typing import Iterator +from pathlib import Path +from string import Template + +from ruamel.yaml import YAML + +_Inventory = dict[str, dict] + + +def get_parser() -> argparse.ArgumentParser: + """Return the parser used for CLI argument parsing.""" + parser = argparse.ArgumentParser( + prog="make_vars.py", + description=__doc__, + ) + parser.add_argument("hostname", type=str) + return parser + + +def get_group( + hostname: str, + inventory_path: str | Path, + groups_path: str | Path, +) -> str: + """For a given hostname, get the name of the vars group it belongs to.""" + yaml = YAML() + with Path(inventory_path).open("r") as fd: + inventory_data = yaml.load(fd) + group_options = [path.name for path in Path(groups_path).glob("*")] + for group in group_options: + if hostname in iter_child_hosts(inventory_data=inventory_data, group=group): + return group + raise RuntimeError(f"Did not find {hostname} in any vars groups!") + + +def iter_child_hosts(inventory_data: _Inventory, group: str) -> Iterator[str]: + """Yield all the hostnames associated with a group.""" + group_data = inventory_data[group] + hosts_dicts = group_data.get("hosts") + if hosts_dicts is not None: + for hostname in hosts_dicts: + yield hostname + child_dicts = group_data.get("children") + if child_dicts is not None: + for child_group in child_dicts: + yield from iter_child_hosts( + inventory_data=inventory_data, + group=child_group, + ) + + +def get_netid(hostname: str) -> str: + """Get the expected AMS netid for a given hostname.""" + ipaddr = socket.gethostbyname(hostname) + return ipaddr + ".1.1" + + +def write_host_vars( + hostname: str, + host_vars_path: str | Path, + group_vars_path: str | Path, + template_path: str | Path, +) -> None: + """Write the vars.yml file given the necessary information.""" + # Load the template, sub in the values + with Path(template_path).open("r") as fd: + template = Template(fd.read()) + host_vars_text = template.substitute( + PLC_IP=hostname, + PLC_NET_ID=get_netid(hostname=hostname), + ) + # Load the group vars, prepend with comment + with Path(group_vars_path).open("r") as fd: + group_vars_lines = ["#" + line for line in fd.read().splitlines()[1:]] + # Write the new file + with Path(host_vars_path).open("w") as fd: + fd.write(host_vars_text) + fd.write( + "\n" + "# Uncomment any setting below and change it " + "to override a default setting." + "\n" + ) + fd.write("\n".join(group_vars_lines)) + fd.write("\n") + + +def main(hostname: str) -> int: + repo_root = Path(__file__).parent.parent + inventory_path = repo_root / "inventory" / "plcs.yaml" + groups_path = repo_root / "group_vars" + group = get_group( + hostname=hostname, + inventory_path=inventory_path, + groups_path=groups_path, + ) + group_vars_path = groups_path / group / "vars.yml" + template_path = repo_root / "tcbsd-plc.yaml.template" + host_vars_path = repo_root / "host_vars" / hostname / "vars.yml" + host_vars_path.parent.mkdir(exist_ok=True) + write_host_vars( + hostname=hostname, + host_vars_path=host_vars_path, + group_vars_path=group_vars_path, + template_path=template_path, + ) + print( + f"Created {host_vars_path}, " + "please edit this as needed for plc-specific settings." + ) + return 0 + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + exit(main(hostname=args.hostname)) diff --git a/scripts/provision_plcs.sh b/scripts/provision_plc.sh similarity index 100% rename from scripts/provision_plcs.sh rename to scripts/provision_plc.sh diff --git a/scripts/new_plc_all.sh b/scripts/setup_new_plc.sh similarity index 76% rename from scripts/new_plc_all.sh rename to scripts/setup_new_plc.sh index a7a2a9b..8190a05 100755 --- a/scripts/new_plc_all.sh +++ b/scripts/setup_new_plc.sh @@ -5,7 +5,7 @@ # # Expected usage, e.g. on a bsd test plc: # -# $ ./new_plc_all.sh plc-tst-bsd1 +# $ ./setup_new_plc.sh plc-tst-bsd1 set -e if [ -z "${1}" ]; then @@ -21,6 +21,5 @@ fi THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" -python "${THIS_DIR}"/add_to_inventory.py "${1}" -"${THIS_DIR}"/first_time_setup.sh "${1}" -"${THIS_DIR}"/provision_plcs.sh "${1}" +"${THIS_DIR}"/bootstrap_plc.sh "${1}" +"${THIS_DIR}"/provision_plc.sh "${1}" diff --git a/tcbsd-plc.yaml.template b/tcbsd-plc.yaml.template index 24d5c8b..6f25518 100644 --- a/tcbsd-plc.yaml.template +++ b/tcbsd-plc.yaml.template @@ -1,107 +1,3 @@ --- ansible_host: ${PLC_IP} tc_ams_net_id: ${PLC_NET_ID} - -# Uncomment any setting below to override a default setting -#ansible_user: Administrator -#ansible_become: true -#ansible_become_method: doas -#ansible_become_password: 1 # TODO: vault -#ansible_python_interpreter: /usr/local/bin/python3 -# -## FreeBSD packages are no longer required, beckhoff added py39-lxml again. -#enable_freebsd_packages: false -# -## psproxy and psntp are currently needed to get bsd and package updates while on the lcls cds networks -#use_psproxy: true -#use_psntp: true -# -## set static IP on x000 (mac id 2) -#x000_set_static_ip: true -#x000_static_ip: 192.168.1.10 -# -## We can set the PLC's timezone, which is largely cosmetic -## See /usr/share/zoneinfo/ on the PLC for options -#plc_timezone: America/Los_Angeles -# -## This is the default of 32MB. Set to 67108864 for 64MB of router memory. -#tc_locked_memory_size_bytes: 33554432 -# -## Heap memory size is not specified by default. If you wish to change the -## default, set this to greater than 0 (e.g., 1024). This must be -## greater than the locked memory size for the router, above. -#tc_heap_memory_size_mb: 2048 -## Install and use bash in place of sh: -#tc_use_bash: true -## Install C/C++ development tools (approximately 1.8GB): -#tc_install_cpp_dev_tools: true -# -## Packages to install: -#tc_libraries: -## - TC31-OrderNo # Mapping of TwinCAT order numbers to TC/BSD package names -## - TC31-TcIoPtp # TcIoPtp | TC3 Precise Time Protocol -## - TC31-TcOsSys # TwinCAT runtime component TcOsSys.dll and TwinCAT license text -## - TC31-XAR # TwinCAT System Service -## - TC31-XAR-EtherCATSlave # TwinCAT EtherCATSlave driver -## - TCBSD-CrossBuildSDK # SDK for TC/BSD cross-compilation -## - TCBSD-Install-Scripts # TCBSD installer scripts -## - TF1810-PLC-HMI-Web # TF1810 | TC3 PLC HMI Web -## - TF2000-HMI-Server # TF2000-HMI-Server -## - TF3300-Scope-Server-IoT # -## - TF3500-Analytics-Logger # TF3500 | TC3 Analytics Logger -## - TF360x-Condition-Monitoring # TF360x | TC3 Condition Monitoring -## - TF3650-Power-Monitoring # TF3650 | TC3 Power Monitoring -## - TF3800-Machine-Learning # TF3800 | TC3 Machine Learning -## - TF5000-NC-PTP # TwinCAT NC PTP driver -## - TF5100-NCI # TF5100 | TC3 NC I -## - TF5210-CNC-E # TF5210 | TC3 CNC E -## - TF5850-XTS-Technology # TF5850 | XTS Technology -## - TF6000-ADS-Comm-Lib # TF6000 | TC3 ADS Communication Library -## - TF6100-OPC-UA-beta # TF6100 | TC3 OPC UA -## - TF6230-Parallel-Redundancy-Protocol # TF6230 | TC3 Parallel Redundancy Protocol -## - TF6250-Modbus-TCP # TF6250 | TC3 Modbus TCP -## - TF627x-PROFINET-RT # TwinCAT PROFINET RT driver -## - TF6280-EtherNetIP # This package was replaces by TF628x-EthernetIP -## - TF628x-EtherNetIP # TwinCAT EtherNet/IP driver -#- TF6310-TCP-IP # TF6310 | TC3 TCP/IP -## - TF6340-Serial-Communication-beta # TF6340 | TC3 Serial Communication -## - TF6420-Database-Server # TF6420 | TC3 Database Server -## - TF6421-XML-Server # TF6421 | TC3 XML Server -## - TF6620-S7-Comm # TF6620 | S7 Communication -## - TF8020-BACnet # TwinCAT BACnet driver -## - TF8310-Wind-Framework # TF8310 | TC3 Wind Framework -# -#tc_tools_packages: -# - TcAdsTool # TcAdsTool | Use the power of ADS from your command line -# - TcAmsLogger # TwinCAT ADS Monitor - AMS Logger -# # - TcBackup # Tools to easily create and restore full system backups -# # - TcBackup-Gui-Installer # Tools to easily create and restore full system backups -# # - TcCoreConf # TwinCAT CPU core configuration tool -# # - TcCppUtils2.0 # -# # - TcEventLoggerAdsProxy # TcEventLoggerAdsProxy -# # - TcImportCert # TcImportCert | Import TwinCAT OEM certificate data into TwinCAT registry -# # - TcPalDrv # TwinCAT PAL driver -# # - TcTypeSystem2.7 # -# # - TcTypeSystem2.8 # -# # - TcUsb # TwinCAT USB driver -# -#tc_packages_to_install: -# - git -# - vim -# - ripgrep -# -## Packages only available via pip can be installed using this. -## py39-pip will only be installed if you marked it here. -## As far as the security implications go: well, that's up to you! -#tc_install_pip_packages: -## - pytmc -## Uninstall pip after using it? -#tc_uninstall_pip: true -# -## Configure the following static routes (and only those): -## NOTE: if you don't want to run my arbitrary module, use this instead -## of tc_add_missing_static_routes below -#tc_set_fixed_static_routes: [] -# -## Alternatively, only add missing routes from the list: -#tc_add_missing_static_routes: [] From b26180f9e6b0485e8387954522779eb5f0462dec Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 15:17:39 -0800 Subject: [PATCH 16/27] ENH: ensure hostname is set without needing a reboot --- tcbsd-provision-playbook.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tcbsd-provision-playbook.yaml b/tcbsd-provision-playbook.yaml index 1679100..d72d998 100644 --- a/tcbsd-provision-playbook.yaml +++ b/tcbsd-provision-playbook.yaml @@ -171,7 +171,7 @@ value: DW when: tc_heap_memory_size_mb > 0 - - name: Set the hostname + - name: Set the startup hostname ansible.builtin.lineinfile: dest: /etc/rc.conf regexp: '^hostname=' @@ -180,6 +180,10 @@ group: wheel mode: u=rw,g=r,o=r + - name: Set the live hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + - name: Change default shell for Administrator ansible.builtin.command: chsh -s /usr/local/bin/bash Administrator when: tc_use_bash From b422fdeff1a033afd62a8e5a9c86a252df12d439 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 16:35:53 -0800 Subject: [PATCH 17/27] ENH: add x001 static ip config and make ip config reversible --- group_vars/tcbsd_plcs/vars.yml | 4 ++ group_vars/tcbsd_vms/vars.yml | 4 ++ host_vars/plc-tmo-tmp-vac/vars.yml | 4 ++ host_vars/plc-tst-bsd1/vars.yml | 4 ++ host_vars/plc-tst-bsd2/vars.yml | 4 ++ tcbsd-provision-playbook.yaml | 62 ++++++++++++++++++++++++++++-- 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/group_vars/tcbsd_plcs/vars.yml b/group_vars/tcbsd_plcs/vars.yml index 909e162..0ce9223 100644 --- a/group_vars/tcbsd_plcs/vars.yml +++ b/group_vars/tcbsd_plcs/vars.yml @@ -16,6 +16,10 @@ use_psntp: true x000_set_static_ip: true x000_static_ip: 192.168.1.10 +# set static IP on x001 (mac id 1) +# Uses the DHCP assigned address, set statically +x001_set_static_ip: false + # We can set the PLC's timezone, which is largely cosmetic # See /usr/share/zoneinfo/ on the PLC for options set_plc_timezone: true diff --git a/group_vars/tcbsd_vms/vars.yml b/group_vars/tcbsd_vms/vars.yml index 24ce2f8..a6d6342 100644 --- a/group_vars/tcbsd_vms/vars.yml +++ b/group_vars/tcbsd_vms/vars.yml @@ -16,6 +16,10 @@ use_psntp: false x000_set_static_ip: false x000_static_ip: 192.168.1.10 +# set static IP on x001 (mac id 1) +# Uses the DHCP assigned address, set statically +x001_set_static_ip: false + # We can set the PLC's timezone, which is largely cosmetic # See /usr/share/zoneinfo/ on the PLC for options set_plc_timezone: false diff --git a/host_vars/plc-tmo-tmp-vac/vars.yml b/host_vars/plc-tmo-tmp-vac/vars.yml index b79e2d2..4ebc476 100644 --- a/host_vars/plc-tmo-tmp-vac/vars.yml +++ b/host_vars/plc-tmo-tmp-vac/vars.yml @@ -20,6 +20,10 @@ tc_ams_net_id: 172.21.132.78.1.1 #x000_set_static_ip: true #x000_static_ip: 192.168.1.10 # +## set static IP on x001 (mac id 1) +## Uses the DHCP assigned address, set statically +#x001_set_static_ip: false +# ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options #set_plc_timezone: true diff --git a/host_vars/plc-tst-bsd1/vars.yml b/host_vars/plc-tst-bsd1/vars.yml index c91e554..40363db 100644 --- a/host_vars/plc-tst-bsd1/vars.yml +++ b/host_vars/plc-tst-bsd1/vars.yml @@ -20,6 +20,10 @@ tc_ams_net_id: 172.21.148.81.1.1 #x000_set_static_ip: true #x000_static_ip: 192.168.1.10 # +## set static IP on x001 (mac id 1) +## Uses the DHCP assigned address, set statically +#x001_set_static_ip: false +# ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options #set_plc_timezone: true diff --git a/host_vars/plc-tst-bsd2/vars.yml b/host_vars/plc-tst-bsd2/vars.yml index edd6811..1f71d54 100644 --- a/host_vars/plc-tst-bsd2/vars.yml +++ b/host_vars/plc-tst-bsd2/vars.yml @@ -20,6 +20,10 @@ tc_ams_net_id: 172.21.148.94.1.1 #x000_set_static_ip: true #x000_static_ip: 192.168.1.10 # +## set static IP on x001 (mac id 1) +## Uses the DHCP assigned address, set statically +#x001_set_static_ip: false +# ## We can set the PLC's timezone, which is largely cosmetic ## See /usr/share/zoneinfo/ on the PLC for options #set_plc_timezone: true diff --git a/tcbsd-provision-playbook.yaml b/tcbsd-provision-playbook.yaml index d72d998..7f3015e 100644 --- a/tcbsd-provision-playbook.yaml +++ b/tcbsd-provision-playbook.yaml @@ -3,7 +3,7 @@ tasks: - name: Verify connectivity with ping - ping: + ansible.builtin.ping: - name: Enable FreeBSD packages when: enable_freebsd_packages @@ -255,8 +255,8 @@ state: restarted when: ams_net_id.changed or locked_memory_size.changed or heap_memory_size.changed - # We use the second port as a LAN port with a known static IP - # This makes it easy to use if we need it for e.g. doing service + # We use the second port as a LAN port with a known static IP + # This makes it easy to use if we need it for e.g. doing service - name: Set static IP on X000 when: x000_set_static_ip register: static_ip_x000_set @@ -264,7 +264,61 @@ name: ifconfig_igb1 value: "inet {{ x000_static_ip }} netmask 255.255.255.0" + - name: Set DHCP on X000 + when: not x000_set_static_ip + register: dhcp_x000_set + community.general.sysrc: + name: ifconfig_igb1 + state: absent + - name: Reset X000 - when: static_ip_x000_set.changed + when: static_ip_x000_set.changed or dhcp_x000_set.changed ansible.builtin.command: /etc/rc.d/netif restart igb1 changed_when: true + + # We use the first port as a the main CDS port with a DNS-defined IP + # Currently we use DHCP, but we could instead set a static IP using this + - name: Get static IP details for X001 + when: x001_set_static_ip + register: x001_ip_details + ansible.builtin.shell: + executable: /usr/local/bin/bash + cmd: ifconfig igb0 inet | grep inet | cut -f 2 | cut -f 1-4 -d " " + + - name: Set static IP on X001 + when: x001_set_static_ip + register: static_ip_x001_set + community.general.sysrc: + name: ifconfig_igb0 + value: "{{ x001_ip_details.stdout }}" + + - name: Set DHCP on X001 + when: not x001_set_static_ip + register: dhcp_x001_set + community.general.sysrc: + name: ifconfig_igb0 + state: absent + + # Note: we have to reset X001 asynchronously + # Otherwise, we just drop our connection and hang + # because we are using X001 to access the plc + - name: Reset X001 (async, static) + when: static_ip_x001_set.changed + ansible.builtin.shell: + executable: /usr/local/bin/bash + cmd: "sleep 1; /etc/rc.d/netif restart igb0 &" + async: 100 + poll: 0 + + - name: Reset X001 (async, dhcp) + when: dhcp_x001_set.changed + ansible.builtin.shell: + executable: /usr/local/bin/bash + cmd: "sleep 1; dhclient igb0 &" + async: 100 + poll: 0 + + - name: Wait for X001 network to resume + when: static_ip_x001_set.changed or dhcp_x001_set.changed + ansible.builtin.wait_for_connection: + delay: 2 From 3d9592a4f941c98ec372cab64332e8d76aa31471 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 16:57:45 -0800 Subject: [PATCH 18/27] ENH: add script for dry-running, make dry-run work without failing --- scripts/dry_run.sh | 25 +++++++++++++++++++++++++ tcbsd-provision-playbook.yaml | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100755 scripts/dry_run.sh diff --git a/scripts/dry_run.sh b/scripts/dry_run.sh new file mode 100755 index 0000000..56dab27 --- /dev/null +++ b/scripts/dry_run.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Check what would happen if the ansible provision script was run. +# +# To run on a single plc, e.g. a bsd test plc: +# +# $ ./dry_run.sh plc-tst-bsd1 +# +# To run on a group of plcs, e.g. all of the tst plcs: +# +# $ ./dry_run.sh tst_all +# +# Groups are defined in the inventory file. +if [ -z "${1}" ]; then + echo "Ansible target required" + exit 1 +fi + +TARGET="${1}" +shift + +THIS_SCRIPT="$(realpath "${0}")" +THIS_DIR="$(dirname "${THIS_SCRIPT}")" + +echo "Running provision_plc.sh in dry-run mode (--check, --diff)" +"${THIS_DIR}"/provision_plc.sh "${TARGET}" --check --diff "$@" diff --git a/tcbsd-provision-playbook.yaml b/tcbsd-provision-playbook.yaml index 7f3015e..4f2c861 100644 --- a/tcbsd-provision-playbook.yaml +++ b/tcbsd-provision-playbook.yaml @@ -307,7 +307,7 @@ ansible.builtin.shell: executable: /usr/local/bin/bash cmd: "sleep 1; /etc/rc.d/netif restart igb0 &" - async: 100 + async: "{{ ansible_check_mode | ternary(0, 100) }}" poll: 0 - name: Reset X001 (async, dhcp) @@ -315,7 +315,7 @@ ansible.builtin.shell: executable: /usr/local/bin/bash cmd: "sleep 1; dhclient igb0 &" - async: 100 + async: "{{ ansible_check_mode | ternary(0, 100) }}" poll: 0 - name: Wait for X001 network to resume From f71a06ab979bda069025ff6f2caebbb90421ef55 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 16:58:00 -0800 Subject: [PATCH 19/27] DOC: typo after script name change --- scripts/provision_plc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index 026a9af..37f7bec 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -3,11 +3,11 @@ # # To run on a single plc, e.g. a bsd test plc: # -# $ ./provision_plcs.sh plc-tst-bsd1 +# $ ./provision_plc.sh plc-tst-bsd1 # # To run on a group of plcs, e.g. all of the tst plcs: # -# $ ./provision_plcs.sh tst_all +# $ ./provision_plc.sh tst_all # # Groups are defined in the inventory file. if [ -z "${1}" ]; then From a2e292f240664f1e9a3328293c04299a0e1f7629 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 17:09:15 -0800 Subject: [PATCH 20/27] ENH: require manually providing the doas password --- group_vars/tcbsd_plcs/vars.yml | 1 - host_vars/plc-tmo-tmp-vac/vars.yml | 1 - host_vars/plc-tst-bsd1/vars.yml | 1 - host_vars/plc-tst-bsd2/vars.yml | 1 - scripts/bootstrap_plc.sh | 2 +- scripts/provision_plc.sh | 2 +- 6 files changed, 2 insertions(+), 6 deletions(-) diff --git a/group_vars/tcbsd_plcs/vars.yml b/group_vars/tcbsd_plcs/vars.yml index 0ce9223..7bd2c3d 100644 --- a/group_vars/tcbsd_plcs/vars.yml +++ b/group_vars/tcbsd_plcs/vars.yml @@ -2,7 +2,6 @@ ansible_user: Administrator ansible_become: true ansible_become_method: doas -ansible_become_password: 1 # TODO: vault ansible_python_interpreter: /usr/local/bin/python3 # FreeBSD packages are no longer required, beckhoff added py39-lxml again. diff --git a/host_vars/plc-tmo-tmp-vac/vars.yml b/host_vars/plc-tmo-tmp-vac/vars.yml index 4ebc476..067140f 100644 --- a/host_vars/plc-tmo-tmp-vac/vars.yml +++ b/host_vars/plc-tmo-tmp-vac/vars.yml @@ -6,7 +6,6 @@ tc_ams_net_id: 172.21.132.78.1.1 #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas -#ansible_become_password: 1 # TODO: vault #ansible_python_interpreter: /usr/local/bin/python3 # ## FreeBSD packages are no longer required, beckhoff added py39-lxml again. diff --git a/host_vars/plc-tst-bsd1/vars.yml b/host_vars/plc-tst-bsd1/vars.yml index 40363db..2e07f53 100644 --- a/host_vars/plc-tst-bsd1/vars.yml +++ b/host_vars/plc-tst-bsd1/vars.yml @@ -6,7 +6,6 @@ tc_ams_net_id: 172.21.148.81.1.1 #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas -#ansible_become_password: 1 # TODO: vault #ansible_python_interpreter: /usr/local/bin/python3 # ## FreeBSD packages are no longer required, beckhoff added py39-lxml again. diff --git a/host_vars/plc-tst-bsd2/vars.yml b/host_vars/plc-tst-bsd2/vars.yml index 1f71d54..65e1489 100644 --- a/host_vars/plc-tst-bsd2/vars.yml +++ b/host_vars/plc-tst-bsd2/vars.yml @@ -6,7 +6,6 @@ tc_ams_net_id: 172.21.148.94.1.1 #ansible_user: Administrator #ansible_become: true #ansible_become_method: doas -#ansible_become_password: 1 # TODO: vault #ansible_python_interpreter: /usr/local/bin/python3 # ## FreeBSD packages are no longer required, beckhoff added py39-lxml again. diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index a500ba5..6801cf9 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -83,4 +83,4 @@ ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test scp -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@${HOSTNAME}:~/bootstrap" # Run the local install version of the bootstrap playbook -ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" +ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index 37f7bec..e1447cb 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -29,4 +29,4 @@ if [ ! -x ansible-playbook ]; then fi # Run the provision playbook -ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" "$@" +ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" From d286c9312904d681189cb410513b02dc7064a2df Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 18:20:03 -0800 Subject: [PATCH 21/27] ENH: add helpers for updating the admin password --- scripts/bootstrap_plc.sh | 9 +++++++++ scripts/update_admin_pass.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 scripts/update_admin_pass.sh diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index 6801cf9..fe4245d 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -59,6 +59,15 @@ ssh-copy-id -i "${SSH_KEY_FILENAME}" -o PreferredAuthentications=keyboard-intera # Check if we can log in using the key ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "echo key-based login test successful" +# Check if the default password has been changed and prompt us to change it +PASS_WARNING="$(ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -x /home/Administrator/.default_warning && /home/Administrator/.default_warning || true")" +if [ -n "${PASS_WARNING}" ]; then + echo "Please change the default password to the standard admin password." + ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -t "${USERNAME}@${HOSTNAME}" passwd +else + echo "Password has been changed from default." +fi + # Check if python3 is installed HAS_PYTHON="$(ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" "${USERNAME}@${HOSTNAME}" "test -e /usr/local/bin/python3 && echo yes || echo no")" if [ "${HAS_PYTHON}" == "yes" ]; then diff --git a/scripts/update_admin_pass.sh b/scripts/update_admin_pass.sh new file mode 100755 index 0000000..ae3e43f --- /dev/null +++ b/scripts/update_admin_pass.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Helper script for updating the admin password on some of or all of the PLCs. +# This is meant to be used when we change the admin password. +# Despite being a script, this is still a manual process. +# You will be prompted for the old password, the new password, and to retype the new password on each plc. +# +# Expected usage, e.g. on a bsd test plc: +# +# $ ./update_admin_pass plc-tst-bsd1 +# +# On a few test plcs: +# +# $ ./update_admin_pass plc-tst-bsd1 plc-tst-bsd2 +set -e + +if [ -z "${1}" ]; then + echo "Error: At least one PLC name required" + exit 1 +fi + +USERNAME="${PLC_USERNAME:=Administrator}" +THIS_SCRIPT="$(realpath "${0}")" +THIS_DIR="$(dirname "${THIS_SCRIPT}")" +ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" +SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" +SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" + +for HOSTNAME in "$@"; do + echo "Logging into ${HOSTNAME}" + ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -t "${USERNAME}@${HOSTNAME}" passwd +done From 890bff386138d3fd7937cc0dae2f2e517f65ca84 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Mar 2024 19:06:55 -0800 Subject: [PATCH 22/27] ENH: add ssh agent helper and begin using it in other scripts --- scripts/bootstrap_plc.sh | 5 +++++ scripts/dry_run.sh | 5 +++++ scripts/provision_plc.sh | 5 +++++ scripts/setup_new_plc.sh | 9 ++++----- scripts/ssh_agent_helper.sh | 32 ++++++++++++++++++++++++++++++++ scripts/update_admin_pass.sh | 5 +++++ 6 files changed, 56 insertions(+), 5 deletions(-) create mode 100755 scripts/ssh_agent_helper.sh diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index fe4245d..07d0b2c 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -53,6 +53,9 @@ if [ ! -f "${SSH_KEY_FILENAME}" ]; then ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" fi +# Register the ssh key with the ssh agent if needed. +source "${THIS_DIR}/ssh_agent_helper.sh" + # Send the public key to the plc, if it has not already been done ssh-copy-id -i "${SSH_KEY_FILENAME}" -o PreferredAuthentications=keyboard-interactive "${USERNAME}@${HOSTNAME}" @@ -93,3 +96,5 @@ scp -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@ # Run the local install version of the bootstrap playbook ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" + +# TODO stop the ssh agent if we started it here diff --git a/scripts/dry_run.sh b/scripts/dry_run.sh index 56dab27..328654d 100755 --- a/scripts/dry_run.sh +++ b/scripts/dry_run.sh @@ -21,5 +21,10 @@ shift THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" +# Register the ssh key with the ssh agent if needed. +source "${THIS_DIR}/ssh_agent_helper.sh" + echo "Running provision_plc.sh in dry-run mode (--check, --diff)" "${THIS_DIR}"/provision_plc.sh "${TARGET}" --check --diff "$@" + +# TODO stop the ssh agent if we started it here diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index e1447cb..cc66c8e 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -23,6 +23,9 @@ THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" +# Register the ssh key with the ssh agent if needed. +source "${THIS_DIR}/ssh_agent_helper.sh" + # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate @@ -30,3 +33,5 @@ fi # Run the provision playbook ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" + +# TODO stop the ssh agent if we started it here diff --git a/scripts/setup_new_plc.sh b/scripts/setup_new_plc.sh index 8190a05..7136769 100755 --- a/scripts/setup_new_plc.sh +++ b/scripts/setup_new_plc.sh @@ -13,13 +13,12 @@ if [ -z "${1}" ]; then exit 1 fi -# Activate python env if we don't have ansible on the path -if [ ! -x ansible-playbook ]; then - source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate -fi - THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" +# Register the ssh key with the ssh agent if needed. +source "${THIS_DIR}/ssh_agent_helper.sh" + +# Run both playbooks and one-time pre-playbook setup "${THIS_DIR}"/bootstrap_plc.sh "${1}" "${THIS_DIR}"/provision_plc.sh "${1}" diff --git a/scripts/ssh_agent_helper.sh b/scripts/ssh_agent_helper.sh new file mode 100755 index 0000000..b8a90fc --- /dev/null +++ b/scripts/ssh_agent_helper.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Helper script for starting the ssh agent if needed and doing an ssh-add. +# This will let anyone smoothly run the ansible scripts without multiple password prompts. +# This script is intended to be sourced. +# Sourcing this script lets ssh-agent set the proper environment variables it needs to run properly. +# +# Expected usage: +# +# source ssh_agent_helper.sh + +THIS_SCRIPT="$(realpath "${BASH_SOURCE[0]}")" +THIS_DIR="$(dirname "${THIS_SCRIPT}")" +ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" +SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" + +# Multipurpose check: return code is 1 if the command fails, 2 if cannot connect to agent. +# I'm not sure if need to differentiate between these cases +if PUBKEYS="$(ssh-add -L)"; then + # Success, check output for pub key + TCBSD_PUB_KEY="$(cut -f 2 -d " " "${SSH_KEY_FILENAME}.pub")" + if [[ "${PUBKEYS}" == *"${TCBSD_PUB_KEY}"* ]]; then + echo "TcBSD key already registered with ssh agent" + return 0 + fi +else + # Failed, start the ssh agent + echo "Starting ssh agent" + eval "$(ssh-agent -s)" +fi +# If we got this far, run ssh-add +echo "Running ssh-add, will prompt for PLC admin password:" +ssh-add "${SSH_KEY_FILENAME}" diff --git a/scripts/update_admin_pass.sh b/scripts/update_admin_pass.sh index ae3e43f..9d51752 100755 --- a/scripts/update_admin_pass.sh +++ b/scripts/update_admin_pass.sh @@ -25,7 +25,12 @@ ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" +# Register the ssh key with the ssh agent if needed. +source "${THIS_DIR}/ssh_agent_helper.sh" + for HOSTNAME in "$@"; do echo "Logging into ${HOSTNAME}" ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -t "${USERNAME}@${HOSTNAME}" passwd done + +# TODO stop the ssh agent if we started it here From 7be3b178a77aa4b32471d6312f178f072d6e8472 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 8 Mar 2024 14:28:14 -0800 Subject: [PATCH 23/27] ENH: clean up ssh agent if it was automatically created --- scripts/bootstrap_plc.sh | 5 +++-- scripts/dry_run.sh | 5 ----- scripts/provision_plc.sh | 9 +++++---- scripts/setup_new_plc.sh | 8 +++++++- scripts/ssh_agent_helper.sh | 20 +++++++++++++++++++- scripts/update_admin_pass.sh | 5 +++-- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index 07d0b2c..7164196 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -53,7 +53,7 @@ if [ ! -f "${SSH_KEY_FILENAME}" ]; then ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" fi -# Register the ssh key with the ssh agent if needed. +# Register the ssh key with the ssh agent if needed source "${THIS_DIR}/ssh_agent_helper.sh" # Send the public key to the plc, if it has not already been done @@ -97,4 +97,5 @@ scp -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -r "${SOURCE_DIR}" "${USERNAME}@ # Run the local install version of the bootstrap playbook ansible-playbook "${ANSIBLE_ROOT}/tcbsd-bootstrap-from-local-playbook.yaml" --extra-vars "target=${HOSTNAME} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" -# TODO stop the ssh agent if we started it here +# Stop the ssh agent if we started it here +ssh_agent_helper_cleanup diff --git a/scripts/dry_run.sh b/scripts/dry_run.sh index 328654d..56dab27 100755 --- a/scripts/dry_run.sh +++ b/scripts/dry_run.sh @@ -21,10 +21,5 @@ shift THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" -# Register the ssh key with the ssh agent if needed. -source "${THIS_DIR}/ssh_agent_helper.sh" - echo "Running provision_plc.sh in dry-run mode (--check, --diff)" "${THIS_DIR}"/provision_plc.sh "${TARGET}" --check --diff "$@" - -# TODO stop the ssh agent if we started it here diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index cc66c8e..2c6a08d 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -23,15 +23,16 @@ THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" -# Register the ssh key with the ssh agent if needed. -source "${THIS_DIR}/ssh_agent_helper.sh" - # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate fi +# Register the ssh key with the ssh agent if needed +source "${THIS_DIR}/ssh_agent_helper.sh" + # Run the provision playbook ansible-playbook "${ANSIBLE_ROOT}/tcbsd-provision-playbook.yaml" --extra-vars "target=${TARGET} ansible_ssh_private_key_file=${SSH_KEY_FILENAME}" --ask-become-pass "$@" -# TODO stop the ssh agent if we started it here +# Stop the ssh agent if we started it here +ssh_agent_helper_cleanup diff --git a/scripts/setup_new_plc.sh b/scripts/setup_new_plc.sh index 7136769..19ca864 100755 --- a/scripts/setup_new_plc.sh +++ b/scripts/setup_new_plc.sh @@ -16,9 +16,15 @@ fi THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" -# Register the ssh key with the ssh agent if needed. +# Register the ssh key with the ssh agent if needed source "${THIS_DIR}/ssh_agent_helper.sh" # Run both playbooks and one-time pre-playbook setup "${THIS_DIR}"/bootstrap_plc.sh "${1}" "${THIS_DIR}"/provision_plc.sh "${1}" + +# Stop the ssh agent if we started it here +if [ "${HELPER_STARTED_AGENT}" = "YES" ] && [ -n "${SSH_AGENT_PID}" ]; then + echo "Cleaning up SSH agent." + kill "${SSH_AGENT_PID}" +fi diff --git a/scripts/ssh_agent_helper.sh b/scripts/ssh_agent_helper.sh index b8a90fc..7ffbf90 100755 --- a/scripts/ssh_agent_helper.sh +++ b/scripts/ssh_agent_helper.sh @@ -12,6 +12,23 @@ THIS_SCRIPT="$(realpath "${BASH_SOURCE[0]}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" +HELPER_STARTED_AGENT="NO" +export HELPER_STARTED_AGENT + +# Define an exportable helper for cleaning up the SSH agent +ssh_agent_helper_cleanup() { + if [ "${HELPER_STARTED_AGENT}" = "YES" ] && [ -n "${SSH_AGENT_PID}" ]; then + echo "Cleaning up SSH agent" + kill "${SSH_AGENT_PID}" + unset HELPER_STARTED_AGENT + unset SSH_AGENT_PID + unset SSH_AUTH_SOCK + export HELPER_STARTED_AGENT + export SSH_AGENT_PID + export SSH_AUTH_SOCK + fi +} +export ssh_agent_helper_cleanup # Multipurpose check: return code is 1 if the command fails, 2 if cannot connect to agent. # I'm not sure if need to differentiate between these cases @@ -19,13 +36,14 @@ if PUBKEYS="$(ssh-add -L)"; then # Success, check output for pub key TCBSD_PUB_KEY="$(cut -f 2 -d " " "${SSH_KEY_FILENAME}.pub")" if [[ "${PUBKEYS}" == *"${TCBSD_PUB_KEY}"* ]]; then - echo "TcBSD key already registered with ssh agent" + echo "TcBSD key is registered with ssh agent" return 0 fi else # Failed, start the ssh agent echo "Starting ssh agent" eval "$(ssh-agent -s)" + HELPER_STARTED_AGENT="YES" fi # If we got this far, run ssh-add echo "Running ssh-add, will prompt for PLC admin password:" diff --git a/scripts/update_admin_pass.sh b/scripts/update_admin_pass.sh index 9d51752..c698fe8 100755 --- a/scripts/update_admin_pass.sh +++ b/scripts/update_admin_pass.sh @@ -25,7 +25,7 @@ ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" -# Register the ssh key with the ssh agent if needed. +# Register the ssh key with the ssh agent if needed source "${THIS_DIR}/ssh_agent_helper.sh" for HOSTNAME in "$@"; do @@ -33,4 +33,5 @@ for HOSTNAME in "$@"; do ssh -F "${SSH_CONFIG}" -i "${SSH_KEY_FILENAME}" -t "${USERNAME}@${HOSTNAME}" passwd done -# TODO stop the ssh agent if we started it here +# Stop the ssh agent if we started it here +ssh_agent_helper_cleanup From b5391d45f6a7b37d1db3b9e4e249560280009a58 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 8 Mar 2024 15:48:18 -0800 Subject: [PATCH 24/27] MAINT: group usage of shared key, use exported helper --- scripts/bootstrap_plc.sh | 1 + scripts/setup_new_plc.sh | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index 7164196..0d72db2 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -51,6 +51,7 @@ fi # Create an ssh key, if it does not already exist if [ ! -f "${SSH_KEY_FILENAME}" ]; then ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" + chmod g+r "${SSH_KEY_FILENAME}" fi # Register the ssh key with the ssh agent if needed diff --git a/scripts/setup_new_plc.sh b/scripts/setup_new_plc.sh index 19ca864..d8774f1 100755 --- a/scripts/setup_new_plc.sh +++ b/scripts/setup_new_plc.sh @@ -24,7 +24,4 @@ source "${THIS_DIR}/ssh_agent_helper.sh" "${THIS_DIR}"/provision_plc.sh "${1}" # Stop the ssh agent if we started it here -if [ "${HELPER_STARTED_AGENT}" = "YES" ] && [ -n "${SSH_AGENT_PID}" ]; then - echo "Cleaning up SSH agent." - kill "${SSH_AGENT_PID}" -fi +ssh_agent_helper_cleanup From af4270b3cc06ce0233b1450590ce16e97c07f982 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 13 Mar 2024 15:12:09 -0700 Subject: [PATCH 25/27] ENH: move the ssh key to the user's ssh config folder, which is most suitable for per-user use. --- scripts/bootstrap_plc.sh | 9 +++++++-- scripts/provision_plc.sh | 3 ++- scripts/update_admin_pass.sh | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index 0d72db2..b8bc0d0 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -6,6 +6,9 @@ # - and set us up for ssh key authentication with the plc # - run the bootstrap playbook, so that the provision playbook can run properly # +# Each user who wants to use ansible for a particular PLC must run this script! +# One of the steps is setting up SSH-based logins, which are done on an per-user basis. +# # Expected usage, e.g. on a bsd test plc: # # $ ./bootstrap_plc.sh plc-tst-bsd1 @@ -24,11 +27,12 @@ if [ ! -x ansible-playbook ]; then source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate fi +SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" + USERNAME="${PLC_USERNAME:=Administrator}" THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" -SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" INVENTORY_PATH="${ANSIBLE_ROOT}/inventory/plcs.yaml" SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" @@ -50,8 +54,9 @@ fi # Create an ssh key, if it does not already exist if [ ! -f "${SSH_KEY_FILENAME}" ]; then + echo "Generating your PLC Ansible SSH Key at ${SSH_KEY_FILENAME}." + echo "Please encrypt this with the TCBSD Admin password!." ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" - chmod g+r "${SSH_KEY_FILENAME}" fi # Register the ssh key with the ssh agent if needed diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index 2c6a08d..8768c53 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -18,10 +18,11 @@ fi TARGET="${1}" shift +SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" + THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" -SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" # Activate python env if we don't have ansible on the path if [ ! -x ansible-playbook ]; then diff --git a/scripts/update_admin_pass.sh b/scripts/update_admin_pass.sh index c698fe8..0bc6c55 100755 --- a/scripts/update_admin_pass.sh +++ b/scripts/update_admin_pass.sh @@ -18,11 +18,12 @@ if [ -z "${1}" ]; then exit 1 fi +SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" + USERNAME="${PLC_USERNAME:=Administrator}" THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" -SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" SSH_CONFIG="${ANSIBLE_ROOT}/ssh_config" # Register the ssh key with the ssh agent if needed From 8b37bbb6626ce246a4ce9c437403ccedaf4bd297 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 13 Mar 2024 16:42:27 -0700 Subject: [PATCH 26/27] ENH: one more SSH_KEY_FILENAME --- scripts/ssh_agent_helper.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/ssh_agent_helper.sh b/scripts/ssh_agent_helper.sh index 7ffbf90..d3c4a01 100755 --- a/scripts/ssh_agent_helper.sh +++ b/scripts/ssh_agent_helper.sh @@ -8,10 +8,8 @@ # # source ssh_agent_helper.sh -THIS_SCRIPT="$(realpath "${BASH_SOURCE[0]}")" -THIS_DIR="$(dirname "${THIS_SCRIPT}")" -ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" -SSH_KEY_FILENAME="${ANSIBLE_ROOT}/tcbsd_key_rsa" +SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" + HELPER_STARTED_AGENT="NO" export HELPER_STARTED_AGENT From f361b87903948b22c99fc4faf9a4c0bd7eff367f Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 13 Mar 2024 16:47:13 -0700 Subject: [PATCH 27/27] ENH: move ssh keygen to ssh helper, define SSH_KEY_FILENAME in exactly one place --- scripts/bootstrap_plc.sh | 9 --------- scripts/provision_plc.sh | 2 -- scripts/ssh_agent_helper.sh | 8 ++++++++ scripts/update_admin_pass.sh | 2 -- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/scripts/bootstrap_plc.sh b/scripts/bootstrap_plc.sh index b8bc0d0..0d5bd7b 100755 --- a/scripts/bootstrap_plc.sh +++ b/scripts/bootstrap_plc.sh @@ -27,8 +27,6 @@ if [ ! -x ansible-playbook ]; then source /cds/group/pcds/pyps/conda/venvs/ansible/bin/activate fi -SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" - USERNAME="${PLC_USERNAME:=Administrator}" THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" @@ -52,13 +50,6 @@ else echo "${VARS_PATH} already exists, skipping creation." fi -# Create an ssh key, if it does not already exist -if [ ! -f "${SSH_KEY_FILENAME}" ]; then - echo "Generating your PLC Ansible SSH Key at ${SSH_KEY_FILENAME}." - echo "Please encrypt this with the TCBSD Admin password!." - ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" -fi - # Register the ssh key with the ssh agent if needed source "${THIS_DIR}/ssh_agent_helper.sh" diff --git a/scripts/provision_plc.sh b/scripts/provision_plc.sh index 8768c53..6356e81 100755 --- a/scripts/provision_plc.sh +++ b/scripts/provision_plc.sh @@ -18,8 +18,6 @@ fi TARGET="${1}" shift -SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" - THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")" ANSIBLE_ROOT="$(realpath "${THIS_DIR}/..")" diff --git a/scripts/ssh_agent_helper.sh b/scripts/ssh_agent_helper.sh index d3c4a01..8c4ff29 100755 --- a/scripts/ssh_agent_helper.sh +++ b/scripts/ssh_agent_helper.sh @@ -9,6 +9,7 @@ # source ssh_agent_helper.sh SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" +export SSH_KEY_FILENAME HELPER_STARTED_AGENT="NO" export HELPER_STARTED_AGENT @@ -28,6 +29,13 @@ ssh_agent_helper_cleanup() { } export ssh_agent_helper_cleanup +# Create an ssh key, if it does not already exist +if [ ! -f "${SSH_KEY_FILENAME}" ]; then + echo "Generating your PLC Ansible SSH Key at ${SSH_KEY_FILENAME}." + echo "Please encrypt this with the TCBSD Admin password!." + ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}" +fi + # Multipurpose check: return code is 1 if the command fails, 2 if cannot connect to agent. # I'm not sure if need to differentiate between these cases if PUBKEYS="$(ssh-add -L)"; then diff --git a/scripts/update_admin_pass.sh b/scripts/update_admin_pass.sh index 0bc6c55..1b2eb63 100755 --- a/scripts/update_admin_pass.sh +++ b/scripts/update_admin_pass.sh @@ -18,8 +18,6 @@ if [ -z "${1}" ]; then exit 1 fi -SSH_KEY_FILENAME="${HOME}/.ssh/tcbsd_key_rsa" - USERNAME="${PLC_USERNAME:=Administrator}" THIS_SCRIPT="$(realpath "${0}")" THIS_DIR="$(dirname "${THIS_SCRIPT}")"