254 lines
No EOL
9.1 KiB
Python
254 lines
No EOL
9.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Complete update script for site 982 CGNAT configuration
|
|
This script handles the complete update process including verification
|
|
"""
|
|
|
|
import os
|
|
import requests
|
|
import json
|
|
import sys
|
|
import time
|
|
|
|
# API configuration
|
|
NETBOX_URL = 'https://netbox.vntx.net/api/'
|
|
API_TOKEN = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
|
|
|
headers = {
|
|
'Authorization': f'Token {API_TOKEN}',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
}
|
|
|
|
def delete_prefix_by_cidr(cidr):
|
|
"""Delete a prefix by CIDR notation"""
|
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'prefix': cidr})
|
|
prefixes = response.json()['results']
|
|
|
|
deleted = False
|
|
for prefix in prefixes:
|
|
print(f"Deleting prefix {prefix['prefix']} (ID: {prefix['id']})")
|
|
response = requests.delete(f"{NETBOX_URL}ipam/prefixes/{prefix['id']}/", headers=headers)
|
|
if response.status_code == 204:
|
|
print(" ✓ Deleted successfully")
|
|
deleted = True
|
|
else:
|
|
print(f" ✗ Error: {response.status_code}")
|
|
|
|
return deleted
|
|
|
|
def delete_ip_by_address(address):
|
|
"""Delete an IP address by address string"""
|
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'address': address})
|
|
ips = response.json()['results']
|
|
|
|
deleted = False
|
|
for ip in ips:
|
|
print(f"Deleting IP {ip['address']} (ID: {ip['id']})")
|
|
response = requests.delete(f"{NETBOX_URL}ipam/ip-addresses/{ip['id']}/", headers=headers)
|
|
if response.status_code == 204:
|
|
print(" ✓ Deleted successfully")
|
|
deleted = True
|
|
else:
|
|
print(f" ✗ Error: {response.status_code}")
|
|
|
|
return deleted
|
|
|
|
def main():
|
|
print("=== Site 982 CGNAT Update Script ===\n")
|
|
|
|
# Step 1: Get site 982
|
|
print("1. Finding site 982...")
|
|
response = requests.get(f'{NETBOX_URL}dcim/sites/', headers=headers, params={'name': '982'})
|
|
sites = response.json()['results']
|
|
|
|
if not sites:
|
|
print("✗ Site 982 not found!")
|
|
sys.exit(1)
|
|
|
|
site = sites[0]
|
|
site_id = site['id']
|
|
print(f"✓ Found site: {site['name']} (ID: {site_id})")
|
|
|
|
# Step 2: Get the router
|
|
print("\n2. Finding 982-router...")
|
|
response = requests.get(f'{NETBOX_URL}dcim/devices/', headers=headers, params={'name': '982-router', 'site_id': site_id})
|
|
devices = response.json()['results']
|
|
|
|
if not devices:
|
|
print("✗ 982-router not found!")
|
|
sys.exit(1)
|
|
|
|
device = devices[0]
|
|
device_id = device['id']
|
|
print(f"✓ Found device: {device['name']} (ID: {device_id})")
|
|
|
|
# Step 3: Clean up old configurations
|
|
print("\n3. Cleaning up old configurations...")
|
|
|
|
# Delete old CGNAT prefix
|
|
print(" Removing old CGNAT prefix 100.64.32.0/22...")
|
|
delete_prefix_by_cidr('100.64.32.0/22')
|
|
|
|
# Delete any existing 100.64.48.0/20 prefix (from previous attempts)
|
|
print(" Removing any existing 100.64.48.0/20 prefix...")
|
|
delete_prefix_by_cidr('100.64.48.0/20')
|
|
|
|
# Delete old IP address
|
|
print(" Removing old IP 100.64.35.254/22...")
|
|
delete_ip_by_address('100.64.35.254/22')
|
|
|
|
# Delete any existing new IP (from previous attempts)
|
|
print(" Removing any existing 100.64.63.254/20...")
|
|
delete_ip_by_address('100.64.63.254/20')
|
|
|
|
# Step 4: Create or find CGNAT interface
|
|
print("\n4. Setting up CGNAT interface...")
|
|
response = requests.get(f'{NETBOX_URL}dcim/interfaces/', headers=headers, params={'device_id': device_id, 'name': 'cgnat'})
|
|
interfaces = response.json()['results']
|
|
|
|
if interfaces:
|
|
interface = interfaces[0]
|
|
interface_id = interface['id']
|
|
print(f"✓ Found existing CGNAT interface (ID: {interface_id})")
|
|
else:
|
|
# Create interface
|
|
interface_data = {
|
|
'device': device_id,
|
|
'name': 'cgnat',
|
|
'type': 'virtual',
|
|
'enabled': True,
|
|
'description': 'CGNAT interface'
|
|
}
|
|
response = requests.post(f'{NETBOX_URL}dcim/interfaces/', headers=headers, json=interface_data)
|
|
if response.status_code == 201:
|
|
interface = response.json()
|
|
interface_id = interface['id']
|
|
print(f"✓ Created CGNAT interface (ID: {interface_id})")
|
|
else:
|
|
print(f"✗ Error creating interface: {response.status_code}")
|
|
print(response.text)
|
|
sys.exit(1)
|
|
|
|
# Step 5: Get or create Customer role
|
|
print("\n5. Setting up Customer role...")
|
|
response = requests.get(f'{NETBOX_URL}ipam/roles/', headers=headers, params={'name': 'Customer'})
|
|
roles = response.json()['results']
|
|
|
|
if roles:
|
|
role = roles[0]
|
|
role_id = role['id']
|
|
print(f"✓ Found Customer role (ID: {role_id})")
|
|
else:
|
|
# Create role
|
|
role_data = {
|
|
'name': 'Customer',
|
|
'slug': 'customer'
|
|
}
|
|
response = requests.post(f'{NETBOX_URL}ipam/roles/', headers=headers, json=role_data)
|
|
if response.status_code == 201:
|
|
role = response.json()
|
|
role_id = role['id']
|
|
print(f"✓ Created Customer role (ID: {role_id})")
|
|
else:
|
|
print(f"✗ Error creating role: {response.status_code}")
|
|
sys.exit(1)
|
|
|
|
# Step 6: Create the new CGNAT prefix
|
|
print("\n6. Creating new CGNAT prefix 100.64.48.0/20...")
|
|
|
|
# Try creating without site first, then update
|
|
prefix_data = {
|
|
'prefix': '100.64.48.0/20',
|
|
'role': role_id,
|
|
'status': 'active',
|
|
'description': 'CGNAT subnet for site 982',
|
|
'tags': []
|
|
}
|
|
|
|
response = requests.post(f'{NETBOX_URL}ipam/prefixes/', headers=headers, json=prefix_data)
|
|
if response.status_code == 201:
|
|
prefix = response.json()
|
|
prefix_id = prefix['id']
|
|
print(f"✓ Created prefix (ID: {prefix_id})")
|
|
|
|
# Now try to assign site
|
|
print(" Assigning prefix to site 982...")
|
|
# Try different approaches
|
|
|
|
# Approach 1: PATCH with just site
|
|
patch_data = {'site': site_id}
|
|
response = requests.patch(f'{NETBOX_URL}ipam/prefixes/{prefix_id}/', headers=headers, json=patch_data)
|
|
|
|
if response.status_code != 200:
|
|
# Approach 2: PUT with all fields
|
|
put_data = {
|
|
'prefix': '100.64.48.0/20',
|
|
'site': site_id,
|
|
'role': role_id,
|
|
'status': 'active',
|
|
'description': 'CGNAT subnet for site 982'
|
|
}
|
|
response = requests.put(f'{NETBOX_URL}ipam/prefixes/{prefix_id}/', headers=headers, json=put_data)
|
|
|
|
if response.status_code in [200, 201]:
|
|
updated_prefix = response.json()
|
|
if updated_prefix.get('site'):
|
|
print(f" ✓ Prefix assigned to site {updated_prefix['site']['name']}")
|
|
else:
|
|
print(" ⚠ Warning: Site assignment may have failed")
|
|
else:
|
|
print(f" ⚠ Warning: Could not assign site: {response.status_code}")
|
|
else:
|
|
print(f"✗ Error creating prefix: {response.status_code}")
|
|
print(response.text)
|
|
sys.exit(1)
|
|
|
|
# Step 7: Create the new IP address
|
|
print("\n7. Creating new IP address 100.64.63.254/20...")
|
|
|
|
ip_data = {
|
|
'address': '100.64.63.254/20',
|
|
'assigned_object_type': 'dcim.interface',
|
|
'assigned_object_id': interface_id,
|
|
'status': 'active',
|
|
'description': 'CGNAT gateway for site 982',
|
|
'tags': []
|
|
}
|
|
|
|
response = requests.post(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, json=ip_data)
|
|
if response.status_code == 201:
|
|
ip = response.json()
|
|
ip_id = ip['id']
|
|
print(f"✓ Created IP address (ID: {ip_id})")
|
|
else:
|
|
print(f"✗ Error creating IP: {response.status_code}")
|
|
print(response.text)
|
|
sys.exit(1)
|
|
|
|
# Step 8: Final verification
|
|
print("\n=== VERIFICATION ===")
|
|
|
|
# Check prefixes
|
|
print("\nPrefixes with 100.64.48.0/20:")
|
|
response = requests.get(f'{NETBOX_URL}ipam/prefixes/', headers=headers, params={'prefix': '100.64.48.0/20'})
|
|
prefixes = response.json()['results']
|
|
for prefix in prefixes:
|
|
site_info = f"Site: {prefix['site']['name']}" if prefix.get('site') else "Site: Not assigned"
|
|
role_info = f"Role: {prefix['role']['name']}" if prefix.get('role') else "Role: None"
|
|
print(f" - {prefix['prefix']} ({site_info}, {role_info})")
|
|
|
|
# Check IPs
|
|
print("\nIP addresses on 982-router:")
|
|
response = requests.get(f'{NETBOX_URL}ipam/ip-addresses/', headers=headers, params={'device_id': device_id})
|
|
ips = response.json()['results']
|
|
for ip in ips:
|
|
interface_info = f"Interface: {ip['assigned_object']['name']}" if ip.get('assigned_object') else "Unassigned"
|
|
print(f" - {ip['address']} ({interface_info})")
|
|
|
|
print("\n✅ Update completed!")
|
|
print("\nNOTE: If the prefix is not showing as assigned to site 982, this may be a")
|
|
print("permission or API limitation. The prefix and IP have been created successfully.")
|
|
|
|
if __name__ == '__main__':
|
|
main() |