Ch3sh1r3

Frigate: Script to Check For Update


Manually checking for software updates is cumbersome, so here is another little script to check for a software update for Frigate, which runs inside a Docker Container.

Create Script

Create a file using your text editor, I use nano editor. Be sure to edit to match your setup in the Edit Area.

touch frigate_check nano -w frigate_check

#!/bin/bash

######################
##    EDIT AREA     ##
######################

# Optional: include [ test ] with call to script, i.e. ./frigate_check test
# Else Force Test API and return values only (0=TRUE;1=FALSE)
API_TEST=1
# Frigate IP and PORT
IPADDR="192.168.1.5"
IPPORT="5000"
# Frigate docker file location (docker-compose.yml)
FRIGATE_DOCKER="/srv/docker/Frigate"
# CURL timeout [seconds]
CURL_TIMEOUT=10
# Frigate REPO to Check
FRIGATE_REPO="blakeblackshear/frigate/releases/latest"
# Github API REPO
FRIGATE_GITHUB_API="https://api.github.com/repos/$FRIGATE_REPO"
# Frigate LOCAL to Check
FRIGATE_LOCAL_API="http://$IPADDR:$IPPORT/api/version"

######################
##     EDIT END     ##
######################

# Check cURL command if available (required), abort if does not exists
type curl >/dev/null 2>&1 || { echo -e >&2 "Requires 'curl' but it's not installed. Install with:\nsudo apt install curl\nAborting..."; exit 1; }
# Check jq command if available (required), abort if not installed
type jq >/dev/null 2>&1 || { echo -e >&2 "Requires 'jq' but it's not installed. Install with:\nsudo apt install jq\nAborting..."; exit 1; }

if [ -n "$1" ] && [ "$1" != "test" ]; then
     { echo -e >&2 "Unknown command '$1'\nAborting..."; exit 1; }
elif [ "$1" == "test" ]; then
    echo
    echo "-*- Testing API and Return Value -*-"
else
    echo -n "Checking if there is an newer version of Frigate"
fi
while (( i++ < 4 )); do
    echo -n " ."
    sleep 1
done
echo

CURRENT_CONNECT=$(curl --connect-timeout $CURL_TIMEOUT --head --write-out "%{http_code}" --output /dev/null --silent "$FRIGATE_GITHUB_API" )
INSTALL_CONNECT=$(curl --connect-timeout $CURL_TIMEOUT --head --write-out "%{http_code}" --output /dev/null --silent "$FRIGATE_LOCAL_API" )

if [[ "$CURRENT_CONNECT" -ne 200 ]]; then
    CURRENT="API unreachable, current version unavailable"
else
    #CURRENT=$(curl --connect-timeout $CURL_TIMEOUT --silent --request GET "$FRIGATE_GITHUB_API" -H "Accept: application/json" | jq ".name" -r)
    CURRENT=$(curl --silent --request GET "$FRIGATE_GITHUB_API" -H "Accept: application/json" | jq ".name" -r)
    CURRENT_VERSION=$(echo "$CURRENT" | sed -n "s/[^0-9]\+\([0-9.]\+\).*/\1/p" | sed -e "s/^[[:space:]]*$//")
fi
if [[ "$INSTALL_CONNECT" -ne 200 ]]; then
    INSTALL="API unreachable, installed version unavailable"
else
    #INSTALL=$(curl --connect-timeout $CURL_TIMEOUT --silent --request GET "$FRIGATE_LOCAL_API")
    INSTALL=$(curl --silent --request GET "$FRIGATE_LOCAL_API")
    INSTALL_VERSION=$(echo "$INSTALL" | cut -d"-" -f 1 | sed -n "s/[^0-9]\+\([0-9.]\+\).*/\0/p" | sed -e "s/^[[:space:]]*$//")
fi

## TEST cURL API RETURN VALUE ##
if  [[ $API_TEST -eq 0 ]] || [ "$1" == "test" ]; then
    echo "CURRENT $CURRENT"
    echo "INSTALL $INSTALL"
    echo "*/*  ##  *//*  ##  */*"
    echo "Current: $CURRENT_VERSION"
    echo "Installed: $INSTALL_VERSION"
    echo "*/*  ##  *//*  ##  */*"
	echo "-*- Change API_TEST to quit test -*-"
	echo
