Skip to content

Commit

Permalink
Merge pull request #12 from ZLLentz/enh_prod
Browse files Browse the repository at this point in the history
ENH: prod scripts
  • Loading branch information
ZLLentz authored Feb 13, 2024
2 parents 5d6c4cb + 1a921c2 commit 01ddf92
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 13 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.DS_Store
*_rsa
*.pub
# Only include the templates here.
/host_vars/*/*.yml
TCBSD*.vdi
TCBSD*.iso
venv
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ $(PLC_HOST_VARS): Makefile tcbsd-plc.yaml.template
envsubst < "tcbsd-plc.yaml.template" > "$@"

run-bootstrap: $(PLC_HOST_VARS) tcbsd-bootstrap-playbook.yaml
ansible-playbook tcbsd-bootstrap-playbook.yaml
ansible-playbook tcbsd-bootstrap-playbook.yaml --extra-vars "target=vms_all ansible_ssh_private_key_file=${SSH_KEY_FILENAME}"

run-provision: run-bootstrap tcbsd-provision-playbook.yaml
ansible-playbook tcbsd-provision-playbook.yaml
ansible-playbook tcbsd-provision-playbook.yaml --extra-vars "target=vms_all ansible_ssh_private_key_file=${SSH_KEY_FILENAME}"

add-route:
# NOTE: the add_route script lazily uses environment variables instead of
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

A repository for trying out Ansible provisioning of TwinCAT BSD PLCs.


### Quick start: set up a new plc in prod
1. clone the repo
2. run ``./scripts/first_time_setup.sh your-plc-name``
3. Edit ``./inventory/plcs.yaml`` to add your plc (and possibly an appropriate group)
4. Edit ``./host_vars/your-plc-name/vars.yaml`` if you'd like to change settings
3. run ``./scripts/provision_plcs.sh your-plc-name``
4. commit and submit the file edits as a PR


### Install requirements

If you have a physical PLC to use, you'll only need the following:
Expand All @@ -26,6 +36,7 @@ And their security recommendations:

[IPC_Security_Guideline_TwinCATBSD_en.pdf](https://download.beckhoff.com/download/document/product-security/Guidelines/IPC_Security_Guideline_TwinCATBSD_en.pdf)


### Create a VirtualBox VM

1. Download TwinCAT BSD image from Beckhoff
Expand Down Expand Up @@ -68,7 +79,7 @@ This will generate a VM with:
* Restarts the TwinCAT service if any TcRegistry changes were made


### Sample session
### Sample session: VM

1. Install requirements
2. Download TwinCAT BSD image from Beckhoff and put it in the same directory as
Expand Down
8 changes: 2 additions & 6 deletions group_vars/tcbsd_plcs/vars.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
ansible_user: Administrator
ansible_ssh_private_key_file: /Users/klauer/Repos/twincat-bsd-ansible-testing/tcbsd_key_rsa
ansible_become: true
ansible_become_method: doas
ansible_become_password: 1 # TODO: vault
Expand All @@ -17,7 +16,7 @@ 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: 0
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):
Expand Down Expand Up @@ -91,7 +90,4 @@ tc_uninstall_pip: true
tc_set_fixed_static_routes: []

# Alternatively, only add missing routes from the list:
tc_add_missing_static_routes:
- name: PC98125
address: 192.168.2.110
net_id: 192.168.2.110.1.1
tc_add_missing_static_routes: []
96 changes: 96 additions & 0 deletions group_vars/tcbsd_vms/vars.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
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 *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

# 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: 0
# 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:
- name: PC98125
address: 192.168.2.110
net_id: 192.168.2.110.1.1
97 changes: 97 additions & 0 deletions host_vars/plc-tst-bsd/vars.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
ansible_host: 172.21.148.81
tc_ams_net_id: 172.21.148.81.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 *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
#
## 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: []
8 changes: 8 additions & 0 deletions inventory/plcs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,13 @@ plcs:
tcbsd_plcs:

tcbsd_plcs:
children:
tst_all:

tst_all:
hosts:
plc-tst-bsd:

vms_all:
hosts:
test-plc-01:
67 changes: 67 additions & 0 deletions scripts/first_time_setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash
# Run (or re-run) this script to prepare a single plc for use in the ansible scripts.
# This will do the following, in order:
# - suggest an edit to the inventory and exit early if needed
# - create a host vars entry
# - 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:
#
# $ ./first_time_setup.sh plc-tst-bsd
if [ -z "${1}" ]; then
echo "Error: PLC name required"
exit 1
fi

HOSTNAME="${1}"

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"

# Check the inventory for your plc
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
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"
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."
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
ssh-keygen -t rsa -f "${SSH_KEY_FILENAME}"
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}"

# Check if we can log in using the key
ssh -i "${SSH_KEY_FILENAME}" "${PLC_USERNAME:=Administrator}@${HOSTNAME}" "echo key-based login test successful"

# 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"
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}"
32 changes: 32 additions & 0 deletions scripts/provision_plcs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/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:
#
# $ ./provision_plcs.sh plc-tst-bsd
#
# To run on a group of plcs, e.g. all of the tst plcs:
#
# $ ./provision_plcs.sh tst_all
#
# Groups are defined in the inventory file.
if [ -z "${1}" ]; then
echo "Ansible target required"
exit 1
fi

TARGET="${1}"

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
# You should create a reasonable venv here, it just needs ansible
source "${THIS_DIR}/venv/bin/activate"
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}"
2 changes: 1 addition & 1 deletion tcbsd-bootstrap-playbook.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- hosts: tcbsd_plcs
- hosts: "{{ target }}"
gather_facts: False

tasks:
Expand Down
Loading

0 comments on commit 01ddf92

Please sign in to comment.