207 lines
No EOL
7.1 KiB
Python
207 lines
No EOL
7.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import requests
|
|
import json
|
|
from urllib.parse import urljoin
|
|
|
|
class NetBoxManager:
|
|
def __init__(self, url, token):
|
|
self.base_url = url.rstrip('/')
|
|
self.api_url = urljoin(self.base_url + '/', 'api/')
|
|
self.headers = {
|
|
'Authorization': f'Token {token}',
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
}
|
|
self.session = requests.Session()
|
|
self.session.headers.update(self.headers)
|
|
|
|
def get(self, endpoint, params=None):
|
|
"""Make GET request to NetBox API"""
|
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
|
response = self.session.get(url, params=params)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
def post(self, endpoint, data):
|
|
"""Make POST request to NetBox API"""
|
|
url = urljoin(self.api_url, endpoint.lstrip('/'))
|
|
response = self.session.post(url, json=data)
|
|
if response.status_code not in [200, 201]:
|
|
print(f"Error creating {endpoint}: {response.status_code}")
|
|
print(f"Response: {response.text}")
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
def create_site(self, name, slug=None, status='active', comments=''):
|
|
"""Create a new site"""
|
|
if not slug:
|
|
slug = name.lower().replace(' ', '-')
|
|
|
|
site_data = {
|
|
'name': name,
|
|
'slug': slug,
|
|
'status': status,
|
|
'comments': comments
|
|
}
|
|
|
|
return self.post('dcim/sites/', site_data)
|
|
|
|
def create_device(self, name, device_type_id, role_id, site_id, status='active'):
|
|
"""Create a new device"""
|
|
device_data = {
|
|
'name': name,
|
|
'device_type': device_type_id,
|
|
'role': role_id,
|
|
'site': site_id,
|
|
'status': status
|
|
}
|
|
|
|
return self.post('dcim/devices/', device_data)
|
|
|
|
def get_or_create_manufacturer(self, name):
|
|
"""Get or create a manufacturer"""
|
|
response = self.get('dcim/manufacturers/', params={'name': name})
|
|
if response['count'] > 0:
|
|
return response['results'][0]['id']
|
|
|
|
# Create manufacturer
|
|
mfg_data = {
|
|
'name': name,
|
|
'slug': name.lower()
|
|
}
|
|
created = self.post('dcim/manufacturers/', mfg_data)
|
|
return created['id']
|
|
|
|
def get_or_create_device_type(self, model, manufacturer_id):
|
|
"""Get or create a device type"""
|
|
response = self.get('dcim/device-types/', params={'model': model})
|
|
if response['count'] > 0:
|
|
return response['results'][0]['id']
|
|
|
|
# Create device type
|
|
dt_data = {
|
|
'manufacturer': manufacturer_id,
|
|
'model': model,
|
|
'slug': model.lower().replace(' ', '-').replace('/', '-')
|
|
}
|
|
created = self.post('dcim/device-types/', dt_data)
|
|
return created['id']
|
|
|
|
def get_or_create_device_role(self, name, slug=None):
|
|
"""Get or create a device role"""
|
|
if not slug:
|
|
slug = name.lower().replace(' ', '-')
|
|
|
|
response = self.get('dcim/device-roles/', params={'name': name})
|
|
if response['count'] > 0:
|
|
return response['results'][0]['id']
|
|
|
|
# Create device role
|
|
role_data = {
|
|
'name': name,
|
|
'slug': slug,
|
|
'color': '2196f3' # Blue color
|
|
}
|
|
created = self.post('dcim/device-roles/', role_data)
|
|
return created['id']
|
|
|
|
|
|
def main():
|
|
# Get API token from environment variable or use the one from CLAUDE.md
|
|
api_token = os.environ.get('NETBOX_KEY', 'e50298f7fd20f7fd6f1931f635511b34f6e8cfde')
|
|
|
|
# Initialize NetBox client
|
|
nb = NetBoxManager('https://netbox.vntx.net/', api_token)
|
|
|
|
print("=== Creating Verona Site and Router in NetBox ===\n")
|
|
|
|
# Check if Verona site exists
|
|
site_response = nb.get('dcim/sites/', params={'name': 'Verona'})
|
|
|
|
if site_response['count'] == 0:
|
|
# Create Verona site
|
|
print("Creating Verona site...")
|
|
try:
|
|
site = nb.create_site(
|
|
name='Verona',
|
|
slug='verona',
|
|
status='active',
|
|
comments='Verona tower site with MikroTik router'
|
|
)
|
|
site_id = site['id']
|
|
print(f"✓ Created Verona site (ID: {site_id})")
|
|
except Exception as e:
|
|
print(f"✗ Failed to create Verona site: {e}")
|
|
return
|
|
else:
|
|
site_id = site_response['results'][0]['id']
|
|
print(f"✓ Verona site already exists (ID: {site_id})")
|
|
|
|
# Check if router already exists
|
|
device_response = nb.get('dcim/devices/', params={'name': 'verona-router', 'site_id': site_id})
|
|
|
|
if device_response['count'] == 0:
|
|
print("\nCreating Verona router device...")
|
|
|
|
# Get or create MikroTik manufacturer
|
|
print(" - Setting up manufacturer...")
|
|
manufacturer_id = nb.get_or_create_manufacturer('MikroTik')
|
|
|
|
# Get or create device type (assuming RouterBOARD or generic)
|
|
print(" - Setting up device type...")
|
|
device_type_id = nb.get_or_create_device_type('RouterBOARD', manufacturer_id)
|
|
|
|
# Get or create device role
|
|
print(" - Setting up device role...")
|
|
role_id = nb.get_or_create_device_role('Router')
|
|
|
|
# Create the device
|
|
try:
|
|
device = nb.create_device(
|
|
name='verona-router',
|
|
device_type_id=device_type_id,
|
|
role_id=role_id,
|
|
site_id=site_id,
|
|
status='active'
|
|
)
|
|
device_id = device['id']
|
|
print(f"✓ Created Verona router device (ID: {device_id})")
|
|
|
|
# Add primary IP
|
|
print("\n - Adding primary IP address...")
|
|
ip_data = {
|
|
'address': '10.254.254.101/32',
|
|
'status': 'active',
|
|
'description': 'Verona router loopback',
|
|
'role': 'loopback'
|
|
}
|
|
try:
|
|
ip_response = nb.post('ipam/ip-addresses/', ip_data)
|
|
ip_id = ip_response['id']
|
|
|
|
# Set as primary IP for the device
|
|
device_update = {
|
|
'primary_ip4': ip_id
|
|
}
|
|
nb.session.patch(f"{nb.api_url}dcim/devices/{device_id}/", json=device_update)
|
|
print("✓ Added primary IP address")
|
|
except Exception as e:
|
|
print(f"✗ Failed to add primary IP: {e}")
|
|
|
|
except Exception as e:
|
|
print(f"✗ Failed to create Verona router: {e}")
|
|
return
|
|
else:
|
|
device_id = device_response['results'][0]['id']
|
|
print(f"✓ Verona router already exists (ID: {device_id})")
|
|
|
|
print(f"\n=== Summary ===")
|
|
print(f"Site: Verona (ID: {site_id})")
|
|
print(f"Device: verona-router (ID: {device_id})")
|
|
print(f"\nYou can now run update_netbox_verona.py to add all the subnet and interface data.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |