#!/usr/bin/env python3 import sys import requests import yaml ######################################## # Device model import ######################################## def get_or_create_manufacturer(netbox_url, headers, manufacturer_name, slug): url = f"{netbox_url}/api/dcim/manufacturers/?slug={slug}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print( f"[INFO] Manufacturer '{manufacturer_name}' (slug={slug}) already exists." ) return results[0] url = f"{netbox_url}/api/dcim/manufacturers/" payload = {"name": manufacturer_name, "slug": slug} resp = requests.post(url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Manufacturer '{manufacturer_name}' created (ID={created['id']}).") return created def get_or_create_device_role(netbox_url, headers, role): name = role["name"] slug = role["slug"] url = f"{netbox_url}/api/dcim/device-roles/?slug={slug}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print(f"[INFO] Device Role '{name}' (slug={slug}) already exists.") return results[0] url = f"{netbox_url}/api/dcim/device-roles/" payload = { "name": name, "slug": slug, "color": role.get("color", "607d8b"), "vm_role": role.get("vm_role", False), } resp = requests.post(url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Device Role '{name}' created (ID={created['id']}).") return created def get_or_create_device_type(netbox_url, headers, device_type, manufacturers_cache): manufacturer_slug = device_type["manufacturer"] if manufacturer_slug not in manufacturers_cache: print( f"[WARN] Manufacturer slug '{manufacturer_slug}' not found in cache. Skipping device type." ) return None manufacturer_obj = manufacturers_cache[manufacturer_slug] slug = device_type["slug"] url = f"{netbox_url}/api/dcim/device-types/?slug={slug}&manufacturer_id={manufacturer_obj['id']}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print( f"[INFO] Device Type '{device_type['model']}' (slug={slug}) already exists." ) return results[0] create_url = f"{netbox_url}/api/dcim/device-types/" payload = { "manufacturer": manufacturer_obj["id"], "model": device_type["model"], "slug": slug, "part_number": device_type.get("part_number", ""), "u_height": device_type.get("u_height", 1), "is_full_depth": device_type.get("is_full_depth", False), "comments": device_type.get("comments", ""), } resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() created_dt = resp.json() print( f"[INFO] Device Type '{created_dt['model']}' created (ID={created_dt['id']})." ) ######################################## # Subnets import ######################################## def get_or_create_region(netbox_url, headers, region_name): url = f"{netbox_url}/api/dcim/regions/?name={region_name}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print(f"[INFO] Region '{region_name}' already exists.") return results[0] create_url = f"{netbox_url}/api/dcim/regions/" payload = {"name": region_name, "slug": region_name.lower().replace(" ", "-")} resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Region '{region_name}' created (ID={created['id']}).") return created def get_or_create_site(netbox_url, headers, site_name, region_id=None): url = f"{netbox_url}/api/dcim/sites/?name={site_name}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print(f"[INFO] Site '{site_name}' already exists.") return results[0] create_url = f"{netbox_url}/api/dcim/sites/" payload = {"name": site_name, "slug": site_name.lower().replace(" ", "-")} if region_id: payload["region"] = region_id resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Site '{site_name}' created (ID={created['id']}).") return created def get_or_create_location(netbox_url, headers, location_name, site_id): url = f"{netbox_url}/api/dcim/locations/?name={location_name}&site_id={site_id}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print( f"[INFO] Location '{location_name}' already exists for site ID={site_id}." ) return results[0] create_url = f"{netbox_url}/api/dcim/locations/" payload = {"name": location_name, "slug": location_name.lower(), "site": site_id} resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Location '{location_name}' created (ID={created['id']}).") return created def get_or_create_prefix_role(netbox_url, headers, role_name): """ Creates or retrieves a prefix role with the given name. We'll build the slug from the role_name. """ slug = role_name.lower().replace(" ", "-") url = f"{netbox_url}/api/ipam/roles/?slug={slug}" resp = requests.get(url, headers=headers) resp.raise_for_status() results = resp.json()["results"] if results: print(f"[INFO] Prefix Role '{role_name}' (slug={slug}) already exists.") return results[0] create_url = f"{netbox_url}/api/ipam/roles/" payload = {"name": role_name, "slug": slug} resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() created = resp.json() print(f"[INFO] Prefix Role '{role_name}' created (ID={created['id']}).") return created def create_container_prefix(netbox_url, headers, cidr, description, role_id, site_id): """ Create (or reuse) a prefix in NetBox with a given role and site. """ check_url = f"{netbox_url}/api/ipam/prefixes/?prefix={cidr}" resp = requests.get(check_url, headers=headers) resp.raise_for_status() existing = resp.json()["results"] if existing: print(f"[WARN] Container prefix '{cidr}' already exists. Not recreating.") return existing[0] create_url = f"{netbox_url}/api/ipam/prefixes/" payload = { "prefix": cidr, "description": description, "role": role_id, "scope_type": "dcim.site", "scope_id": site_id, } resp = requests.post(create_url, headers=headers, json=payload) resp.raise_for_status() new_prefix = resp.json() print(f"[INFO] Container prefix '{cidr}' created (ID={new_prefix['id']}).") return new_prefix ######################################## # Divers Creation ######################################## def get_or_create_custom_field(netbox_url, headers): field_name = "ASN" url = f"{netbox_url}/api/extras/custom-fields/" # Check if the custom field already exists response = requests.get(url, headers=headers, params={"name": field_name}) if response.status_code == 200: existing_fields = response.json().get("results", []) if existing_fields: print(f"[INFO] Custom field '{field_name}' already exists.") return # Define the custom field payload custom_field_data = { "name": field_name, "label": "ASN", "type": "integer", "description": "ASN", "required": False, "default": "", "weight": 100, "filter_logic": "loose", "ui_visible": "always", "is_cloneable": True, "object_types": ["dcim.device"], } # Create the custom field create_response = requests.post(url, headers=headers, json=custom_field_data) if create_response.status_code == 201: print(f"[INFO] Custom field '{field_name}' created successfully.") else: print(f"[ERROR] Failed to create custom field: {create_response.text}") ######################################## # MAIN ######################################## def main(): if len(sys.argv) != 5: print( "Usage: python import_netbox.py " ) sys.exit(1) netbox_url = sys.argv[1].rstrip("/") netbox_token = sys.argv[2] device_model_file = sys.argv[3] subnets_file = sys.argv[4] headers = { "Authorization": f"Token {netbox_token}", "Content-Type": "application/json", "Accept": "application/json", } # 1) Load device_model.yml with open(device_model_file, "r") as f: device_model_data = yaml.safe_load(f) # 2) Load subnets.yml with open(subnets_file, "r") as f: subnets_data = yaml.safe_load(f) # Divers Creation get_or_create_custom_field(netbox_url, headers) ###################################################### # device_model.yml : manufacturers, roles, types ###################################################### manufacturers_cache = {} if "manufacturers" in device_model_data: for mf in device_model_data["manufacturers"]: name = mf["name"] slug = mf["slug"] mf_obj = get_or_create_manufacturer(netbox_url, headers, name, slug) manufacturers_cache[slug] = mf_obj if "device_roles" in device_model_data: for role in device_model_data["device_roles"]: get_or_create_device_role(netbox_url, headers, role) if "device_types" in device_model_data: for dt in device_model_data["device_types"]: get_or_create_device_type(netbox_url, headers, dt, manufacturers_cache) ###################################################### # subnets.yml : Region, Site, Containers, etc. ###################################################### region_name = subnets_data.get("Location", {}).get("Region", "Europe") region_obj = get_or_create_region(netbox_url, headers, region_name) region_id = region_obj["id"] city_name = subnets_data.get("Location", {}).get("City", "Paris") site_obj = get_or_create_site(netbox_url, headers, city_name, region_id=region_id) site_id = site_obj["id"] # For each container key, create a prefix role and a prefix containers = subnets_data.get("Containers", {}) for container_name, c_data in containers.items(): # Attempt to fix any 'cirdr' -> 'cidr' typos by reading "cidr" if possible cidr = c_data.get("cidr") description = c_data.get("description", f"{container_name} prefix") # 1) Create a prefix role named after the container key # e.g., container_name='UnderlayContainer' => role = UnderlayContainer role_obj = get_or_create_prefix_role(netbox_url, headers, container_name) role_id = role_obj["id"] # 2) Create the prefix with that role, attached to the site create_container_prefix( netbox_url, headers, cidr, description, role_id, site_id ) # Optionally handle buildings as locations buildings = subnets_data.get("Buildings", {}) for building_name in buildings.keys(): get_or_create_location(netbox_url, headers, building_name, site_id) print("[INFO] Script completed successfully!") if __name__ == "__main__": main()