This script creates a bunch of Digital Ocean droplets. It’ll make up to 10 of the cheapest droplets, 1 per region.
It will also add the machine to Tailscale and place a tag on the droplet on Digital Ocean the Tailscale device ID so when it’s time to delete the droplet, we can use that tag to also remove it from Tailscale.
import requests
import time
TOKEN = 'xxxx'
HEADERS = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {TOKEN}',
}
USER_DATA_SCRIPT = r"""#!/bin/bash
# Define TAILSCALE_AUTH_KEY and DIGITALOCEAN_TOKEN at the beginning of the script
TAILSCALE_AUTH_KEY="xxxx"
DIGITALOCEAN_TOKEN="xxxx"
# Update the system and install jq
apt-get update
apt-get install -y jq
# Install tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# Start tailscale with the provided auth key
tailscale up --ssh --authkey "${TAILSCALE_AUTH_KEY}"
# Wait 5 seconds
sleep 5
# Get the ID of the Self object from tailscale status
SELF_ID=$(tailscale status --json | jq -r '.Self.ID')
# Check if we successfully retrieved the ID
if [ -z "$SELF_ID" ]; then
echo "Error: Failed to retrieve the ID from tailscale status."
exit 1
fi
echo "Retrieved ID: $SELF_ID"
# Create a new tag on DigitalOcean using the API
curl -X POST "https://api.digitalocean.com/v2/tags" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DIGITALOCEAN_TOKEN}" \
-d "{\"name\":\"${SELF_ID}\"}"
# Assuming you want to tag the droplet this script runs on, you can obtain its droplet ID from the metadata service
DROPLET_ID=$(curl -s http://169.254.169.254/metadata/v1/id)
# Add the droplet to the tag
curl -X POST "https://api.digitalocean.com/v2/tags/${SELF_ID}/resources" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DIGITALOCEAN_TOKEN}" \
-d "{\"resources\":[{\"resource_id\":\"${DROPLET_ID}\",\"resource_type\":\"droplet\"}]}"
"""
def list_regions():
response = requests.get("https://api.digitalocean.com/v2/regions", headers=HEADERS)
response.raise_for_status()
return response.json()['regions']
def list_sizes():
response = requests.get("https://api.digitalocean.com/v2/sizes", headers=HEADERS)
response.raise_for_status()
return response.json()['sizes']
def cheapest_droplet_per_region(regions, sizes):
cheapest_droplets = {}
for region in regions:
available_sizes = [size for size in sizes if region['slug'] in size['regions']]
if not available_sizes:
continue
min_size = min(available_sizes, key=lambda x: x['price_monthly'])
cheapest_droplets[region['slug']] = min_size['slug']
return cheapest_droplets
def create_droplet(region, size_slug):
data = {
"name": f"cheapest-{region}",
"region": region,
"size": size_slug,
"image": "debian-12-x64",
"ssh_keys": ["xxxx"],
"firewalls": ["xxxx"],
"user_data": USER_DATA_SCRIPT
}
response = requests.post("https://api.digitalocean.com/v2/droplets", headers=HEADERS, json=data)
response.raise_for_status()
return response.json()['droplet']
def main():
regions = list_regions()
sizes = list_sizes()
droplets_to_create = cheapest_droplet_per_region(regions, sizes)
count = 0
for region, size in droplets_to_create.items():
if count >= 10:
break
print(f"Creating droplet in {region} with size {size}")
create_droplet(region, size)
count += 1
if count < 10: # Only sleep if it's not the last iteration
time.sleep(10)
if __name__ == "__main__":
main()