else
    if [[ -z "$CURRENT_VERSION" ]] && [[ "$INSTALL_VERSION" ]]; then
        echo "$CURRENT"
        echo "Installed local version: $INSTALL_VERSION"
        echo "Unable to determine if update is available"
    elif [[ -z "$INSTALL_VERSION" ]] && [[ "$CURRENT_VERSION" ]]; then
        echo "Current available version: $CURRENT_VERSION"
        echo "$INSTALL"
        echo "Unable to determine if update available"
    elif [[ "$CURRENT_VERSION" ]] && [[ "$INSTALL_VERSION" ]]; then
	    if  [ "$CURRENT_VERSION" != "$INSTALL_VERSION" ]; then
            echo "There is a newer version of Frigate available"
            echo "Update to Version: $CURRENT_VERSION"
            echo "Installed Version: $INSTALL_VERSION"
            read -p "Would you like to update now?(Y/n)" -n 1 -r UPDATE
            update=${UPDATE,,}
            if [[ "$update" =~ ^(y| ) ]] || [[ -z "$update" ]]; then
			    cd "$FRIGATE_DOCKER" || { echo -e >&2 "Unable to find Frigate docker file\nAborting..."; exit 1; }
                docker compose pull
                docker compose up -d --remove-orphans
            else
                echo
                echo "Frigate not updated at this time"
                echo "Frigate Running $INSTALL_VERSION"
            fi
        else
		    echo "Current available version: $CURRENT_VERSION"
		    echo "Installed local version: $INSTALL_VERSION"
		    echo "The most recent version of Frigate is installed ($INSTALL_VERSION)"
	    fi
    else
        echo "$CURRENT"
        echo "$INSTALL"
        echo "Try again later"
    fi
fi

Save the file. Example in nano: ctrl+o and ctrl+x

Then switch to a root shell to move the script file, set permissions, and set owner. Be sure to use your own location; I save mine in the docker folder for convenience.

sudo -s
mv frigate_check /srv/docker/
chmod +x /srv/docker/frigate_check
chmod 0750 /srv/docker/frigate_check
chown root:root /srv/docker/frigate_check

You can run manually or use cron to set a schedule to check automatically.

Reference

https://github.com/blakeblackshear/frigate/issues/2236

FINALLY!! PfSense UPnP and Multiple Consoles Playing the Same Game


Summary

I’ve been running PfSense since 2014 and was never able to get UPnP to work with multiple consoles trying to play the same game and get open NAT. I’m currently running version 220.01/2.6.0 and still no resolution to the issue. Every few months the complaint would come up in the house; one person trying to convince the other to stop playing so they could play with open NAT, etc. So, I would do my regular check and test my Google-fu to see if the problem had been solved and try different options others claim have fixed the issue with no resolution. Finally, after years of let down I stumbled across a promising thread involving a Netgate employee and developer, and the community destined to solve this issue. Thank you! Thank you! Thank you!!

So, here are my documented steps following the forum post, which you can find below in the references…


*** This Patch is No Longer Needed if Using

PfSense 2.7.0 ***


Add and Apply Patch

PfSense Dashboard->System => Patches = Add New Patch

Add New Patch
PfSense Dashboard->System => Patches = Add New Patch

The patch can be applied using the System Patches package.

to create a new entry. Click the commit id to copy it to your clipboard and paste it into the URL/Commit ID box.

3b50f7656967fbb4daa869a7ae6d18bc5ab6eec3

Then save and apply changes.

Alternately, you can paste in the added rules. Diagnostic->Edit File and browse to /etc/inc/filter.inc

NAT Patch Rules
NAT Rules Patch

The patch will appear in the table with the option to revert the patch.

Patch Applied
Patch Applied

After applying the fix, either reboot the firewall OR trigger a filter reload (Status > Filter Reload) and then reset the state table (Diagnostics > States).

Settings

After applying the patch, port forwards were removed for UPnP services and outbound NAT mappings were removed, and Outbound NAT Mode was set to “Automatic outbound NAT rule generation”. Before this, it was set to Manual Outbound NAT with an attempt to manually map services with no luck.

Outbound NAT
Outbound NAT

