diff --git a/doc/README.md b/doc/README.md index 8b025162..9b9417d9 100644 --- a/doc/README.md +++ b/doc/README.md @@ -22,6 +22,7 @@ the `help` command. - [Containers in Infix](container.md) - [Find Your Device on the Network](discovery.md) - [Hardware Info & Status](hardware.md) + - [Scripting Infix](scripting.md) - [Infix Variants](variant.md) - [Virtual Environments](virtual.md) - [Vital Product Data (VPD)](vpd.md) diff --git a/doc/scripting.md b/doc/scripting.md new file mode 100644 index 00000000..92eb78ad --- /dev/null +++ b/doc/scripting.md @@ -0,0 +1,336 @@ +# Scripting Infix + +In some situations a user cannot, or does not want to, use the NETCONF +API for interacting with Infix. Examples include production tasks and +simpler remote scripting jobs to one or more remote devices. + +This document assumes you have the password for the `admin` user, and +that you can connect to the device. Please see [Finding my Device][1] +for help on locating it. + +Furthermore, the example commands shown here that are execute from a PC +to a remote device over SSH, use Linux/UNIX. With advances lately in +both Windows and macOS, many of the user friendly tools previously only +available in Linux are now available there too. + + - The shell prompt for the PC laptop side: + + ```shell + ~$ + ``` + + - The shell prompt when logged in to an Infix device: + + ```shell + admin@example:~$ + ``` + +> **Note:** the shell script commands used here are the raw variants +> which the CLI usually wraps in a warm and snugly blanket. Meaning +> they may change over time, while the CLI wrappers do *not*. That +> being said, please let us know if you find any inconsistencies. + + +## Tips + + - Ensure the `admin` user does *not* have `clish` as login shell + - Enable [SSH key authentication](system.md#ssh-authorized-key) + - Deploy same SSH *public* key to many Infix devices + - Secure your *private* SSH key using, e.g., `ssh-agent` + +The `ssh-keygen` command, used to create the private/public key pair, +asks for a passphrase and although this is *technically optional* it is +highly recommended to set one. For ease of use, in particular when +scripting, use `ssh-agent` to avoid retyping the passphrase for every +command. + +Useful links on SSH, keys, and using `ssh-agent`: + + - https://en.wikipedia.org/wiki/Ssh-agent + - https://www.cyberciti.biz/faq/how-to-use-ssh-agent-for-authentication-on-linux-unix/ + - https://goteleport.com/blog/how-to-use-ssh-agent-safely/ + + +## Admin User Not Authorized? + +All system services and critical configuration files are owned by the +locked-down `root` user. It is not possible to activate the `root` user +account for remote logins. Instead, use `admin` user and the `sudo` +command prefix. + +Here we are logged in to an example device: + +``` +admin@example:~$ cp /cfg/startup-config.cfg /cfg/backup-config.cfg +cp: can't create '/cfg/backup-config.cfg': Permission denied +admin@example:~$ sudo cp /cfg/startup-config.cfg /cfg/backup-config.cfg +``` + +## Examples + +The following example commands are run from the PC over SSH. The +following is a *very brief* introduction. + +The notation is `ssh username@address`, where address can be an IPv4 or +IPv6 address, a DNS name, or an mDNS name, e.g. infix.local. In the +case of IPv6: `address%interface`, where interface differs between +operating systems. On Linux and macOS the interface name is used, but +on Windows the interface index[^1] is used. + +[^1]: Press Win-r to bring up the Run dialog, enter `cmd.exe` and press + enter. Then type in `ipconfig /all` to list all interfaces, their + status, as well as interface index. + +**Logging in to a device** + +``` +~$ ssh admin@fe80::ff:fe00:0%eth0 +The authenticity of host 'fe80::ff:fe00:0%eth0 (fe80::ff:fe00:0%eth0)' can't be established. +ED25519 key fingerprint is SHA256:5/9mw64jhmYyD8MD+SwrsG3RXMBbP48pDe2T8bg14RQ. +This key is not known by any other names +Are you sure you want to continue connecting (yes/no/[fingerprint])? yes +Warning: Permanently added 'fe80::ff:fe00:0%eth0' (ED25519) to the list of known hosts. +admin@fe80::ff:fe00:0%eth0's password: ***** +.-------. +| . . | Infix -- a Network Operating System +|-. v .-| https://kernelkit.github.io +'-'---'-' + +Run the command 'cli' for interactive OAM +``` + +**Executing a command on a device** + +``` +~$ ssh admin@fe80::ff:fe00:0%eth0 echo hej +admin@fe80::ff:fe00:0%eth0's password: ***** +hej +``` + +**Made Easy** + +Connecting to networked devices using IP addresses is the way many +people are used to. The above example with IPv6 tend to scare off +people, so for the rest of this document we'll use the mDNS name +instead: + +``` +~$ ssh admin@infix.local%eth0 +The authenticity of host 'infix.local%eth0 (infix.local%eth0)' can't be established. +``` + +### Factory Reset + +The command option `-y` disables any "are you sure?" interaction and +immediately triggers a factory reset and reboot of the device. It is +when the device boots up it erases all writable storage. + +``` +~$ ssh admin@infix.local%eth0 factory -y +admin@infix.local%eth0's password: ***** +``` + +### System Reboot + +``` +~$ ssh admin@infix.local%eth0 reboot +admin@infix.local%eth0's password: ***** +``` + +### Set Date and Time + +Devices running Infix may have their system time completely off and this +can cause problems for upgrading and when accessing the web interface +over HTTPS (certificate validation looks at start and end dates). + +To set the device's system time, *and* sync that with the RTC: +use the PCs current time as argument: + +``` +~$ ssh admin@infix.local%eth0 "sudo date -s '2024-03-20 18:14+01:00' && sudo hwclock -w -u" +admin@infix.local%eth0's password: ***** +``` + +> The `-u` option ensures saving system time to the RTC in UTC time. + +Verify that the change took: + +``` +~$ ssh admin@infix.local%eth0 date +admin@infix.local%eth0's password: ***** +Wed Mar 20 17:14:47 UTC 2024 +``` + +### Remote Control of Ethernet Ports + +There are two ways to do it: + + 1. Change the configuration without saving it to `startup-config` + 2. Change the operational state + +The first involves sending a NETCONF command/config in XML, the second +we will cover here. We start by querying available interfaces (ports) +on the remote system: + +``` +~$ ssh admin@infix.local%qtap0 ip -br a +admin@infix.local%qtap0's password: +lo UP 127.0.0.1/8 ::1/128 +e0 UP fe80::ff:fe00:0/64 +e1 UP +e2 UP +e3 UP +e4 UP +e5 UP fe80::ff:fe00:5/64 +e6 UP fe80::ff:fe00:6/64 +e7 UP fe80::ff:fe00:7/64 +e8 UP fe80::ff:fe00:8/64 +e9 UP 192.168.2.200/24 fe80::ff:fe00:9/64 +br0 UP +``` + +Here we see a loopback interface (lo), ten Ethernet ports (e0-e9) and a +bridge (br0). From this quick glance we can guess that the ports e1-e4 +are bridged (you can verify this with the remote command `bridge link`) +because they do not have a link-local IPv6 address. + +I know it's port e6 that I want to take down: + +``` +~$ ssh admin@infix.local%qtap0 ip link set e6 down +admin@infix.local%qtap0's password: +RTNETLINK answers: Operation not permitted +~$ ssh admin@infix.local%qtap0 sudo ip link set e6 down +admin@infix.local%qtap0's password: +``` + +Changing the operational link state of a port is a privileged command, +so we have to prefix our command with `sudo`. + +Inspecting the link state again show the port is now down: + +``` +~$ ssh admin@infix.local%qtap0 ip -br a +admin@infix.local%qtap0's password: +lo UP 127.0.0.1/8 ::1/128 +e0 UP fe80::ff:fe00:0/64 +e1 UP +e2 UP +e3 UP +e4 UP +e5 UP fe80::ff:fe00:5/64 +e6 DOWN +e7 UP fe80::ff:fe00:7/64 +e8 UP fe80::ff:fe00:8/64 +e9 UP 192.168.2.200/24 fe80::ff:fe00:9/64 +br0 UP +``` + +### Check Device's Network Connectivity + +Say you want to perform a [System Upgrade][#system-uprgade] and it just +doesn't work, then you might want to ensure the device actually can +reach the upgrade server. + +``` +~$ ssh admin@infix.local%eth0 ping -c 3 server.local +admin@infix.local%qtap0's password: ***** +PING server.local (192.168.2.42) 56(84) bytes of data. +64 bytes from server.local: icmp_seq=1 ttl=64 time=0.201 ms +64 bytes from server.local: icmp_seq=2 ttl=64 time=0.432 ms +64 bytes from server.local: icmp_seq=3 ttl=64 time=0.427 ms + +--- server.local ping statistics --- +3 packets transmitted, 3 received, 0% packet loss, time 2050ms +rtt min/avg/max/mdev = 0.201/0.353/0.432/0.107 ms +``` + +Here we get a reply, so whatever is the issue with the upgrade was +not hiding behind a connectivity issue at least. + +### System Upgrade + +The underlying software that handles upgrades is called [RAUC][2]. To +trigger an upgrade you (currently) need an FTP/TFTP or HTTP/HTTPS server +where RAUC can fetch the upgrade from. In this example we use an FTP +server to upgrade the currently inactive "slot": + +``` +~$ ssh admin@infix.local%eth0 rauc install ftp://server.local/infix-aarch64-24.06.0.pkg +admin@infix.local%eth0's password: ***** +installing + 0% Installing + 0% Determining slot states + 20% Determining slot states done. + 20% Checking bundle + 20% Verifying signature + 40% Verifying signature done. + 40% Checking bundle done. + 40% Checking manifest contents + 60% Checking manifest contents done. + 60% Determining target install group + 80% Determining target install group done. + 80% Updating slots + 80% Checking slot rootfs.1 + 90% Checking slot rootfs.1 done. + 90% Copying image to rootfs.1 + 99% Copying image to rootfs.1 done. + 99% Updating slots done. +100% Installing done. +idle +Installing `ftp://server.local/infix-aarch64-24.06.0.pkg` succeeded +~$ +``` + +The inactive slot is now marked active and will be used on the next +boot. To upgrade the partition we booted from, we must first reboot. + +For more information, see the [Boot Procedure][3] document. + +**Alternative:** + +If you know your device has sufficient storage, eMMC or RAM disk (check +with the remote command `df -h`), you can also copy the `.pkg` file to +the device instead of having to set up an FTP/TFTP or HTTP/HTTPS server. + +Create an upload directory where `admin` has write permission: + +``` +~$ ssh admin@infix.local%eth0 "sudo mkdir /var/tmp/upload; sudo chown admin /var/tmp/upload" +admin@infix.local%eth0's password: +``` + +Copy the file with secure copy, first we show the nasty IPv6 version of +the command: + +``` +~$ scp infix-aarch64-24.06.0.pkg admin@\[fe80::ff:fe00:0%eth0\]:/var/tmp/upload/ +admin@fe80::ff:fe00:0%eth0's password: +infix-aarch64-24.06.0.pkg 100% 296 601.4KB/s 00:00 +``` + +And the upgrade command itself: + +``` +~$ ssh admin@infix.local%eth0 rauc install /var/tmp/upload/infix-aarch64-24.06.0.pkg +admin@infix.local%eth0's password: ***** +. +. +. +``` + +Remember to remove the file from the upload directory when you are done, +this can be done before or after the reboot to activate the upgrade. If +you want to upgrade both "slots", then you can of course keep the file +until you are done (provided the upload directory was created on +persistent storage). + +``` +~$ ssh admin@infix.local%eth0 rm /var/tmp/upload/infix-aarch64-24.06.0.pkg +admin@infix.local%eth0's password: ***** +~$ +``` + +[1]: discovery.md +[2]: https://rauc.io/ +[3]: boot.md#system-upgrade