-
Notifications
You must be signed in to change notification settings - Fork 2k
Add super-old (and unsupported) PXE scripts from datasheets site #4167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
documentation/asciidoc/computers/remote-access/old/prepare_pxetools.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#!/bin/bash | ||
|
||
set -e | ||
|
||
sudo apt install -y python3 python3-pip ipcalc | ||
sudo pip3 install tabulate | ||
|
||
# Get network info | ||
NAMESERVER=$(cat /etc/resolv.conf | grep nameserver | head -n 1 | cut -d " " -f2) | ||
GATEWAY=$(ip -4 route | grep default | head -n 1 | cut -d " " -f3) | ||
IP=$(ifconfig eth0 | grep "inet addr" | cut -d " " -f 12 | cut -d ":" -f 2) | ||
BRD=$(ifconfig eth0 | grep "inet addr" | cut -d " " -f 14 | cut -d ":" -f 2) | ||
NETMASK=$(ifconfig eth0 | grep "inet addr" | cut -d " " -f 16 | cut -d ":" -f 2) | ||
|
||
echo "IP: $IP" | ||
echo "Netmask: $NETMASK" | ||
echo "Broadcast: $BRD" | ||
echo "Nameserver: $NAMESERVER" | ||
echo "Gateway: $GATEWAY" | ||
|
||
echo "Setting static IP using above information" | ||
|
||
cat << EOF | sudo tee /etc/network/interfaces | ||
auto lo | ||
iface lo inet loopback | ||
|
||
auto eth0 | ||
iface eth0 inet static | ||
address $IP | ||
netmask $NETMASK | ||
gateway $GATEWAY | ||
EOF | ||
|
||
sudo systemctl stop dhcpcd | ||
sudo systemctl disable dhcpcd | ||
sudo systemctl restart networking | ||
|
||
# In case it is already set | ||
sudo chattr -i /etc/resolv.conf | ||
|
||
echo "Setting nameserver" | ||
cat << EOF | sudo tee /etc/resolv.conf | ||
nameserver $NAMESERVER | ||
EOF | ||
|
||
# Prevent DNSMasq from changing | ||
sudo chattr +i /etc/resolv.conf | ||
|
||
sudo apt install -y nfs-kernel-server dnsmasq iptables-persistent unzip nmap kpartx rsync | ||
|
||
sudo mkdir -p /nfs | ||
sudo mkdir -p /tftpboot | ||
sudo cp -r /boot /tftpboot/base | ||
sudo cp /boot/bootcode.bin /tftpboot | ||
sudo chmod -R 777 /tftpboot | ||
|
||
echo "Writing dnsmasq.conf" | ||
cat << EOF | sudo tee /etc/dnsmasq.conf | ||
port=0 | ||
dhcp-range=$BRD,proxy | ||
bind-interfaces | ||
log-dhcp | ||
enable-tftp | ||
log-facility=/var/log/dnsmasq | ||
tftp-root=/tftpboot | ||
pxe-service=0,"Raspberry Pi Boot" | ||
EOF | ||
|
||
# Flush any rules that might exist | ||
sudo iptables -t raw --flush | ||
|
||
# Create the DHCP_clients chain in the 'raw' table | ||
sudo iptables -t raw -N DHCP_clients || true | ||
|
||
# Incoming DHCP, pass to chain processing DHCP | ||
sudo iptables -t raw -A PREROUTING -p udp --dport 67 -j DHCP_clients | ||
|
||
# Deny clients not in chain not listed above | ||
sudo iptables -t raw -A DHCP_clients -j DROP | ||
|
||
sudo iptables-save | sudo tee /etc/iptables/rules.v4 | ||
|
||
# Start services | ||
sudo systemctl enable dnsmasq | ||
sudo systemctl restart dnsmasq | ||
sudo systemctl enable rpcbind | ||
sudo systemctl restart rpcbind | ||
sudo systemctl enable nfs-kernel-server | ||
sudo systemctl restart nfs-kernel-server | ||
|
||
echo "Getting latest Raspberry Pi OS lite image to use as NFS root" | ||
# Get latest Raspberry Pi OS lite image | ||
sudo mkdir -p /nfs/bases | ||
cd /nfs/bases | ||
sudo wget -O raspios_latest.zip https://downloads.raspberrypi.org/raspios_lite_armhf_latest | ||
sudo unzip raspios_latest.zip | ||
sudo rm raspios_latest.zip | ||
|
||
sudo wget -O /usr/local/sbin/pxetools https://datasheets.raspberrypi.org/soft/pxetools.py | ||
sudo chmod +x /usr/local/sbin/pxetools | ||
|
||
echo "Now run sudo pxetools --add \$serial" |
234 changes: 234 additions & 0 deletions
234
documentation/asciidoc/computers/remote-access/old/pxetools.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import os | ||
import re | ||
import subprocess | ||
import time | ||
import sys | ||
from tabulate import tabulate | ||
|
||
HELP = "Usage:\n\ | ||
\tpxetools --add serial\n\ | ||
\tpxetools --remove serial\n\ | ||
\tpxetools --list\n" | ||
|
||
LAN = None | ||
NFS_IP = None | ||
|
||
def cmd(cmd, print_out=False, print_cmd=True, can_fail=False): | ||
if print_cmd: | ||
print("# {}".format(cmd)) | ||
|
||
out = None | ||
|
||
try: | ||
out = subprocess.check_output(cmd, shell=True).decode() | ||
except: | ||
if not can_fail: | ||
raise | ||
|
||
if print_out: | ||
print(out) | ||
|
||
return out | ||
|
||
def add(): | ||
serial = None | ||
if len(sys.argv) != 3: | ||
if os.path.exists("/usr/local/sbin/get_serial"): | ||
# Auto detect | ||
print("Will try and auto detect serial. Please plug in your Pi now!") | ||
cmd("systemctl stop dnsmasq") | ||
cmd("iptables -t raw --flush") | ||
|
||
try: | ||
serial = cmd("get_serial", print_cmd=False).rstrip() | ||
except KeyboardInterrupt: | ||
cmd("iptables-restore < /etc/iptables/rules.v4") | ||
cmd("systemctl start dnsmasq") | ||
sys.exit() | ||
|
||
print("Found serial") | ||
cmd("iptables-restore < /etc/iptables/rules.v4") | ||
cmd("systemctl start dnsmasq") | ||
else: | ||
serial = sys.argv[2] | ||
|
||
# Validate serial | ||
serial = serial.lstrip("0") | ||
if not re.search("^[0-9a-f]{8}$", serial): | ||
raise Exception("Invalid serial number {}".format(serial)) | ||
|
||
print("Serial: {}".format(serial)) | ||
owner = input("Owner Name (ex Gordon): ") | ||
name = input("Name for pi: ") | ||
|
||
print("Select a base image:") | ||
selection = ["I will prepare my own filesystem"] + os.listdir('/nfs/bases') | ||
for i in range (0, len(selection)): | ||
print("\t{}. {}".format(i + 1, selection[i])) | ||
|
||
img_choice = input("Enter an option number: ") | ||
|
||
tftp_path = "/tftpboot/{}".format(serial) | ||
nfs_path = "/nfs/{}".format(serial) | ||
if os.path.exists(tftp_path): | ||
raise Exception("{} already exists!".format(tftp_path)) | ||
|
||
valid_img_choice = True | ||
try: | ||
img_choice = int(img_choice) | ||
# Make 0 based again | ||
img_choice -= 1 | ||
except ValueError: | ||
valid_img_choice = False | ||
|
||
if img_choice < 0 or img_choice > (len(selection) - 1) or (not valid_img_choice): | ||
raise Exception("Invalid image choice {}".format(img_choice)) | ||
|
||
img = None | ||
if img_choice > 0: | ||
img = "/nfs/bases/{}".format(selection[img_choice]) | ||
|
||
print("\nSetting up pi...\n") | ||
|
||
cmd("iptables -t raw -I DHCP_clients -m mac --mac-source {0} -j ACCEPT".format(mac(serial))) | ||
cmd("iptables-save > /etc/iptables/rules.v4") | ||
cmd("mkdir {}".format(tftp_path)) | ||
cmd("cp -r /tftpboot/base/* {}".format(tftp_path)) | ||
cmd("mkdir {}".format(nfs_path)) | ||
cmd("echo \"{} *(rw,sync,no_subtree_check,no_root_squash)\" >> /etc/exports".format(nfs_path)) | ||
cmd("exportfs -a") | ||
|
||
cmdline_txt = "dwc_otg.lpm_enable=0 root=/dev/nfs nfsroot={}:{} rw ip=dhcp rootwait elevator=deadline".format(NFS_IP, nfs_path) | ||
cmd("echo \"{}\" > {}/cmdline.txt".format(cmdline_txt, tftp_path)) | ||
cmd("echo \"{}\" > {}/owner".format(owner, tftp_path)) | ||
cmd("echo \"{}\" > {}/name".format(name, tftp_path)) | ||
|
||
if img_choice: | ||
cmd("mkdir -p /mnt/tmp") | ||
cmd("kpartx -a -v {}".format(img), print_out=True) | ||
time.sleep(1) | ||
cmd("mount /dev/mapper/loop0p2 /mnt/tmp") | ||
cmd("rsync -a /mnt/tmp/ {}/".format(nfs_path)) | ||
cmd("umount /mnt/tmp") | ||
cmd("echo > {}/etc/fstab".format(nfs_path)) | ||
cmd("cd {}/etc/init.d; rm dhcpcd dphys-swapfile raspi-config resize2fs_once".format(nfs_path)) | ||
cmd("cd {}/etc/systemd/system; rm -r dhcp* multi-user.target.wants/dhcp*".format(nfs_path)) | ||
cmd("mount /dev/mapper/loop0p1 /mnt/tmp") | ||
cmd("rsync -a --exclude bootcode.bin --exclude start.elf --exclude cmdline.txt /mnt/tmp/ {}/".format(tftp_path)) | ||
cmd("umount /mnt/tmp") | ||
cmd("kpartx -d -v {}".format(img), print_out=True) | ||
else: | ||
print("You opted to prep your own system so please put files in:\n\t{}\n\t{}".format(tftp_path, nfs_path)) | ||
print("I have wrote you a cmdline.txt so don't change it:") | ||
print(cmdline_txt) | ||
|
||
print("Should be working. You might have to wait a couple of minutes before SSH lets you in") | ||
|
||
def remove(): | ||
serial = sys.argv[2] | ||
|
||
if not re.search("^[0-9a-f]{8}$", serial): | ||
raise Exception("Invalid serial number {}".format(serial)) | ||
|
||
sure = "" | ||
while sure != "Y" and sure != "N": | ||
sure = input("ARE YOU SURE YOU WANT TO DELETE {}? Y/N: ".format(serial)) | ||
|
||
if sure == "N": | ||
print("Aborting") | ||
return | ||
|
||
cmd("rm -rf /tftpboot/{}".format(serial), can_fail=True) | ||
|
||
nfspath = "/nfs/{}".format(serial) | ||
cmd("rm -rf {}".format(nfspath), can_fail=True) | ||
|
||
print("Removing from /etc/exports") | ||
with open("/etc/exports", 'r+') as f: | ||
export = f.read() | ||
f.seek(0) | ||
|
||
for l in export.splitlines(): | ||
if l.startswith(nfspath) == False: | ||
f.write(l + "\n") | ||
|
||
f.truncate() | ||
|
||
mac_uppercase = mac(serial).upper() | ||
print("Removing from iptables rules") | ||
with open("/etc/iptables/rules.v4", 'r+') as f: | ||
rules = f.read() | ||
f.seek(0) | ||
|
||
for l in rules.splitlines(): | ||
if mac_uppercase not in l: | ||
f.write(l + "\n") | ||
|
||
f.truncate() | ||
|
||
cmd("iptables-restore < /etc/iptables/rules.v4") | ||
|
||
def mac(serial): | ||
# MAC is least significant bits of serial | ||
# Example: | ||
# b8:27:eb:be:e3:d2 | ||
# 0000000044bee3d2 | ||
prefix = "b8:27:eb:" | ||
suffix = serial[-6:] | ||
|
||
# Insert colon every 2 chars. Stolen from stackoverflow | ||
s = suffix | ||
s = ":".join(a+b for a,b in zip(s[::2], s[1::2])) | ||
return prefix + s | ||
|
||
def ip(mac): | ||
# Hacky way of getting IP from Mac Address | ||
cmdstr = ("nmap -sn -PR --min-rate 5000 --max-retries=0 {0} " | ||
"| grep -i -B 2 {1} | head -n 1 |" | ||
" awk '{{print $5}}'").format(LAN, mac) | ||
ip = cmd(cmdstr, print_cmd=False) | ||
if len(ip) == 0: | ||
ip = "Not found" | ||
else: | ||
ip = ip.rstrip() | ||
|
||
return ip | ||
|
||
def file_or_none(base, file): | ||
path = os.path.join(base, file) | ||
if not os.path.exists(path): | ||
return "Not Found" | ||
|
||
with open(path, 'r') as fh: | ||
return fh.read() | ||
|
||
def list(): | ||
tbl = [["Serial", "Owner", "Name", "MAC", "IP"]] | ||
pis = os.listdir("/tftpboot") | ||
pis = [p for p in pis if p != "base" and p != "bootcode.bin"] | ||
|
||
for p in pis: | ||
base = os.path.join("/tftpboot", p) | ||
tbl.append(["0x{}".format(p), file_or_none(base, "owner"), file_or_none(base, "name"), mac(p), ip(mac(p))]) | ||
|
||
print(tabulate(tbl, headers="firstrow")) | ||
|
||
if __name__ == "__main__": | ||
if os.geteuid() != 0: | ||
exit("Please run with sudo or as root user") | ||
|
||
LAN = cmd('ip -4 addr show dev eth0 | grep inet | cut -d " " -f6 | xargs ipcalc | grep Network | cut -d " " -f4', print_cmd=False).rstrip() | ||
NFS_IP = cmd('ifconfig eth0 | grep "inet addr" | cut -d " " -f 12 | cut -d ":" -f 2', print_cmd=False).rstrip() | ||
|
||
if len(sys.argv) == 1: | ||
print(HELP) | ||
elif sys.argv[1] == "--list": | ||
list() | ||
elif sys.argv[1] == "--add": | ||
add() | ||
elif sys.argv[1] == "--remove": | ||
remove() | ||
else: | ||
print(HELP) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this now refer to wherever
pxetools.py
will end up on the documentation site?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was assuming that I'd be able to point the redirect on datasheets to this new location? (when the time comes 😉 )