I set up ACL entries in the UPnP Access Control Lists for the consoles that I want to limit UPnP to.

Services->UPnP & NAT-PMP = UPnP Access Control Lists

UPnP ACL
Services->UPnP & NAT-PMP = UPnP Access Control Lists

Conclusion

After applying the patch and changing settings above, all the consoles and PC’s had open NAT even when two consoles/PC’s were playing the same game. I received much praise after this but of course we are only standing on the shoulder of giants. Much thanks to JIMP and the community who made this possible!

References

Last piece of the puzzle – The discussion that led to the fix

The Fix – The documented fix with additional solutions of other community members

Shutdown VM’s on ESXi 7.0 using NUT on pfSense


Summary

Utilizing a UPS for your network devices and servers not only keeps your system up and running when there is an interruption to the utility power but it also protects you from unnecessary reboots during a temporary power outage. However, unless you have a larger backup system, the battery will eventually drain and your system will go down. To preserve power and keep critical services running longer, or to shutdown servers before the UPS battery drains, a plan to shutdown servers is necessary.

I use pfSense as my main router and a UPS to protect my network and servers from such cases and wanted an automated way to shutdown my servers when the UPS got too low. Since I use NUT (Network UPS Tool) to monitor my UPS in pfSense, I utilized the advanced settings in the UPS Service to provide clients a way to monitor the UPS. I installed a VIB on my ESXi VMware host to monitor the UPS status and react accordingly when there is a UPS alert. This post assumes you have the NUT UPS package installed on pfSense, and pfSense is currently monitoring an attached UPS and working properly. The following describes how I got it to work.

Setup NUT server on pfSense…

Setup

First thing to do is set up the UPS Service to to allow other devices to monitor the UPS attached to pfSense. In the pfSense GUI go to the services tab, open the UPS Service and under the UPS Settings tab click Display Advanced.

In the box labeled “Extra Arguments to driver (optional)” box add the following lines:

ignorelb
override.battery.charge.warning = 25
override.battery.charge.low = 20

This will ignore the UPS default “low battery” signal and instead go by the actual battery %. The other two lines will warn of low battery at 25% and send the low battery signal at 20%. The low battery signal will trigger the shutdown. You can adjust the values according to your system but this is a typical middle ground to start with.

Next, in the box labeled “Additional configuration lines for upsmon.conf” add the following lines:

RUN_AS_USER root
NOTIFYFLAG NOCOMM     SYSLOG 
NOTIFYFLAG COMMOK     SYSLOG 
NOTIFYFLAG COMMBAD    SYSLOG 
POLLFREQ 60 
POLLFREQALERT 60 
DEADTIME 180

This entry is optional but will ensure the NUT monitor service runs as root. The other options are meant to suppress the notifications sent to your terminal and reduce the amount of time it polls and alerts; they will still be logged in your system logs to help with debugging if necessary.

Next, in the box labeled “Additional configuration for ups.conf” add the following lines:

user = root

This will ensure the NUT service itself runs as root.

Next, in the box labeled “Additional configuration lines for upsd.conf” add the following lines:

LISTEN pfsense.ip.address.here

Change “pfsense.ip.address.here” to the IP address of your pfSense router or network interface you want to broadcast the NUT server on. This will allow clients to monitor the status of the UPS through the UPS Daemon running on pfSense by connecting via the IP address of pfSense on port 3493.

Next, in the box labeled “Additional configuration lines for upsd.users” add the following lines:

[ups_remote_client]
password = P@ssw0rd
upsmon slave

This is what the client, or in this case, the ESXi host will use to connect to the UPS Daemon running on pfSense. [ups_remote_client] can be whatever name you want to choose to identify the connection; the password can be whatever you choose for the client credentials to connect to the daemon.

Finally, restart the UPS Service to enable the updated configuration.

Test pfSense Configuration

SSH into the pfSense and run upsc UPS_name@localhost command, where UPS_name is the name on the UPS Status page. If the current status is displayed then the NUT server is setup correctly.

Prepare the ESXi 7.0 host…

On the ESXi host, a VIB will need to be uploaded and installed. In order to install the VIB the acceptance level of the host will need to be set to the Community acceptance level and enable SSH access to the ESXi host.

