From f2b63ae2d066562a0307541cd82bd3452010444c Mon Sep 17 00:00:00 2001 From: afeiszli Date: Wed, 4 Jan 2023 16:15:12 -0500 Subject: [PATCH 01/14] added script --- scripts/nm-upgrade.sh | 379 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 scripts/nm-upgrade.sh diff --git a/scripts/nm-upgrade.sh b/scripts/nm-upgrade.sh new file mode 100644 index 00000000..608b367b --- /dev/null +++ b/scripts/nm-upgrade.sh @@ -0,0 +1,379 @@ +#!/bin/bash + +cat << "EOF" +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + __ __ ______ ______ __ __ ______ __ __ ______ ______ +/\ "-.\ \ /\ ___\ /\__ _\ /\ "-./ \ /\ __ \ /\ \/ / /\ ___\ /\ == \ +\ \ \-. \ \ \ __\ \/_/\ \/ \ \ \-./\ \ \ \ __ \ \ \ _"-. \ \ __\ \ \ __< + \ \_\\"\_\ \ \_____\ \ \_\ \ \_\ \ \_\ \ \_\ \_\ \ \_\ \_\ \ \_____\ \ \_\ \_\ + \/_/ \/_/ \/_____/ \/_/ \/_/ \/_/ \/_/\/_/ \/_/\/_/ \/_____/ \/_/ /_/ + + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EOF + +if [ $(id -u) -ne 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +wait_seconds() {( + for ((a=1; a <= $1; a++)) + do + echo ". . ." + sleep 1 + done +)} + +confirm() {( + while true; do + read -p 'Does everything look right? [y/n]: ' yn + case $yn in + [Yy]* ) override="true"; break;; + [Nn]* ) echo "exiting..."; exit 1;; + * ) echo "Please answer yes or no.";; + esac + done +)} + +echo "checking dependencies..." + +OS=$(uname) + +if [ -f /etc/debian_version ]; then + dependencies="yq jq" + update_cmd='apt update' + install_cmd='apt-get install -y' +elif [ -f /etc/centos-release ]; then + dependencies="wireguard jq docker.io docker-compose netclient" + update_cmd='yum update' + install_cmd='yum install -y' +elif [ -f /etc/fedora-release ]; then + dependencies="wireguard jq docker.io docker-compose netclient" + update_cmd='dnf update' + install_cmd='dnf install -y' +elif [ -f /etc/redhat-release ]; then + dependencies="wireguard jq docker.io docker-compose netclient" + update_cmd='yum update' + install_cmd='yum install -y' +elif [ -f /etc/arch-release ]; then + dependecies="wireguard-tools jq docker.io docker-compose netclient" + update_cmd='pacman -Sy' + install_cmd='pacman -S --noconfirm' +else + echo "OS not supported for automatic install" + exit 1 +fi + +set -- $dependencies + +${update_cmd} + +while [ -n "$1" ]; do + is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") + if [ "${is_installed}" != "" ]; then + echo " " $1 is installed + else + echo " " $1 is not installed. Attempting install. + ${install_cmd} $1 + sleep 5 + if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then + is_installed=$(opkg list-installed $1 | grep $1) + else + is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") + fi + if [ "${is_installed}" != "" ]; then + echo " " $1 is installed + elif [ -x "$(command -v $1)" ]; then + echo " " $1 is installed + else + echo " " FAILED TO INSTALL $1 + echo " " This may break functionality. + fi + fi + shift +done + +echo "-----------------------------------------------------" +echo "dependency check complete" +echo "-----------------------------------------------------" + +wait_seconds 3 + +set -e + +unset MASTER_KEY +MASTER_KEY=$(yq -r .services.netmaker.environment.MASTER_KEY docker-compose.yml) +echo "-----------------------------------------------------" +echo "Is $MASTER_KEY the correct master key for your Netmaker installation?" +echo "-----------------------------------------------------" +select mkey_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $MASTER_KEY for master key" + break + ;; + 2) + read -p "Enter Master Key: " mkey + MASTER_KEY=$mkey + echo "using $MASTER_KEY" + break + ;; + *) echo "invalid option $REPLY";; + esac +done + +unset SERVER_HTTP_HOST +SERVER_HTTP_HOST=$(yq -r .services.netmaker.environment.SERVER_HTTP_HOST docker-compose.yml) +echo "-----------------------------------------------------" +echo "Is $SERVER_HTTP_HOST the correct endpoint for your Netmaker installation?" +echo "-----------------------------------------------------" +select endpoint_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $SERVER_HTTP_HOST for endpoint" + break + ;; + 2) + read -p "Enter Endpoint: " endpoint + SERVER_HTTP_HOST=$endpoint + echo "using $SERVER_HTTP_HOST" + break + ;; + *) echo "invalid option $REPLY";; + esac +done + + +CURRENT_VERSION=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/server/getserverinfo | jq ' .Version') + +if [[ $CURRENT_VERSION == '"v0.17.1"' ]]; then + echo "version is $CURRENT_VERSION" +else + echo "error, current version is $CURRENT_VERSION" + echo "please upgrade to v0.17.1 in order to use the upgrade script" + exit 1 +fi + +curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/nodes | jq -c '[ .[] | select(.isserver=="yes") ]' > nodejson +NODE_LEN=$(jq length nodejson.tmp) +HAS_INGRESS="no" +echo $NODE_LEN +if [ "$NODE_LEN" -gt 0 ]; then + echo "===SERVER NODES===" + for i in $(seq 1 $NODE_LEN); do + NUM=$(($i-1)) + echo " SERVER NODE $NUM:" + echo " network: $(jq ".[$NUM].network" ./nodejson.tmp)" + echo " name: $(jq ".[$NUM].name" ./nodejson.tmp)" + echo " private ipv4: $(jq ".[$NUM].address" ./nodejson.tmp)" + echo " private ipv6: $(jq ".[$NUM].address6" ./nodejson.tmp)" + echo " is egress: $(jq ".[$NUM].isegressgateway" ./nodejson.tmp)" + if [[ $(jq ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then + echo " egress range: $(jq ".[$NUM].egressgatewayranges" ./nodejson.tmp)" + fi + echo " is ingress: $(jq ".[$NUM].isingressgateway" ./nodejson.tmp)" + if [[ $(jq ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then + HAS_INGRESS="yes" + fi + echo " is relay: $(jq ".[$NUM].isrelay" ./nodejson.tmp)" + echo " is failover: $(jq ".[$NUM].failover" ./nodejson.tmp)" + echo " ------------" + done + echo "==================" +else + echo "no nodes to parse" +fi + +echo "Please confirm that the above output matches the server nodes in your Netmaker server." +confirm + + +if [[ $HAS_INGRESS == "yes" ]]; then + echo "WARNING: Your server contains an Ingress Gateway. After upgrading, existing Ext Clients will be lost and must be recreated. Please confirm that you would like to continue." + confirm +fi + +echo "Setting docker-compose and Caddyfile..." + +sed -i "s/v0.17.1/v0.18.0/g" /root/docker-compose.yml +echo "Starting containers..." + +docker-compose -f /root/docker-compose.yml up -d + +sleep 2 + +test_connection() { + +echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)" +for i in 1 2 3 4 5 6 7 8 +do +curlresponse=$(curl -vIs https://api.${NETMAKER_BASE_DOMAIN} 2>&1) + +if [[ "$i" == 8 ]]; then + echo " Caddy is having an issue setting up certificates, please investigate (docker logs caddy)" + echo " Exiting..." + exit 1 +elif [[ "$curlresponse" == *"failed to verify the legitimacy of the server"* ]]; then + echo " Certificates not yet configured, retrying..." + +elif [[ "$curlresponse" == *"left intact"* ]]; then + echo " Certificates ok" + break +else + secs=$(($i*5+10)) + echo " Issue establishing connection...retrying in $secs seconds..." +fi +sleep $secs +done +} + + +setup_netclient() {( set -e +if [ -f /etc/debian_version ]; then + curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc + curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list + sudo apt update + sudo apt install netclient +elif [ -f /etc/centos-release ]; then + curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key + curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo + sudo rpm --import /tmp/gpg.key + sudo dnf check-update + sudo dnf install netclient +elif [ -f /etc/fedora-release ]; then + curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key + curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo + sudo rpm --import /tmp/gpg.key + sudo dnf check-update + sudo dnf install netclient +elif [ -f /etc/redhat-release ]; then + curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key + curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo + sudo rpm --import /tmp/gpg.key + sudo dnf check-update( + sudo dnf install netclient +elif [ -f /etc/arch-release ]; then + yay -S netclient +else + echo "OS not supported for automatic install" + exit 1 +fi + +register_ + +if [ -z "${install_cmd}" ]; then + echo "OS unsupported for automatic dependency install" + exit 1 +fi +)} + +setup_nmctl() {( + wget https://github.com/gravitl/netmaker/releases/download/v0.17.1/nmctl + chmod +x nmctl + ./nmctl context set default --endpoint="https://$SERVER_HTTP_HOST" --master_key="$MASTER_KEY" + ./nmctl context use default + RESP=$(./nmctl network list) + if [[ $RESP == *"unauthorized"* ]]; then + echo "Unable to properly configure NMCTL, exiting..." + exit 1 + fi +)} + +join_networks() {( + +NODE_LEN=$(jq length nodejson.tmp) +HAS_INGRESS="no" +echo $NODE_LEN +if [ "$NODE_LEN" -gt 0 ]; then + for i in $(seq 1 $NODE_LEN); do + NUM=$(($i-1)) + echo " joining network $(jq ".[$NUM].network" ./nodejson.tmp):" + KEY_JSON=./nmctl keys create $(jq ".[$NUM].network" ./nodejson.tmp) 1 + KEY=$(echo $KEY_JSON | jq -r .accessstring) + NAME=$(jq ".[$NUM].name" ./nodejson.tmp) + netclient join -t $KEY --name="" + echo " network: $(jq ".[$NUM].network" ./nodejson.tmp)" + echo " name: $(jq ".[$NUM].name" ./nodejson.tmp)" + echo " private ipv4: $(jq ".[$NUM].address" ./nodejson.tmp)" + echo " private ipv6: $(jq ".[$NUM].address6" ./nodejson.tmp)" + echo " is egress: $(jq ".[$NUM].isegressgateway" ./nodejson.tmp)" + if [[ $(jq ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then + echo " egress range: $(jq ".[$NUM].egressgatewayranges" ./nodejson.tmp)" + fi + + HOST_ID=$(yq e .host.id /etc/netclient/netclient.yml) + # set as a default host + + # create an egress if necessary + # create an ingress if necessary + echo " is ingress: $(jq ".[$NUM].isingressgateway" ./nodejson.tmp)" + if [[ $(jq ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then + HAS_INGRESS="yes" + fi + echo " is relay: $(jq ".[$NUM].isrelay" ./nodejson.tmp)" + echo " is failover: $(jq ".[$NUM].failover" ./nodejson.tmp)" + echo " ------------" + done + echo "==================" +else + echo "no networks to join" +fi + + +)} + +setup_netmaker() {( set -e + + +for i in 1 2 3 4 5 6 +do + echo " waiting for server node to become available" + wait_seconds 10 + curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker) + SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse}) + echo " Server ID: $SERVER_ID" + if [ $SERVER_ID == "null" ]; then + SERVER_ID="" + fi + if [[ "$i" -ge "6" && -z "$SERVER_ID" ]]; then + echo " Netmaker is having issues configuring itself, please investigate (docker logs netmaker)" + echo " Exiting..." + exit 1 + elif [ -z "$SERVER_ID" ]; then + echo " server node not yet configured, retrying..." + elif [[ ! -z "$SERVER_ID" ]]; then + echo " server node is now availble, continuing" + break + fi +done + + +if [[ ! -z "$SERVER_ID" ]]; then + curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress +fi +)} + +set +e + +# setup_netmaker +# wait_seconds 2 +test_connection +wait_seconds 2 +setup_netclient +wait_seconds 2 +join_networks + +echo "-----------------------------------------------------------------" +echo "-----------------------------------------------------------------" +echo "Netmaker setup is now complete. You are ready to begin using Netmaker." +echo "Visit dashboard.$NETMAKER_BASE_DOMAIN to log in" +echo "-----------------------------------------------------------------" +echo "-----------------------------------------------------------------" + +# cp -f /etc/skel/.bashrc /root/.bashrc From 60952bdc1c11d0e68e5b1e2a3e640b9023b9f267 Mon Sep 17 00:00:00 2001 From: afeiszli Date: Mon, 23 Jan 2023 08:06:27 -0500 Subject: [PATCH 02/14] script now working besides blockers --- scripts/nm-upgrade.sh | 773 ++++++++++++++++++++++++------------------ 1 file changed, 449 insertions(+), 324 deletions(-) diff --git a/scripts/nm-upgrade.sh b/scripts/nm-upgrade.sh index 608b367b..910af64f 100644 --- a/scripts/nm-upgrade.sh +++ b/scripts/nm-upgrade.sh @@ -1,36 +1,29 @@ #!/bin/bash -cat << "EOF" -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - __ __ ______ ______ __ __ ______ __ __ ______ ______ -/\ "-.\ \ /\ ___\ /\__ _\ /\ "-./ \ /\ __ \ /\ \/ / /\ ___\ /\ == \ -\ \ \-. \ \ \ __\ \/_/\ \/ \ \ \-./\ \ \ \ __ \ \ \ _"-. \ \ __\ \ \ __< - \ \_\\"\_\ \ \_____\ \ \_\ \ \_\ \ \_\ \ \_\ \_\ \ \_\ \_\ \ \_____\ \ \_\ \_\ - \/_/ \/_/ \/_____/ \/_/ \/_/ \/_/ \/_/\/_/ \/_/\/_/ \/_____/ \/_/ /_/ - +# make sure current version is 0.17.1 before continuing +check_version() { + IMG_TAG=$(yq -r '.services.netmaker.image' docker-compose.yml) -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EOF + if [[ "$IMG_TAG" == *"v0.17.1"* ]]; then + echo "version is $IMG_TAG" + else + echo "error, current version is $IMG_TAG" + echo "please upgrade to v0.17.1 in order to use the upgrade script" + exit 1 + fi +} -if [ $(id -u) -ne 0 ]; then - echo "This script must be run as root" - exit 1 -fi - -wait_seconds() {( +# wait a number of seconds, print a log +wait_seconds() { for ((a=1; a <= $1; a++)) do echo ". . ." sleep 1 done -)} +} -confirm() {( +# confirm a choice, or exit script +confirm() { while true; do read -p 'Does everything look right? [y/n]: ' yn case $yn in @@ -39,243 +32,309 @@ confirm() {( * ) echo "Please answer yes or no.";; esac done -)} - -echo "checking dependencies..." - -OS=$(uname) - -if [ -f /etc/debian_version ]; then - dependencies="yq jq" - update_cmd='apt update' - install_cmd='apt-get install -y' -elif [ -f /etc/centos-release ]; then - dependencies="wireguard jq docker.io docker-compose netclient" - update_cmd='yum update' - install_cmd='yum install -y' -elif [ -f /etc/fedora-release ]; then - dependencies="wireguard jq docker.io docker-compose netclient" - update_cmd='dnf update' - install_cmd='dnf install -y' -elif [ -f /etc/redhat-release ]; then - dependencies="wireguard jq docker.io docker-compose netclient" - update_cmd='yum update' - install_cmd='yum install -y' -elif [ -f /etc/arch-release ]; then - dependecies="wireguard-tools jq docker.io docker-compose netclient" - update_cmd='pacman -Sy' - install_cmd='pacman -S --noconfirm' -else - echo "OS not supported for automatic install" - exit 1 -fi - -set -- $dependencies - -${update_cmd} - -while [ -n "$1" ]; do - is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") - if [ "${is_installed}" != "" ]; then - echo " " $1 is installed - else - echo " " $1 is not installed. Attempting install. - ${install_cmd} $1 - sleep 5 - if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then - is_installed=$(opkg list-installed $1 | grep $1) - else - is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") - fi - if [ "${is_installed}" != "" ]; then - echo " " $1 is installed - elif [ -x "$(command -v $1)" ]; then - echo " " $1 is installed - else - echo " " FAILED TO INSTALL $1 - echo " " This may break functionality. - fi - fi - shift -done - -echo "-----------------------------------------------------" -echo "dependency check complete" -echo "-----------------------------------------------------" - -wait_seconds 3 - -set -e - -unset MASTER_KEY -MASTER_KEY=$(yq -r .services.netmaker.environment.MASTER_KEY docker-compose.yml) -echo "-----------------------------------------------------" -echo "Is $MASTER_KEY the correct master key for your Netmaker installation?" -echo "-----------------------------------------------------" -select mkey_option in "yes" "no (enter manually)"; do - case $REPLY in - 1) - echo "using $MASTER_KEY for master key" - break - ;; - 2) - read -p "Enter Master Key: " mkey - MASTER_KEY=$mkey - echo "using $MASTER_KEY" - break - ;; - *) echo "invalid option $REPLY";; - esac -done - -unset SERVER_HTTP_HOST -SERVER_HTTP_HOST=$(yq -r .services.netmaker.environment.SERVER_HTTP_HOST docker-compose.yml) -echo "-----------------------------------------------------" -echo "Is $SERVER_HTTP_HOST the correct endpoint for your Netmaker installation?" -echo "-----------------------------------------------------" -select endpoint_option in "yes" "no (enter manually)"; do - case $REPLY in - 1) - echo "using $SERVER_HTTP_HOST for endpoint" - break - ;; - 2) - read -p "Enter Endpoint: " endpoint - SERVER_HTTP_HOST=$endpoint - echo "using $SERVER_HTTP_HOST" - break - ;; - *) echo "invalid option $REPLY";; - esac -done - - -CURRENT_VERSION=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/server/getserverinfo | jq ' .Version') - -if [[ $CURRENT_VERSION == '"v0.17.1"' ]]; then - echo "version is $CURRENT_VERSION" -else - echo "error, current version is $CURRENT_VERSION" - echo "please upgrade to v0.17.1 in order to use the upgrade script" - exit 1 -fi - -curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/nodes | jq -c '[ .[] | select(.isserver=="yes") ]' > nodejson -NODE_LEN=$(jq length nodejson.tmp) -HAS_INGRESS="no" -echo $NODE_LEN -if [ "$NODE_LEN" -gt 0 ]; then - echo "===SERVER NODES===" - for i in $(seq 1 $NODE_LEN); do - NUM=$(($i-1)) - echo " SERVER NODE $NUM:" - echo " network: $(jq ".[$NUM].network" ./nodejson.tmp)" - echo " name: $(jq ".[$NUM].name" ./nodejson.tmp)" - echo " private ipv4: $(jq ".[$NUM].address" ./nodejson.tmp)" - echo " private ipv6: $(jq ".[$NUM].address6" ./nodejson.tmp)" - echo " is egress: $(jq ".[$NUM].isegressgateway" ./nodejson.tmp)" - if [[ $(jq ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then - echo " egress range: $(jq ".[$NUM].egressgatewayranges" ./nodejson.tmp)" - fi - echo " is ingress: $(jq ".[$NUM].isingressgateway" ./nodejson.tmp)" - if [[ $(jq ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then - HAS_INGRESS="yes" - fi - echo " is relay: $(jq ".[$NUM].isrelay" ./nodejson.tmp)" - echo " is failover: $(jq ".[$NUM].failover" ./nodejson.tmp)" - echo " ------------" - done - echo "==================" -else - echo "no nodes to parse" -fi - -echo "Please confirm that the above output matches the server nodes in your Netmaker server." -confirm - - -if [[ $HAS_INGRESS == "yes" ]]; then - echo "WARNING: Your server contains an Ingress Gateway. After upgrading, existing Ext Clients will be lost and must be recreated. Please confirm that you would like to continue." - confirm -fi - -echo "Setting docker-compose and Caddyfile..." - -sed -i "s/v0.17.1/v0.18.0/g" /root/docker-compose.yml -echo "Starting containers..." - -docker-compose -f /root/docker-compose.yml up -d - -sleep 2 - -test_connection() { - -echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)" -for i in 1 2 3 4 5 6 7 8 -do -curlresponse=$(curl -vIs https://api.${NETMAKER_BASE_DOMAIN} 2>&1) - -if [[ "$i" == 8 ]]; then - echo " Caddy is having an issue setting up certificates, please investigate (docker logs caddy)" - echo " Exiting..." - exit 1 -elif [[ "$curlresponse" == *"failed to verify the legitimacy of the server"* ]]; then - echo " Certificates not yet configured, retrying..." - -elif [[ "$curlresponse" == *"left intact"* ]]; then - echo " Certificates ok" - break -else - secs=$(($i*5+10)) - echo " Issue establishing connection...retrying in $secs seconds..." -fi -sleep $secs -done } +# install system dependencies necessary for script to run +install_dependencies() { + OS=$(uname) + is_ubuntu=$(sudo cat /etc/lsb-release | grep "Ubuntu") + if [ "${is_ubuntu}" != "" ]; then + dependencies="yq jq wireguard jq docker.io docker-compose" + update_cmd='apt update' + install_cmd='snap install' + elif [ -f /etc/debian_version ]; then + dependencies="yq jq wireguard jq docker.io docker-compose" + update_cmd='apt update' + install_cmd='apt install -y' + elif [ -f /etc/centos-release ]; then + dependencies="wireguard jq docker.io docker-compose" + update_cmd='yum update' + install_cmd='yum install -y' + elif [ -f /etc/fedora-release ]; then + dependencies="wireguard jq docker.io docker-compose" + update_cmd='dnf update' + install_cmd='dnf install -y' + elif [ -f /etc/redhat-release ]; then + dependencies="wireguard jq docker.io docker-compose" + update_cmd='yum update' + install_cmd='yum install -y' + elif [ -f /etc/arch-release ]; then + dependecies="wireguard-tools jq docker.io docker-compose netclient" + update_cmd='pacman -Sy' + install_cmd='pacman -S --noconfirm' + else + echo "OS not supported for automatic install" + exit 1 + fi -setup_netclient() {( set -e -if [ -f /etc/debian_version ]; then - curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc - curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list - sudo apt update - sudo apt install netclient -elif [ -f /etc/centos-release ]; then - curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key - curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo - sudo rpm --import /tmp/gpg.key - sudo dnf check-update - sudo dnf install netclient -elif [ -f /etc/fedora-release ]; then - curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key - curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo - sudo rpm --import /tmp/gpg.key - sudo dnf check-update - sudo dnf install netclient -elif [ -f /etc/redhat-release ]; then - curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key - curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo - sudo rpm --import /tmp/gpg.key - sudo dnf check-update( - sudo dnf install netclient -elif [ -f /etc/arch-release ]; then - yay -S netclient -else - echo "OS not supported for automatic install" + set -- $dependencies + + ${update_cmd} + + set +e + while [ -n "$1" ]; do + is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") + if [ "${is_installed}" != "" ]; then + echo " " $1 is installed + else + echo " " $1 is not installed. Attempting install. + ${install_cmd} $1 + sleep 5 + if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then + is_installed=$(opkg list-installed $1 | grep $1) + else + is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed") + fi + if [ "${is_installed}" != "" ]; then + echo " " $1 is installed + elif [ -x "$(command -v $1)" ]; then + echo " " $1 is installed + else + echo " " FAILED TO INSTALL $1 + echo " " This may break functionality. + fi + fi + shift + done + set -e + + echo "-----------------------------------------------------" + echo "dependency install complete" + echo "-----------------------------------------------------" +} + +# retrieve server settings from existing compose file +collect_server_settings() { + MASTER_KEY=$(yq -r .services.netmaker.environment.MASTER_KEY docker-compose.yml) + echo "-----------------------------------------------------" + echo "Is $MASTER_KEY the correct master key for your Netmaker installation?" + echo "-----------------------------------------------------" + select mkey_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $MASTER_KEY for master key" + break + ;; + 2) + read -p "Enter Master Key: " mkey + MASTER_KEY=$mkey + echo "using $MASTER_KEY" + break + ;; + *) echo "invalid option $REPLY, choose 1 or 2";; + esac + done + + SERVER_HTTP_HOST=$(yq -r .services.netmaker.environment.SERVER_HTTP_HOST docker-compose.yml) + echo "-----------------------------------------------------" + echo "Is $SERVER_HTTP_HOST the correct api endpoint for your Netmaker installation?" + echo "-----------------------------------------------------" + select endpoint_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $SERVER_HTTP_HOST for api endpoint" + break + ;; + 2) + read -p "Enter API Endpoint: " endpoint + SERVER_HTTP_HOST=$endpoint + echo "using $SERVER_HTTP_HOST" + break + ;; + *) echo "invalid option $REPLY";; + esac + done + + BROKER_NAME=$(yq -r .services.netmaker.environment.SERVER_NAME docker-compose.yml) + echo "-----------------------------------------------------" + echo "Is $BROKER_NAME the correct domain for your MQ broker?" + echo "-----------------------------------------------------" + select broker_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $BROKER_NAME for endpoint" + break + ;; + 2) + read -p "Enter Broker Domain: " broker + BROKER_NAME=$broker + echo "using $BROKER_NAME" + break + ;; + *) echo "invalid option $REPLY";; + esac + done + + SERVER_NAME=${BROKER_NAME#"broker."} + echo "-----------------------------------------------------" + echo "Is $SERVER_NAME the correct base domain for your installation?" + echo "-----------------------------------------------------" + select domain_option in "yes" "no (enter manually)"; do + case $REPLY in + 1) + echo "using $SERVER_NAME for domain" + break + ;; + 2) + read -p "Enter Server Domain: " broker + SERVER_NAME=$server + echo "using $SERVER_NAME" + break + ;; + *) echo "invalid option $REPLY";; + esac + done + + STUN_NAME="stun.$SERVER_NAME" + echo "-----------------------------------------------------" + echo "Netmaker v0.18.0 requires a new DNS entry for $STUN_NAME." + echo "Please confirm this is added to your DNS provider before continuing" + echo "(note: this is not required if using an nip.io address)" + echo "-----------------------------------------------------" + confirm +} + +# get existing server node configuration +collect_node_settings() { + curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/nodes | jq -c '[ .[] | select(.isserver=="yes") ]' > nodejson.tmp + NODE_LEN=$(jq length nodejson.tmp) + HAS_INGRESS="no" + if [ "$NODE_LEN" -gt 0 ]; then + echo "===SERVER NODES===" + for i in $(seq 1 $NODE_LEN); do + NUM=$(($i-1)) + echo " SERVER NODE $NUM:" + echo " network: $(jq -r ".[$NUM].network" ./nodejson.tmp)" + echo " name: $(jq -r ".[$NUM].name" ./nodejson.tmp)" + echo " private ipv4: $(jq -r ".[$NUM].address" ./nodejson.tmp)" + echo " private ipv6: $(jq -r ".[$NUM].address6" ./nodejson.tmp)" + echo " is egress: $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then + echo " egress range: $(jq -r ".[$NUM].egressgatewayranges" ./nodejson.tmp)" + fi + echo " is ingress: $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then + HAS_INGRESS="yes" + fi + echo " is relay: $(jq -r ".[$NUM].isrelay" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isrelay" ./nodejson.tmp) == "yes" ]]; then + HAS_RELAY="yes" + echo " relay addrs: $(jq -r ".[$NUM].relayaddrs" ./nodejson.tmp | tr -d '[]\n"[:space:]')" + fi + echo " is failover: $(jq -r ".[$NUM].failover" ./nodejson.tmp)" + echo " ------------" + done + echo "==================" + else + echo "no nodes to parse" + fi + + echo "Please confirm that the above output matches the server nodes in your Netmaker server." + confirm + + if [[ $HAS_INGRESS == "yes" ]]; then + echo "WARNING: Your server contains an Ingress Gateway. After upgrading, existing Ext Clients will be lost and must be recreated. Please confirm that you would like to continue." + confirm + fi +} + +# set compose file with proper values +set_compose() { + + # DEV_TEMP - Temporary instructions for testing + sed -i "s/v0.17.1/testing/g" /root/docker-compose.yml + + # RELEASE_REPLACE - Use this once release is ready + #sed -i "s/v0.17.1/v0.18.0/g" /root/docker-compose.yml + yq ".services.netmaker.environment.SERVER_NAME = \"$SERVER_NAME\"" -i /root/docker-compose.yml + yq ".services.netmaker.environment += {\"BROKER_NAME\": \"$BROKER_NAME\"}" -i /root/docker-compose.yml + yq ".services.netmaker.environment += {\"STUN_NAME\": \"$STUN_NAME\"}" -i /root/docker-compose.yml + yq ".services.netmaker.environment += {\"STUN_PORT\": \"3478\"}" -i /root/docker-compose.yml +} + +start_containers() { + docker-compose -f /root/docker-compose.yml up -d +} + +# make sure caddy is working +test_caddy() { + echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)" + for i in 1 2 3 4 5 6 7 8 + do + curlresponse=$(curl -vIs https://${SERVER_HTTP_HOST} 2>&1) + + if [[ "$i" == 8 ]]; then + echo " Caddy is having an issue setting up certificates, please investigate (docker logs caddy)" + echo " Exiting..." exit 1 -fi + elif [[ "$curlresponse" == *"failed to verify the legitimacy of the server"* ]]; then + echo " Certificates not yet configured, retrying..." -register_ + elif [[ "$curlresponse" == *"left intact"* ]]; then + echo " Certificates ok" + break + else + secs=$(($i*5+10)) + echo " Issue establishing connection...retrying in $secs seconds..." + fi + sleep $secs + done +} -if [ -z "${install_cmd}" ]; then - echo "OS unsupported for automatic dependency install" - exit 1 -fi -)} +setup_netclient() { -setup_nmctl() {( - wget https://github.com/gravitl/netmaker/releases/download/v0.17.1/nmctl +# DEV_TEMP - Temporary instructions for testing +wget https://fileserver.netmaker.org/testing/netclient +chmod +x netclient +./netclient install + +# RELEASE_REPLACE - Use this once release is ready +# if [ -f /etc/debian_version ]; then +# curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc +# curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list +# sudo apt update +# sudo apt install netclient +# elif [ -f /etc/centos-release ]; then +# curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key +# curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo +# sudo rpm --import /tmp/gpg.key +# sudo dnf check-update +# sudo dnf install netclient +# elif [ -f /etc/fedora-release ]; then +# curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key +# curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo +# sudo rpm --import /tmp/gpg.key +# sudo dnf check-update +# sudo dnf install netclient +# elif [ -f /etc/redhat-release ]; then +# curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key +# curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo +# sudo rpm --import /tmp/gpg.key +# sudo dnf check-update( +# sudo dnf install netclient +# elif [ -f /etc/arch-release ]; then +# yay -S netclient +# else +# echo "OS not supported for automatic install" +# exit 1 +# fi + +# if [ -z "${install_cmd}" ]; then +# echo "OS unsupported for automatic dependency install" +# exit 1 +# fi +} + +setup_nmctl() { + + # DEV_TEMP - Temporary instructions for testing + wget https://fileserver.netmaker.org/testing/nmctl + + # RELEASE_REPLACE - Use this once release is ready + # wget https://github.com/gravitl/netmaker/releases/download/v0.17.1/nmctl chmod +x nmctl + echo "using server $SERVER_HTTP_HOST" + echo "using master key $MASTER_KEY" ./nmctl context set default --endpoint="https://$SERVER_HTTP_HOST" --master_key="$MASTER_KEY" ./nmctl context use default RESP=$(./nmctl network list) @@ -283,97 +342,163 @@ setup_nmctl() {( echo "Unable to properly configure NMCTL, exiting..." exit 1 fi -)} +} -join_networks() {( +join_networks() { + NODE_LEN=$(jq length nodejson.tmp) + HAS_INGRESS="no" + if [ "$NODE_LEN" -gt 0 ]; then + for i in $(seq 1 $NODE_LEN); do + NUM=$(($i-1)) + NETWORK=$(jq -r ".[$NUM].network" ./nodejson.tmp) + echo " joining network $NETWORK with following settings. Please confirm:" + echo " network: $(jq -r ".[$NUM].network" ./nodejson.tmp)" + echo " name: $(jq -r ".[$NUM].name" ./nodejson.tmp)" + echo " private ipv4: $(jq -r ".[$NUM].address" ./nodejson.tmp)" + echo " private ipv6: $(jq -r ".[$NUM].address6" ./nodejson.tmp)" + echo " is egress: $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then + HAS_EGRESS="yes" + echo " egress range: $(jq -r ".[$NUM].egressgatewayranges" ./nodejson.tmp)" + fi + echo " is ingress: $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then + HAS_INGRESS="yes" + fi + echo " is relay: $(jq -r ".[$NUM].isrelay" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].isrelay" ./nodejson.tmp) == "yes" ]]; then + HAS_RELAY="yes" + RELAY_ADDRS=$(jq -r ".[$NUM].relayaddrs" ./nodejson.tmp | tr -d '[]\n"[:space:]') + fi + echo " is failover: $(jq -r ".[$NUM].failover" ./nodejson.tmp)" + if [[ $(jq -r ".[$NUM].failover" ./nodejson.tmp) == "yes" ]]; then + HAS_FAILOVER="yes" + fi + echo " ------------" -NODE_LEN=$(jq length nodejson.tmp) -HAS_INGRESS="no" -echo $NODE_LEN -if [ "$NODE_LEN" -gt 0 ]; then - for i in $(seq 1 $NODE_LEN); do - NUM=$(($i-1)) - echo " joining network $(jq ".[$NUM].network" ./nodejson.tmp):" - KEY_JSON=./nmctl keys create $(jq ".[$NUM].network" ./nodejson.tmp) 1 - KEY=$(echo $KEY_JSON | jq -r .accessstring) - NAME=$(jq ".[$NUM].name" ./nodejson.tmp) - netclient join -t $KEY --name="" - echo " network: $(jq ".[$NUM].network" ./nodejson.tmp)" - echo " name: $(jq ".[$NUM].name" ./nodejson.tmp)" - echo " private ipv4: $(jq ".[$NUM].address" ./nodejson.tmp)" - echo " private ipv6: $(jq ".[$NUM].address6" ./nodejson.tmp)" - echo " is egress: $(jq ".[$NUM].isegressgateway" ./nodejson.tmp)" - if [[ $(jq ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then - echo " egress range: $(jq ".[$NUM].egressgatewayranges" ./nodejson.tmp)" - fi + confirm + echo "running command: ./nmctl keys create $NETWORK 1" + KEY_JSON=$(./nmctl keys create $NETWORK 1) + KEY=$(echo $KEY_JSON | jq -r .accessstring) - HOST_ID=$(yq e .host.id /etc/netclient/netclient.yml) - # set as a default host - - # create an egress if necessary - # create an ingress if necessary - echo " is ingress: $(jq ".[$NUM].isingressgateway" ./nodejson.tmp)" - if [[ $(jq ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then - HAS_INGRESS="yes" - fi - echo " is relay: $(jq ".[$NUM].isrelay" ./nodejson.tmp)" - echo " is failover: $(jq ".[$NUM].failover" ./nodejson.tmp)" - echo " ------------" - done - echo "==================" -else - echo "no networks to join" + echo "join key created: $KEY" + + NAME=$(jq -r ".[$NUM].name" ./nodejson.tmp) + ADDRESS=$(jq -r ".[$NUM].address" ./nodejson.tmp) + ADDRESS6=$(jq -r ".[$NUM].address6" ./nodejson.tmp) + + + if [[ ! -z "$ADDRESS6" ]]; then + echo "joining with command: netclient join -t $KEY --name=$NAME --address=$ADDRESS --address6=$ADDRESS6 +" + confirm + netclient join -t $KEY --name=$NAME --address=$ADDRESS --address6=$ADDRESS6 + else + echo "joining with command: netclient join -t $KEY --name=$NAME --address=$ADDRESS" + confirm + netclient join -t $KEY --name=$NAME --address=$ADDRESS + fi + NODE_ID=$(sudo cat /etc/netclient/nodes.yml | yq -r .$NETWORK.commonnode.id) + echo "join complete. New node ID: $NODE_ID" + if [[ $NUM -eq 0 ]]; then + HOST_ID=$(sudo cat /etc/netclient/netclient.yml | yq -r .host.id) + echo "For first join, making host a default" + echo "Host ID: $HOST_ID" + # set as a default host + # TODO - this command is not working + ./nmctl host update $HOST_ID --default + fi + + # create an egress if necessary + if [[ $HAS_EGRESS == "yes" ]]; then + echo "Egress is currently unimplemented. Wait for 0.18.1" + fi + + echo "HAS INGRESS: $HAS_INGRESS" + # create an ingress if necessary + if [[ $HAS_INGRESS == "yes" ]]; then + if [[ $HAS_FAILOVER == "yes" ]]; then + echo "creating ingress and failover..." + ./nmctl node create_ingress $NETWORK $NODE_ID --failover + else + echo "creating ingress..." + ./nmctl node create_ingress $NETWORK $NODE_ID + fi + fi + + # relay + if [[ $HAS_RELAY == "yes" ]]; then + echo "creating relay..." + ./nmctl node create_relay $NETWORK $NODE_ID $RELAY_ADDRS + fi + + done + echo "==================" + else + echo "no networks to join" + fi +} + + +cat << "EOF" +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +The Netmaker Upgrade Script: Upgrading to v0.18.0 so you don't have to! +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EOF + +set -e + +if [ $(id -u) -ne 0 ]; then + echo "This script must be run as root" + exit 1 fi +echo "...installing dependencies for script" +install_dependencies -)} +echo "...confirming version is correct" +check_version -setup_netmaker() {( set -e +echo "...collecting necessary server settings" +collect_server_settings +echo "...setup nmctl" +setup_nmctl -for i in 1 2 3 4 5 6 -do - echo " waiting for server node to become available" - wait_seconds 10 - curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker) - SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse}) - echo " Server ID: $SERVER_ID" - if [ $SERVER_ID == "null" ]; then - SERVER_ID="" - fi - if [[ "$i" -ge "6" && -z "$SERVER_ID" ]]; then - echo " Netmaker is having issues configuring itself, please investigate (docker logs netmaker)" - echo " Exiting..." - exit 1 - elif [ -z "$SERVER_ID" ]; then - echo " server node not yet configured, retrying..." - elif [[ ! -z "$SERVER_ID" ]]; then - echo " server node is now availble, continuing" - break - fi -done +echo "...retrieving current server node settings" +collect_node_settings +echo "...backing up docker compose to docker-compose.yml.backup" +cp /root/docker-compose.yml /root/docker-compose.yml.backup -if [[ ! -z "$SERVER_ID" ]]; then - curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress -fi -)} +echo "...setting docker-compose values" +set_compose -set +e +echo "...starting containers" +start_containers -# setup_netmaker +wait_seconds 3 + +echo "..testing Caddy proxy" +test_caddy + +echo "..testing Netmaker health" +# TODO, implement health check +# netmaker_health_check # wait_seconds 2 -test_connection -wait_seconds 2 + +echo "...setting up netclient (this may take a minute, be patient)" setup_netclient wait_seconds 2 + +echo "...join networks" join_networks echo "-----------------------------------------------------------------" echo "-----------------------------------------------------------------" echo "Netmaker setup is now complete. You are ready to begin using Netmaker." -echo "Visit dashboard.$NETMAKER_BASE_DOMAIN to log in" +echo "Visit dashboard.$SERVER_NAME to log in" echo "-----------------------------------------------------------------" -echo "-----------------------------------------------------------------" - -# cp -f /etc/skel/.bashrc /root/.bashrc +echo "-----------------------------------------------------------------" \ No newline at end of file From 0d92bf4aa187c402a95773b5577f0e34b8270efb Mon Sep 17 00:00:00 2001 From: afeiszli Date: Mon, 23 Jan 2023 08:11:20 -0500 Subject: [PATCH 03/14] added comments --- scripts/nm-upgrade.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/nm-upgrade.sh b/scripts/nm-upgrade.sh index 910af64f..8874445c 100644 --- a/scripts/nm-upgrade.sh +++ b/scripts/nm-upgrade.sh @@ -1,6 +1,6 @@ #!/bin/bash -# make sure current version is 0.17.1 before continuing +# check_version - make sure current version is 0.17.1 before continuing check_version() { IMG_TAG=$(yq -r '.services.netmaker.image' docker-compose.yml) @@ -13,7 +13,7 @@ check_version() { fi } -# wait a number of seconds, print a log +# wait_seconds - wait a number of seconds, print a log wait_seconds() { for ((a=1; a <= $1; a++)) do @@ -22,7 +22,7 @@ wait_seconds() { done } -# confirm a choice, or exit script +# confirm - confirm a choice, or exit script confirm() { while true; do read -p 'Does everything look right? [y/n]: ' yn @@ -34,7 +34,7 @@ confirm() { done } -# install system dependencies necessary for script to run +# install_dependencies - install system dependencies necessary for script to run install_dependencies() { OS=$(uname) is_ubuntu=$(sudo cat /etc/lsb-release | grep "Ubuntu") @@ -103,7 +103,7 @@ install_dependencies() { echo "-----------------------------------------------------" } -# retrieve server settings from existing compose file +# collect_server_settings - retrieve server settings from existing compose file collect_server_settings() { MASTER_KEY=$(yq -r .services.netmaker.environment.MASTER_KEY docker-compose.yml) echo "-----------------------------------------------------" @@ -194,7 +194,7 @@ collect_server_settings() { confirm } -# get existing server node configuration +# collect_node_settings - get existing server node configuration collect_node_settings() { curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/nodes | jq -c '[ .[] | select(.isserver=="yes") ]' > nodejson.tmp NODE_LEN=$(jq length nodejson.tmp) @@ -238,7 +238,7 @@ collect_node_settings() { fi } -# set compose file with proper values +# set_compose - set compose file with proper values set_compose() { # DEV_TEMP - Temporary instructions for testing @@ -252,11 +252,12 @@ set_compose() { yq ".services.netmaker.environment += {\"STUN_PORT\": \"3478\"}" -i /root/docker-compose.yml } +# start_containers - run docker-compose up -d start_containers() { docker-compose -f /root/docker-compose.yml up -d } -# make sure caddy is working +# test_caddy - make sure caddy is working test_caddy() { echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)" for i in 1 2 3 4 5 6 7 8 @@ -281,6 +282,7 @@ test_caddy() { done } +# setup_netclient - installs netclient locally setup_netclient() { # DEV_TEMP - Temporary instructions for testing @@ -325,6 +327,7 @@ chmod +x netclient # fi } +# setup_nmctl - pulls nmctl and makes it executable setup_nmctl() { # DEV_TEMP - Temporary instructions for testing @@ -344,6 +347,7 @@ setup_nmctl() { fi } +# join_networks - joins netclient into the networks using old settings join_networks() { NODE_LEN=$(jq length nodejson.tmp) HAS_INGRESS="no" From 37c8a253b8d1df6260d08c2c53e93596832dfccb Mon Sep 17 00:00:00 2001 From: afeiszli Date: Mon, 23 Jan 2023 13:35:40 -0500 Subject: [PATCH 04/14] set STUN port --- scripts/nm-upgrade.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nm-upgrade.sh b/scripts/nm-upgrade.sh index 8874445c..4344f1d1 100644 --- a/scripts/nm-upgrade.sh +++ b/scripts/nm-upgrade.sh @@ -250,6 +250,7 @@ set_compose() { yq ".services.netmaker.environment += {\"BROKER_NAME\": \"$BROKER_NAME\"}" -i /root/docker-compose.yml yq ".services.netmaker.environment += {\"STUN_NAME\": \"$STUN_NAME\"}" -i /root/docker-compose.yml yq ".services.netmaker.environment += {\"STUN_PORT\": \"3478\"}" -i /root/docker-compose.yml + yq ".services.netmaker.ports += \"3478:3478/udp\"" -i /root/docker-compose.yml } # start_containers - run docker-compose up -d From aad4abc181f2a062b7ea96e9a0117f4258c664a4 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Fri, 27 Jan 2023 14:51:06 -0500 Subject: [PATCH 05/14] remove dependencies on netclient --- go.mod | 8 ++- go.sum | 4 +- logic/metrics/metrics.go | 2 +- logic/peers.go | 37 +++++----- metrics/metrics.go | 110 +++++++++++++++++++++++++++++ models/mqtt.go | 29 ++++---- models/proxy.go | 145 +++++++++++++++++++++++++++++++++++++++ mq/publishers.go | 3 +- 8 files changed, 296 insertions(+), 42 deletions(-) create mode 100644 metrics/metrics.go create mode 100644 models/proxy.go diff --git a/go.mod b/go.mod index ef45d207..9b75fc9d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/oauth2 v0.3.0 golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect - golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c + golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31 google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.1 @@ -29,7 +29,7 @@ require ( require ( filippo.io/edwards25519 v1.0.0 github.com/c-robinson/iplib v1.0.6 - github.com/go-ping/ping v1.1.0 // indirect + github.com/go-ping/ping v1.1.0 github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 ) @@ -42,8 +42,8 @@ require ( ) require ( - github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09 github.com/guumaster/tablewriter v0.0.10 + github.com/kr/pretty v0.3.1 github.com/matryer/is v1.4.0 github.com/olekukonko/tablewriter v0.0.5 github.com/spf13/cobra v1.6.1 @@ -53,7 +53,9 @@ require ( cloud.google.com/go/compute/metadata v0.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect ) diff --git a/go.sum b/go.sum index 6972718d..573411d1 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09 h1:T0gLl+i8whnrdwtW91R4u8x8bmqFVfPTU9WfBratkMc= -github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09/go.mod h1:g3q+vhLySW/6smOsWsVy5LrxoW++f+kqiBAp9BM6sbY= github.com/guumaster/tablewriter v0.0.10 h1:A0HD94yMdt4usgxBjoEceNeE0XMJ027euoHAzsPqBQs= github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= @@ -78,6 +76,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -121,6 +120,7 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY= github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= diff --git a/logic/metrics/metrics.go b/logic/metrics/metrics.go index 08085715..7c671fb3 100644 --- a/logic/metrics/metrics.go +++ b/logic/metrics/metrics.go @@ -3,9 +3,9 @@ package metrics import ( "time" - proxy_metrics "github.com/gravitl/netclient/nmproxy/metrics" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" + proxy_metrics "github.com/gravitl/netmaker/metrics" "github.com/gravitl/netmaker/models" "golang.zx2c4.com/wireguard/wgctrl" ) diff --git a/logic/peers.go b/logic/peers.go index ddba2cd3..df92ea83 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -10,7 +10,6 @@ import ( "strings" "time" - proxy_models "github.com/gravitl/netclient/nmproxy/models" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic/acls/nodeacls" @@ -28,10 +27,10 @@ import ( // TODO ========================== // TODO ========================== // revisit this logic with new host/node models. -func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyManagerPayload, error) { - proxyPayload := proxy_models.ProxyManagerPayload{} +func GetPeersForProxy(node *models.Node, onlyPeers bool) (models.ProxyManagerPayload, error) { + proxyPayload := models.ProxyManagerPayload{} var peers []wgtypes.PeerConfig - peerConfMap := make(map[string]proxy_models.PeerConf) + peerConfMap := make(map[string]models.PeerConf) var err error currentPeers, err := GetNetworkNodes(node.Network) if err != nil { @@ -70,7 +69,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana logger.Log(1, "failed to relayed nodes: ", node.ID.String(), err.Error()) proxyPayload.IsRelay = false } else { - relayPeersMap := make(map[string]proxy_models.RelayedConf) + relayPeersMap := make(map[string]models.RelayedConf) for _, relayedNode := range relayedNodes { relayedNode := relayedNode payload, err := GetPeersForProxy(&relayedNode, true) @@ -81,7 +80,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana } relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, host.ListenPort)) if udpErr == nil { - relayPeersMap[host.PublicKey.String()] = proxy_models.RelayedConf{ + relayPeersMap[host.PublicKey.String()] = models.RelayedConf{ RelayedPeerEndpoint: relayedEndpoint, RelayedPeerPubKey: relayedHost.PublicKey.String(), Peers: payload.Peers, @@ -111,7 +110,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana if proxyStatus { listenPort = host.ProxyListenPort if listenPort == 0 { - listenPort = proxy_models.NmProxyPort + listenPort = models.NmProxyPort } } else if listenPort == 0 { listenPort = host.ListenPort @@ -136,7 +135,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana PersistentKeepaliveInterval: &keepalive, ReplaceAllowedIPs: true, }) - peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{ + peerConfMap[host.PublicKey.String()] = models.PeerConf{ Address: net.ParseIP(peer.PrimaryAddress()), Proxy: proxyStatus, PublicListenPort: int32(listenPort), @@ -152,7 +151,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana } relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, relayHost.ListenPort)) if err == nil { - peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{ + peerConfMap[host.PublicKey.String()] = models.PeerConf{ IsRelayed: true, RelayedTo: relayTo, @@ -193,11 +192,11 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana } // GetProxyUpdateForHost - gets the proxy update for host -func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload, error) { - proxyPayload := proxy_models.ProxyManagerPayload{ - Action: proxy_models.ProxyUpdate, +func GetProxyUpdateForHost(host *models.Host) (models.ProxyManagerPayload, error) { + proxyPayload := models.ProxyManagerPayload{ + Action: models.ProxyUpdate, } - peerConfMap := make(map[string]proxy_models.PeerConf) + peerConfMap := make(map[string]models.PeerConf) if host.IsRelayed { relayHost, err := GetHost(host.RelayedBy) if err == nil { @@ -214,14 +213,14 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload, } if host.IsRelay { relayedHosts := GetRelayedHosts(host) - relayPeersMap := make(map[string]proxy_models.RelayedConf) + relayPeersMap := make(map[string]models.RelayedConf) for _, relayedHost := range relayedHosts { relayedHost := relayedHost payload, err := GetPeerUpdateForHost(&relayedHost) if err == nil { relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, getPeerListenPort(&relayedHost))) if udpErr == nil { - relayPeersMap[relayedHost.PublicKey.String()] = proxy_models.RelayedConf{ + relayPeersMap[relayedHost.PublicKey.String()] = models.RelayedConf{ RelayedPeerEndpoint: relayedEndpoint, RelayedPeerPubKey: relayedHost.PublicKey.String(), Peers: payload.Peers, @@ -254,10 +253,10 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload, if err != nil { continue } - var currPeerConf proxy_models.PeerConf + var currPeerConf models.PeerConf var found bool if currPeerConf, found = peerConfMap[peerHost.PublicKey.String()]; !found { - currPeerConf = proxy_models.PeerConf{ + currPeerConf = models.PeerConf{ Proxy: peerHost.ProxyEnabled, PublicListenPort: int32(getPeerListenPort(peerHost)), } @@ -787,7 +786,7 @@ func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, e } -func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_models.PeerConf) ([]wgtypes.PeerConfig, map[string]proxy_models.PeerConf, error) { +func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]models.PeerConf) ([]wgtypes.PeerConfig, map[string]models.PeerConf, error) { var peers []wgtypes.PeerConfig host, err := GetHost(node.HostID.String()) if err != nil { @@ -836,7 +835,7 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_model ReplaceAllowedIPs: true, AllowedIPs: allowedips, } - extConf := proxy_models.PeerConf{ + extConf := models.PeerConf{ IsExtClient: true, Address: net.ParseIP(extPeer.Address), } diff --git a/metrics/metrics.go b/metrics/metrics.go new file mode 100644 index 00000000..97322a5a --- /dev/null +++ b/metrics/metrics.go @@ -0,0 +1,110 @@ +package metrics + +import ( + "fmt" + "sync" + "time" + + "github.com/go-ping/ping" + "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/models" +) + +// lock for metrics map +var metricsMapLock = &sync.RWMutex{} + +// metrics data map +var metricsPeerMap = make(map[string]map[string]*models.ProxyMetric) + +// GetMetricByServer - get metric data of peers by server +func GetMetricByServer(server string) map[string]*models.ProxyMetric { + metricsMapLock.RLock() + defer metricsMapLock.RUnlock() + if _, ok := metricsPeerMap[server]; !ok { + return nil + } + return metricsPeerMap[server] +} + +// GetMetric - fetches the metric data for the peer +func GetMetric(server, peerKey string) models.ProxyMetric { + metric := models.ProxyMetric{} + peerMetricMap := GetMetricByServer(server) + metricsMapLock.RLock() + defer metricsMapLock.RUnlock() + if peerMetricMap == nil { + return metric + } + if m, ok := peerMetricMap[peerKey]; ok && m != nil { + metric = *m + } + return metric +} + +// UpdateMetric - updates metric data for the peer +func UpdateMetric(server, peerKey string, metric *models.ProxyMetric) { + metricsMapLock.Lock() + defer metricsMapLock.Unlock() + if metricsPeerMap[server] == nil { + metricsPeerMap[server] = make(map[string]*models.ProxyMetric) + } + metricsPeerMap[server][peerKey] = metric +} + +// UpdateMetricByPeer - updates metrics data by peer public key +func UpdateMetricByPeer(peerKey string, metric *models.ProxyMetric, onlyTraffic bool) { + metricsMapLock.Lock() + defer metricsMapLock.Unlock() + for server, peerKeyMap := range metricsPeerMap { + if peerMetric, ok := peerKeyMap[peerKey]; ok { + peerMetric.TrafficRecieved += metric.TrafficRecieved + peerMetric.TrafficSent += metric.TrafficSent + if !onlyTraffic { + peerMetric.LastRecordedLatency = metric.LastRecordedLatency + } + + metricsPeerMap[server][peerKey] = peerMetric + } + } +} + +// ResetMetricsForPeer - reset metrics for peer +func ResetMetricsForPeer(server, peerKey string) { + metricsMapLock.Lock() + defer metricsMapLock.Unlock() + delete(metricsPeerMap[server], peerKey) +} + +// ResetMetricForNode - resets node level metrics +func ResetMetricForNode(server, peerKey, peerID string) { + metric := GetMetric(server, peerKey) + delete(metric.NodeConnectionStatus, peerID) + UpdateMetric(server, peerKey, &metric) +} + +const MetricCollectionInterval = time.Second * 25 + +// PeerConnectionStatus - get peer connection status by pinging +func PeerConnectionStatus(address string) (connected bool) { + fmt.Println("PINGER ADDR: ", address) + pinger, err := ping.NewPinger(address) + if err != nil { + logger.Log(0, "could not initiliaze ping peer address", address, err.Error()) + connected = false + } else { + pinger.Timeout = time.Second * 2 + err = pinger.Run() + if err != nil { + logger.Log(0, "failed to ping on peer address", address, err.Error()) + return false + } else { + pingStats := pinger.Statistics() + if pingStats.PacketsRecv > 0 { + connected = true + return + } + } + } + + return +} diff --git a/models/mqtt.go b/models/mqtt.go index 5fb1781e..71a203d0 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -1,30 +1,29 @@ package models import ( - proxy_models "github.com/gravitl/netclient/nmproxy/models" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) // PeerUpdate - struct type PeerUpdate struct { - Network string `json:"network" bson:"network" yaml:"network"` - ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"` - ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"` - Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` - DNS string `json:"dns" bson:"dns" yaml:"dns"` - PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` - ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` + Network string `json:"network" bson:"network" yaml:"network"` + ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"` + ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"` + Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` + DNS string `json:"dns" bson:"dns" yaml:"dns"` + PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` + ProxyUpdate ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` } // HostPeerUpdate - struct for host peer updates type HostPeerUpdate struct { - Host Host `json:"host" bson:"host" yaml:"host"` - ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"` - ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"` - Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"` - Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` - PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` - ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` + Host Host `json:"host" bson:"host" yaml:"host"` + ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"` + ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"` + Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"` + Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` + PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` + ProxyUpdate ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` } // NetworkInfo - struct for network info diff --git a/models/proxy.go b/models/proxy.go new file mode 100644 index 00000000..6e69c9d7 --- /dev/null +++ b/models/proxy.go @@ -0,0 +1,145 @@ +package models + +import ( + "context" + "crypto/md5" + "fmt" + "net" + "sync" + "time" + + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +// ProxyAction - type for proxy action +type ProxyAction string + +const ( + // default proxy port + NmProxyPort = 51722 + // default CIDR for proxy peers + DefaultCIDR = "127.0.0.1/8" + // PersistentKeepaliveInterval - default keepalive for wg peer + DefaultPersistentKeepaliveInterval = time.Duration(time.Second * 20) + + // ProxyUpdate - constant for proxy update action + ProxyUpdate ProxyAction = "PROXY_UPDATE" + // ProxyDeletePeers - constant for proxy delete peers action + ProxyDeletePeers ProxyAction = "PROXY_DELETE" + // ProxyDeleteAllPeers - constant for proxy delete all peers action + ProxyDeleteAllPeers ProxyAction = "PROXY_DELETE_ALL" + // NoProxy - constant for no ProxyAction + NoProxy ProxyAction = "NO_PROXY" +) + +// PeerConnMap - type for peer conn config map +type PeerConnMap map[string]*Conn + +// Proxy - struct for proxy config +type Proxy struct { + PeerPublicKey wgtypes.Key + IsExtClient bool + PeerConf wgtypes.PeerConfig + PeerEndpoint *net.UDPAddr + RemoteConnAddr *net.UDPAddr + LocalConnAddr *net.UDPAddr + ListenPort int + ProxyStatus bool +} + +// Conn is a peer Connection configuration +type Conn struct { + // Key is a public key of a remote peer + Key wgtypes.Key + IsExtClient bool + IsRelayed bool + RelayedEndpoint *net.UDPAddr + Config Proxy + StopConn func() + ResetConn func() + LocalConn net.Conn + Mutex *sync.RWMutex + NetworkSettings map[string]Settings + ServerMap map[string]struct{} +} + +// RemotePeer - struct remote peer data +type RemotePeer struct { + PeerKey string + Endpoint *net.UDPAddr + IsExtClient bool + LocalConn net.Conn + CancelFunc context.CancelFunc + CommChan chan *net.UDPAddr +} + +// HostInfo - struct for host information +type HostInfo struct { + PublicIp net.IP + PrivIp net.IP + PubPort int + PrivPort int + ProxyEnabled bool +} + +// RelayedConf - struct relayed peers config +type RelayedConf struct { + RelayedPeerEndpoint *net.UDPAddr `json:"relayed_peer_endpoint"` + RelayedPeerPubKey string `json:"relayed_peer_pub_key"` + Peers []wgtypes.PeerConfig `json:"relayed_peers"` +} + +// PeerConf - struct for peer config in the network +type PeerConf struct { + Proxy bool `json:"proxy"` + PublicListenPort int32 `json:"public_listen_port"` + IsExtClient bool `json:"is_ext_client"` + Address net.IP `json:"address"` + ExtInternalIp net.IP `json:"ext_internal_ip"` + IsRelayed bool `json:"is_relayed"` + RelayedTo *net.UDPAddr `json:"relayed_to"` +} + +// ConvPeerKeyToHash - converts peer key to a md5 hash +func ConvPeerKeyToHash(peerKey string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(peerKey))) +} + +// IsPublicIP indicates whether IP is public or not. +func IsPublicIP(ip net.IP) bool { + if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsPrivate() { + return false + } + return true +} + +// ProxyManagerPayload - struct for proxy manager payload +type ProxyManagerPayload struct { + Action ProxyAction `json:"action"` + InterfaceName string `json:"interface_name"` + Server string `json:"server"` + //WgAddr string `json:"wg_addr"` + Peers []wgtypes.PeerConfig `json:"peers"` + PeerMap map[string]PeerConf `json:"peer_map"` + IsIngress bool `json:"is_ingress"` + IsRelayed bool `json:"is_relayed"` + RelayedTo *net.UDPAddr `json:"relayed_to"` + IsRelay bool `json:"is_relay"` + RelayedPeerConf map[string]RelayedConf `json:"relayed_conf"` +} + +// Metric - struct for metric data +type ProxyMetric struct { + NodeConnectionStatus map[string]bool `json:"node_connection_status"` + LastRecordedLatency uint64 `json:"last_recorded_latency"` + TrafficSent int64 `json:"traffic_sent"` // stored in MB + TrafficRecieved int64 `json:"traffic_recieved"` // stored in MB +} + +// Settings - struct for host settings +type Settings struct { + IsRelay bool + IsIngressGateway bool + IsRelayed bool + RelayedTo *net.UDPAddr +} diff --git a/mq/publishers.go b/mq/publishers.go index 652dab7e..08d6c7e1 100644 --- a/mq/publishers.go +++ b/mq/publishers.go @@ -6,7 +6,6 @@ import ( "fmt" "time" - proxy_models "github.com/gravitl/netclient/nmproxy/models" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" @@ -46,7 +45,7 @@ func PublishSingleHostUpdate(host *models.Host) error { if err != nil { return err } - proxyUpdate.Action = proxy_models.ProxyUpdate + proxyUpdate.Action = models.ProxyUpdate peerUpdate.ProxyUpdate = proxyUpdate } From 4d4252d271fe30bf83f4786f441684e08c5cfe0c Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 30 Jan 2023 10:23:43 -0500 Subject: [PATCH 06/14] leave netclient specific structs in netclient --- models/proxy.go | 65 ------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/models/proxy.go b/models/proxy.go index 6e69c9d7..7c918442 100644 --- a/models/proxy.go +++ b/models/proxy.go @@ -1,11 +1,7 @@ package models import ( - "context" - "crypto/md5" - "fmt" "net" - "sync" "time" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" @@ -17,8 +13,6 @@ type ProxyAction string const ( // default proxy port NmProxyPort = 51722 - // default CIDR for proxy peers - DefaultCIDR = "127.0.0.1/8" // PersistentKeepaliveInterval - default keepalive for wg peer DefaultPersistentKeepaliveInterval = time.Duration(time.Second * 20) @@ -32,9 +26,6 @@ const ( NoProxy ProxyAction = "NO_PROXY" ) -// PeerConnMap - type for peer conn config map -type PeerConnMap map[string]*Conn - // Proxy - struct for proxy config type Proxy struct { PeerPublicKey wgtypes.Key @@ -47,41 +38,6 @@ type Proxy struct { ProxyStatus bool } -// Conn is a peer Connection configuration -type Conn struct { - // Key is a public key of a remote peer - Key wgtypes.Key - IsExtClient bool - IsRelayed bool - RelayedEndpoint *net.UDPAddr - Config Proxy - StopConn func() - ResetConn func() - LocalConn net.Conn - Mutex *sync.RWMutex - NetworkSettings map[string]Settings - ServerMap map[string]struct{} -} - -// RemotePeer - struct remote peer data -type RemotePeer struct { - PeerKey string - Endpoint *net.UDPAddr - IsExtClient bool - LocalConn net.Conn - CancelFunc context.CancelFunc - CommChan chan *net.UDPAddr -} - -// HostInfo - struct for host information -type HostInfo struct { - PublicIp net.IP - PrivIp net.IP - PubPort int - PrivPort int - ProxyEnabled bool -} - // RelayedConf - struct relayed peers config type RelayedConf struct { RelayedPeerEndpoint *net.UDPAddr `json:"relayed_peer_endpoint"` @@ -100,19 +56,6 @@ type PeerConf struct { RelayedTo *net.UDPAddr `json:"relayed_to"` } -// ConvPeerKeyToHash - converts peer key to a md5 hash -func ConvPeerKeyToHash(peerKey string) string { - return fmt.Sprintf("%x", md5.Sum([]byte(peerKey))) -} - -// IsPublicIP indicates whether IP is public or not. -func IsPublicIP(ip net.IP) bool { - if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsPrivate() { - return false - } - return true -} - // ProxyManagerPayload - struct for proxy manager payload type ProxyManagerPayload struct { Action ProxyAction `json:"action"` @@ -135,11 +78,3 @@ type ProxyMetric struct { TrafficSent int64 `json:"traffic_sent"` // stored in MB TrafficRecieved int64 `json:"traffic_recieved"` // stored in MB } - -// Settings - struct for host settings -type Settings struct { - IsRelay bool - IsIngressGateway bool - IsRelayed bool - RelayedTo *net.UDPAddr -} From 4e3ff513b7cfbf08dc561f15f28800de2d62351f Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 30 Jan 2023 10:47:40 -0500 Subject: [PATCH 07/14] remove point to site from network model --- models/network.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/models/network.go b/models/network.go index 7eb67d2a..fd6a9f8c 100644 --- a/models/network.go +++ b/models/network.go @@ -25,7 +25,6 @@ type Network struct { IsLocal string `json:"islocal" bson:"islocal" validate:"checkyesorno"` IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"` IsIPv6 string `json:"isipv6" bson:"isipv6" validate:"checkyesorno"` - IsPointToSite string `json:"ispointtosite" bson:"ispointtosite" validate:"checkyesorno"` DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"` DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"` DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"` @@ -56,9 +55,6 @@ func (network *Network) SetDefaults() { if network.IsLocal == "" { network.IsLocal = "no" } - if network.IsPointToSite == "" { - network.IsPointToSite = "no" - } if network.DefaultInterface == "" { if len(network.NetID) < 13 { network.DefaultInterface = "nm-" + network.NetID From 92af578ab1660691fb22ee6c56ba8610f49b5a27 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 30 Jan 2023 11:04:22 -0500 Subject: [PATCH 08/14] remove point to site from nmctl --- cli/cmd/network/create.go | 4 ---- cli/cmd/network/flags.go | 1 - cli/cmd/network/update.go | 4 ---- 3 files changed, 9 deletions(-) diff --git a/cli/cmd/network/create.go b/cli/cmd/network/create.go index 10615eed..08c17e5f 100644 --- a/cli/cmd/network/create.go +++ b/cli/cmd/network/create.go @@ -41,9 +41,6 @@ var networkCreateCmd = &cobra.Command{ if defaultACL { network.DefaultACL = "yes" } - if pointToSite { - network.IsPointToSite = "yes" - } network.DefaultInterface = defaultInterface network.DefaultListenPort = int32(defaultListenPort) network.NodeLimit = int32(nodeLimit) @@ -69,7 +66,6 @@ func init() { networkCreateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?") networkCreateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?") networkCreateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?") - networkCreateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?") networkCreateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface") networkCreateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated") networkCreateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated") diff --git a/cli/cmd/network/flags.go b/cli/cmd/network/flags.go index 38c1448d..286c8fbb 100644 --- a/cli/cmd/network/flags.go +++ b/cli/cmd/network/flags.go @@ -8,7 +8,6 @@ var ( udpHolePunch bool localNetwork bool defaultACL bool - pointToSite bool defaultInterface string defaultListenPort int nodeLimit int diff --git a/cli/cmd/network/update.go b/cli/cmd/network/update.go index e171487b..93ae9f26 100644 --- a/cli/cmd/network/update.go +++ b/cli/cmd/network/update.go @@ -44,9 +44,6 @@ var networkUpdateCmd = &cobra.Command{ if defaultACL { network.DefaultACL = "yes" } - if pointToSite { - network.IsPointToSite = "yes" - } network.DefaultInterface = defaultInterface network.DefaultListenPort = int32(defaultListenPort) network.NodeLimit = int32(nodeLimit) @@ -70,7 +67,6 @@ func init() { networkUpdateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?") networkUpdateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?") networkUpdateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?") - networkUpdateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?") networkUpdateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface") networkUpdateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated") networkUpdateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated") From 4e2e66c06fd7e91191c4dbedcf3761e527e79584 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 31 Jan 2023 08:53:37 -0500 Subject: [PATCH 09/14] move struct back to netclient --- models/proxy.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/models/proxy.go b/models/proxy.go index 7c918442..ae8bfd99 100644 --- a/models/proxy.go +++ b/models/proxy.go @@ -26,18 +26,6 @@ const ( NoProxy ProxyAction = "NO_PROXY" ) -// Proxy - struct for proxy config -type Proxy struct { - PeerPublicKey wgtypes.Key - IsExtClient bool - PeerConf wgtypes.PeerConfig - PeerEndpoint *net.UDPAddr - RemoteConnAddr *net.UDPAddr - LocalConnAddr *net.UDPAddr - ListenPort int - ProxyStatus bool -} - // RelayedConf - struct relayed peers config type RelayedConf struct { RelayedPeerEndpoint *net.UDPAddr `json:"relayed_peer_endpoint"` From 48f8a1398a1426a7c086ccad139a4c02dea94bb8 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 31 Jan 2023 09:00:04 -0500 Subject: [PATCH 10/14] review comments --- metrics/metrics.go | 1 + 1 file changed, 1 insertion(+) diff --git a/metrics/metrics.go b/metrics/metrics.go index 97322a5a..eb4b5f40 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -82,6 +82,7 @@ func ResetMetricForNode(server, peerKey, peerID string) { UpdateMetric(server, peerKey, &metric) } +// MetricCollectionInterval - collection interval for metrics const MetricCollectionInterval = time.Second * 25 // PeerConnectionStatus - get peer connection status by pinging From 5a59d6e49330f2e6fd39c1ce6992287d926328c6 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Wed, 1 Feb 2023 11:00:25 -0500 Subject: [PATCH 11/14] ensured host, if found, keeps password --- controllers/node.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/controllers/node.go b/controllers/node.go index 7a3de32b..0771fad5 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -524,7 +524,7 @@ func createNode(w http.ResponseWriter, r *http.Request) { } if !logic.IsVersionComptatible(data.Host.Version) { - err := errors.New("incomatible netclient version") + err := errors.New("incompatible netclient version") logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } @@ -600,6 +600,7 @@ func createNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + data.Host = *host } else { logger.Log(0, "error creating host", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) From a10e1809e4dddd5aa826833b0ce6356a76ebcd51 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Wed, 1 Feb 2023 20:16:45 +0400 Subject: [PATCH 12/14] skip ext client from peer list when disabled --- logic/peers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index b5d20c8f..07ae8191 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -741,7 +741,7 @@ func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, e } if host.PublicKey.String() == extPeer.PublicKey || - extPeer.IngressGatewayID != node.ID.String() { + extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled { continue } @@ -806,7 +806,7 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]models.Peer } if host.PublicKey.String() == extPeer.PublicKey || - extPeer.IngressGatewayID != node.ID.String() { + extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled { continue } From f034c748382ecb7798a9c9caa32f3412ab4100a5 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Wed, 1 Feb 2023 11:21:30 -0500 Subject: [PATCH 13/14] fixed default expiration date setting and removed unused func --- logic/nodes.go | 26 -------------------------- models/node.go | 2 +- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/logic/nodes.go b/logic/nodes.go index c6fdee84..1502941f 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -239,7 +239,6 @@ func SetNodeDefaults(node *models.Node) { if err == nil { node.NetworkRange6 = *cidr } - node.ExpirationDateTime = time.Now().Add(models.TEN_YEARS_IN_SECONDS) if node.DefaultACL == "" { node.DefaultACL = parentNetwork.DefaultACL @@ -260,7 +259,6 @@ func SetNodeDefaults(node *models.Node) { node.SetLastCheckIn() node.SetDefaultConnected() node.SetExpirationDateTime() - } // GetRecordKey - get record key @@ -272,30 +270,6 @@ func GetRecordKey(id string, network string) (string, error) { return id + "###" + network, nil } -// GetNodeByMacAddress - gets a node by mac address -func GetNodeByMacAddress(network string, macaddress string) (models.Node, error) { - - var node models.Node - - key, err := GetRecordKey(macaddress, network) - if err != nil { - return node, err - } - - record, err := database.FetchRecord(database.NODES_TABLE_NAME, key) - if err != nil { - return models.Node{}, err - } - - if err = json.Unmarshal([]byte(record), &node); err != nil { - return models.Node{}, err - } - - SetNodeDefaults(&node) - - return node, nil -} - // GetNodesByAddress - gets a node by mac address func GetNodesByAddress(network string, addresses []string) ([]models.Node, error) { var nodes []models.Node diff --git a/models/node.go b/models/node.go index 0e1d85c8..60512176 100644 --- a/models/node.go +++ b/models/node.go @@ -15,7 +15,7 @@ const ( // NODE_SERVER_NAME - the default server name NODE_SERVER_NAME = "netmaker" // TEN_YEARS_IN_SECONDS - ten years in seconds - TEN_YEARS_IN_SECONDS = 300000000 + TEN_YEARS_IN_SECONDS = 315670000000000000 // MAX_NAME_LENGTH - max name length of node MAX_NAME_LENGTH = 62 // == ACTIONS == (can only be set by server) From 3d364774f3015f0727c0c63f2476fdc294604ab1 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Wed, 1 Feb 2023 11:28:35 -0500 Subject: [PATCH 14/14] concealed hostpass return --- controllers/node.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/controllers/node.go b/controllers/node.go index 0771fad5..b7573053 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -653,6 +653,8 @@ func createNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + data.Host.HostPass = "" // client should not change password after join + // concealing hash response := models.NodeJoinResponse{ Node: data.Node, ServerConfig: server,