Host->Manage => Security & Users => Acceptance level->Edit settings = change to Community

Acceptance Level
Host->Manage => Security & Users => Acceptance level->Edit settings = change to Community

Host => Actions->Services = Enable Secure Shell (SSH)

Enable Secure Shell
Host => Actions->Services = Enable Secure Shell (SSH)

Download the module that will be copied to the ESXi host to install the VIB.

Alternately, you can get the file from the creator’s site. (You will need translator since the site is in French). Rene’s Diary There’s some extra info to read, as well.

Setup ESXi Host and Configuration…

Setup

Now that the ESXi host is ready for setup, Copy the NutClient-ESXi-2.8.0-2.3.0.i386.tar.gz file to the /tmp directory of the ESXi host. This can be accomplished using SCP from a Linux client, the WinSCP tool from a Windows client, or my favorite choice, FileZilla. SSH into the ESXi host as root or a user who has administrator rights and navigate to the /tmp directory and run the following commands to install the VIB. The process will take a few minutes. Once complete, the Installation Result will display and upon successful install you can exit the SSH session.

/tmp # tar -xzf NutClient-ESXi-2.8.0-2.3.0.i386.tar.gz
/tmp # sh upsmon-install.sh
Installation Result
   Message: Operation finished successfully.
   Reboot Required: false
   VIBs Installed: Margar_bootbank_upsmon_2.8.0-2.3.0
   VIBs Removed:
   VIBs Skipped:

Configuration

Go back to the ESXi GUI to configure the NUT client before the service is started. Actually, the service won’t start until the configuration is complete. Right click each option and select edit to configure the settings as needed to meet your requirements.

If the configuration variables do not appear in the administration interface after installation, issue the /etc/init.d/hostd restart command on the ESXi host in the SSH session. Be careful not to have any jobs in progress if you do this (taking snapshots, VMotion, etc.).

Host->Manage->System => Advanced settings

# in the search bubble type UserVars.Nut to display the options that can be configured

Advanced settings NUT selection
Host->Manage->System => Advanced settings
  • UserVars.NutUpsName  : Name of the UPS on the NUT server (in the form inverter_name@server_name_or_ip). Multiple inverters can be entered separated by a space. There will be no system shutdown until the last inverter still standing gives the shutdown command.
  • UserVars.NutUser  : Name of the NUT server connection account
  • UserVars.NutPassword  : NUT server login account password
  • UserVars.NutFinalDelay  : Seconds to wait after receiving low battery event to perform system shutdown
  • UserVars.NutSendMail  : To be set to 1 so that the NUT client sends an e-mail at each important inverter event
  • UserVars.NutMailTo  : Email address to send inverter events to
  • UserVars.NutMinSupplies  : For multi-inverter systems. The number of UPSs that must be able to power the system before initiating a shutdown. This number must be less than or equal to the number of ups defined in UserVars.NutUpsName . If you violate this constraint, the client will not start. With only one inverter, leave the value at 1.

For the sake of following the examples used in this post, the following settings will be set. Be sure to set to the values used in your environment.

UserVars.NutUpsNameUPS_name@pfsense.ip.address.here
UserVars.NutUserups_remote_client
UserVars.NutPasswordP@ssw0rd

Note that each time these parameters are modified, it will be necessary to stop/start the service to take them into account. For a more in-depth configuration, see below for links to references.

Start Service

The NutClient service should be running but if its not then start the service and set the start and stop policy.

Host->Manage->Services = NutClient

NUT Client Service
Host->Manage->Services = NutClient
NUT Client Start Stop

Confirm Firewall

In the NutClient service row, the last item is a link to the firewall rule. Click the link to confirm the rule was loaded during the VIB install. If rule is not found then SSH into the ESXi host and run esxcli network firewall refresh command to load the firewall rule. Run esxcli network firewall ruleset list to list the firewall rules to confirm the NutServer rule is loaded and enabled.

The NUT client and server use port 3493/tcp, so additional configuration may have to be setup on your internal network or clients if you have a firewall configured. This may be on your client or across vlans.

Test ESXi Configuration

To test the configuration , SSH into the ESXi host and run the command /opt/nut/bin/upsc UPS_name@pfsense.ip.address.here , where UPS_name is the name on the UPS Status page. If the current status is displayed then the NUT client is setup correctly and monitoring the UPS status from the NUT server on pfSense.

When the ESXi host receives a low battery signal, and after the UserVars.NutFinalDelay value in seconds has elapsed, the VM’s on the ESXi host will shutdown (or suspend) in respect to the settings and order set on the ESXi host.

Host->Manage->System => Autostart

ESXi Autostart
Host->Manage->System => Autostart

To do a manual test, SSH into the ESXi host and run /opt/nut/sbin/upsmon -c fsd command. The shutdown procedure is immediately started. This can be useful to confirm the shutdown procedure is as expected, and to estimate the time required for the server to shutdown.

Conclusion

With a bit of research I was effectively able to allow the ESXi host to monitor the UPS and shutdown active VM’s after a UPS alert. With the NUT server setup, this can be expanded to other clients that could benefit from monitoring the UPS by installing or configuring the NUT client service. Let me know if this was helpful or any correction you find to be useful for others.

References

NUT manual pages – User manual pages for all the items that pertain to NUT

Understand VMware Acceptance Levels – A good read to understand acceptance levels for Hosts and VIBs

Introduction to Network UPS Tools – A great reference with examples for a more in-depth configuration

Rene’s Diary – Source for the VIB with additional resources (in French will need to translate)

UPS management with NUT – the initial inspiration for this post and expanded to meet my needs

Continue reading…

Simple Script to Update Ubuntu on CLI


Updating Ubuntu using the CLI is done by typing the commands one-by-one or combining the commands using the && operator, i.e. sudo apt update && sudo apt upgrade. Running multiple servers and having to update them by typing out the apt commands over and over can be repetitious so writing a simple script can save some time and stop from misspelling commands. The following will simplify updating your Ubuntu servers.

Update Script

This script is currently being used on Ubuntu 18.04 20.04 22.04. You can choose to uncomment the option to refresh snap if you use it on your system. Create a file using your text editor, I use nano editor.

touch updateos
nano -w updateos

Copy the script into the editor.

#!/bin/bash

# Use: sudo updateos [Option]
# Option: upgrade, dist-upgrade,full-upgrade, default=[upgrade]
# Example: sudo updateos upgrade

# Check if root
if [[ $EUID -ne 0 ]]; then
     echo "You forgot sudo"
     exit 1
fi
# Check for option
if [ -z $1 ]; then
    upgoption="upgrade"
elif [ -n $1 ]; then
     case $1 in
       "dist-upgrade")
          upgoption="dist-upgrade"
          ;;
       "full-upgrade")
          upgoption="full-upgrade"
          ;;
       *)
          echo "Invalid Statement"
          exit
          ;;
     esac
else
     echo "Sum Ting Wong"
     exit
fi
# Going for it
echo "Starting Update"
sudo apt update
echo "Starting " $upgoption
sudo apt $upgoption
echo "Checking for orphaned dependencies..."
sudo apt autoremove
#sudo snap refresh
# Check if need reboot
RESTART_NEEDED=/var/run/reboot-required
if [ -f "$RESTART_NEEDED" ]; then
    echo "Update Complete"
    echo "Restart Required"
    read -p "Would you like to reboot now?(Y/n)" -n 1 -r REEBOOT
    reeboot=${REEBOOT,,}
    if [[ $reeboot =~ ^(y| ) ]] || [[ -z $reeboot ]]; then
         echo
         sudo reboot
    else
         echo
    fi
else
   echo "Update Complete"
   echo "No Restart Required"
fi

Save the file. Example in nano: ctrl+o and ctrl+x

Then switch to a root shell to move the script file, set permissions, and set owner.

sudo -s
mv updateos /usr/bin/
chmod +x /usr/bin/updateos
chmod 0750 /usr/bin/updateos
chown root:root /usr/bin/updateos

Once the above is done, type exit at the command prompt to exit the root shell and back into your user shell. Type the new command updateos and the server will execute the apt & optional snap commands. More experienced users can add commands to run additional updates in the script.

Reference

https://nationalpost.com/news/sum-ting-wong-intern-blamed-for-leaking-fake-names-of-pilots-aboard-plane-that-crashed-in-san-francisco

https://www.tutorialspoint.com/unix/shell_scripting.htm