Of course! The Cobbler API is a powerful way to automate infrastructure provisioning using Python. Here’s a comprehensive guide covering what it is, how to use it, and practical examples.

What is the Cobbler API?
Cobbler is a Linux installation server that allows for rapid setup of network installation environments. It can PXE boot, provision, and manage the lifecycle of servers.
The Cobbler API is a Python-based, XML-RPC interface that allows you to programmatically control every aspect of a Cobbler server. This means you can write Python scripts to:
- Add, edit, and delete distributions (OS install trees).
- Manage profiles (templates for systems).
- Create and manage system entries (individual hosts to be provisioned).
- Sync configuration files to the TFTP and web servers.
- Kick off installations.
The API is the backbone of the Cobbler web interface (cobbler-web) and is designed for automation.
How to Access the API
The API is exposed as an XML-RPC service. You don't need to know the details of XML-RPC to use it. The cobbler Python module provides a convenient wrapper.

Prerequisites
You need the cobbler Python module installed on the machine where your script will run. This is typically installed on the Cobbler server itself.
# On RHEL/CentOS/Fedora sudo dnf install cobbler # On Debian/Ubuntu sudo apt-get install cobbler
Connecting to the API
Your first step in any script is to create a connection to the Cobbler API server.
import cobbler.api as capi
try:
# Connect to the Cobbler API
# The API is typically on the local Cobbler server.
# The second argument is the username, and the third is the password.
# Default credentials are usually "cobbler" / "cobbler".
api = capi.CobblerAPI("http://127.0.0.1", "cobbler", "cobbler")
# You can test the connection
if api is not None:
print("Successfully connected to Cobbler API!")
print(f"Cobbler Version: {api.get_version()}")
except Exception as e:
print(f"Error connecting to Cobbler API: {e}")
exit(1)
Common API Operations
Once connected, the api object gives you access to all of Cobbler's functionality. The methods are organized into logical groups.
A. Getting Information (Read-Only)
You can query all objects in Cobbler.
# --- Get all distributions ---
distributions = api.get_distributions()
print(f"\nFound {len(distributions)} distributions:")
for dist in distributions:
print(f" - {dist.name} (Kernel: {dist.kernel})")
# --- Get all profiles ---
profiles = api.get_profiles()
print(f"\nFound {len(profiles)} profiles:")
for profile in profiles:
print(f" - {profile.name} (Distro: {profile.get_distro()})")
# --- Get all systems ---
systems = api.get_systems()
print(f"\nFound {len(systems)} systems:")
for system in systems:
print(f" - {system.name} (Profile: {system.get_profile()})")
B. Creating and Modifying Objects (CRUD)
This is where the real power lies. The general pattern is:
- Get a new object from the API (e.g.,
api.new_distro()). - Set its attributes.
- Call the appropriate
add_...()oradd_..._autoinstall()method. - Call
api.sync()to apply the changes to the filesystem.
Important: After adding, editing, or deleting objects, you must call api.sync() for the changes to take effect. This generates the PXE files, DHCP configurations, etc.
Example 1: Adding a New Distribution
Let's say you have a custom OS install tree available via HTTP.
# Create a new distribution object
new_distro = api.new_distro()
# Set the attributes for the distribution
new_distro.name = "custom-rocky9-x86_64"
new_distro.kernel = "/var/www/cobbler/distro_images/custom-rocky9-x86_64/images/pxeboot/vmlinuz"
new_distro.initrd = "/var/www/cobbler/distro_images/custom-rocky9-x86_64/images/pxeboot/initrd.img"
new_distro.breed = "redhat"
new_distro.os_version = "rhel9"
new_distro.arch = "x86_64"
new_distro.boot_files = {
"/images/pxeboot/kernel": "/var/www/cobbler/distro_images/custom-rocky9-x86_64/images/pxeboot/kernel",
"/images/pxeboot/initrd.img": "/var/www/cobbler/distro_images/custom-rocky9-x86_64/images/pxeboot/initrd.img"
}
# Add the distribution to Cobbler
api.add_distro(new_distro, save=True) # save=True is equivalent to calling api.sync() after
print(f"\nSuccessfully added distribution: {new_distro.name}")
Example 2: Adding a Profile and a System
Profiles are templates for systems. Let's create a profile based on the distribution we just added, and then a system that uses that profile.
# --- Create a Profile ---
new_profile = api.new_profile()
new_profile.name = "web-server-profile"
new_profile.distro = "custom-rocky9-x86_64" # Use the name of the distro
new_profile.kickstart = "/var/lib/cobbler/kickstarts/rocky9-ks.cfg"
new_profile.kernel_options = {
"lang": "en_US",
"text": "", # Install in text mode
"ksdevice": "eth0"
}
api.add_profile(new_profile, save=True)
print(f"\nSuccessfully added profile: {new_profile.name}")
# --- Create a System ---
new_system = api.new_system()
new_system.name = "web-server-01"
new_system.profile = "web-server-profile"
new_system.hostname = "web-01.example.com"
new_system.interfaces = {
"eth0": {
"macaddress": "52:54:00:12:34:56",
"ipaddress": "192.168.1.101",
"netmask": "255.255.255.0",
"dhcp_tag": "default",
"static": True
}
}
api.add_system(new_system, save=True)
print(f"\nSuccessfully added system: {new_system.name}")
# --- Final Sync ---
# It's good practice to sync one last time to ensure everything is clean.
# The individual save=True calls should handle this, but a final sync is robust.
api.sync()
print("\nFinal sync complete.")
C. Deleting Objects
Deleting is straightforward. You just need the name of the object.
# --- Delete a System ---
system_to_delete = "web-server-01"
if api.find_system(name=system_to_delete):
api.remove_system(system_to_delete, save=True)
print(f"\nSuccessfully deleted system: {system_to_delete}")
else:
print(f"\nSystem not found: {system_to_delete}")
# --- Delete a Profile ---
profile_to_delete = "web-server-profile"
if api.find_profile(name=profile_to_delete):
api.remove_profile(profile_to_delete, save=True)
print(f"Successfully deleted profile: {profile_to_delete}")
else:
print(f"Profile not found: {profile_to_delete}")
# --- Delete a Distribution ---
distro_to_delete = "custom-rocky9-x86_64"
if api.find_distro(name=distro_to_delete):
api.remove_distro(distro_to_delete, save=True)
print(f"Successfully deleted distribution: {distro_to_delete}")
else:
print(f"Distribution not found: {distro_to_delete}")
Putting It All Together: A Complete Script
Here is a full, runnable script that demonstrates adding a distribution, profile, and system, and then cleaning them up.
#!/usr/bin/env python3
import cobbler.api as capi
import time
# --- Configuration ---
COBBLER_URL = "http://127.0.0.1"
COBBLER_USER = "cobbler"
COBBLER_PASS = "cobbler"
# Object names to be created and managed
TEST_DISTRO_NAME = "my-test-distro"
TEST_PROFILE_NAME = "my-test-profile"
TEST_SYSTEM_NAME = "my-test-system"
def main():
"""Main function to demonstrate the Cobbler API."""
try:
# 1. Connect to the Cobbler API
print("Connecting to Cobbler API...")
api = capi.CobblerAPI(COBBLER_URL, COBBLER_USER, COBBLER_PASS)
print(f"Connected! Cobbler version: {api.get_version()}")
# 2. Create and Add a Distribution
# NOTE: For this to work, the kernel/initrd files must exist at the specified paths.
# We will create a "dummy" distro for demonstration.
print(f"\n--- Creating Distribution: {TEST_DISTRO_NAME} ---")
if not api.find_distro(name=TEST_DISTRO_NAME):
distro = api.new_distro()
distro.name = TEST_DISTRO_NAME
distro.kernel = "/path/to/your/kernel" # IMPORTANT: Replace with a real path
distro.initrd = "/path/to/your/initrd.img" # IMPORTANT: Replace with a real path
distro.breed = "redhat"
distro.os_version = "rhel9"
distro.arch = "x86_64"
api.add_distro(distro, save=True)
print(f"Distribution '{TEST_DISTRO_NAME}' added successfully.")
else:
print(f"Distribution '{TEST_DISTRO_NAME}' already exists. Skipping creation.")
# 3. Create and Add a Profile
print(f"\n--- Creating Profile: {TEST_PROFILE_NAME} ---")
if not api.find_profile(name=TEST_PROFILE_NAME):
profile = api.new_profile()
profile.name = TEST_PROFILE_NAME
profile.distro = TEST_DISTRO_NAME
profile.kickstart = "/var/lib/cobbler/kickstarts/sample.ks" # Use a real kickstart
profile.kernel_options = {"lang": "en_US", "kssendmac": ""}
api.add_profile(profile, save=True)
print(f"Profile '{TEST_PROFILE_NAME}' added successfully.")
else:
print(f"Profile '{TEST_PROFILE_NAME}' already exists. Skipping creation.")
# 4. Create and Add a System
print(f"\n--- Creating System: {TEST_SYSTEM_NAME} ---")
if not api.find_system(name=TEST_SYSTEM_NAME):
system = api.new_system()
system.name = TEST_SYSTEM_NAME
system.profile = TEST_PROFILE_NAME
system.hostname = TEST_SYSTEM_NAME + ".localdomain"
system.interfaces = {
"eth0": {
"macaddress": "AA:BB:CC:DD:EE:FF",
"ipaddress": "192.168.1.150",
"netmask": "255.255.255.0",
"static": True
}
}
api.add_system(system, save=True)
print(f"System '{TEST_SYSTEM_NAME}' added successfully.")
else:
print(f"System '{TEST_SYSTEM_NAME}' already exists. Skipping creation.")
# 5. Final Sync
print("\nPerforming a final sync to apply all changes...")
api.sync()
print("Sync complete.")
# Optional: Pause to see the objects in the web UI
print("\nScript finished. You can check the Cobbler web UI.")
# time.sleep(30) # Uncomment to pause for 30 seconds
except capi.CobblerAPIError as e:
print(f"\nA Cobbler API error occurred: {e}")
except Exception as e:
print(f"\nAn unexpected error occurred: {e}")
finally:
# 6. Cleanup (Optional)
# Uncomment the block below to automatically clean up the created objects.
print("\n--- Cleaning up created objects ---")
try:
if api.find_system(name=TEST_SYSTEM_NAME):
api.remove_system(TEST_SYSTEM_NAME, save=True)
print(f"Removed system: {TEST_SYSTEM_NAME}")
if api.find_profile(name=TEST_PROFILE_NAME):
api.remove_profile(TEST_PROFILE_NAME, save=True)
print(f"Removed profile: {TEST_PROFILE_NAME}")
if api.find_distro(name=TEST_DISTRO_NAME):
api.remove_distro(TEST_DISTRO_NAME, save=True)
print(f"Removed distribution: {TEST_DISTRO_NAME}")
api.sync()
print("Cleanup sync complete.")
except Exception as e:
print(f"Error during cleanup: {e}")
if __name__ == "__main__":
main()
Important Considerations
- Authentication: The default credentials are weak. For production, you should configure Cobbler to use a more secure authentication method, like Kerberos or by integrating with a central user directory.
api.sync(): This is the most important command. It's what makes your changes "live". Forgetting it is a common mistake. It can be resource-intensive on large setups.- Error Handling: Always wrap your API calls in
try...exceptblocks. Thecobbler.api.CobblerAPIErrorexception is specific to the API and will give you details about what went wrong (e.g., a missing kickstart file, a name conflict). - Idempotency: Good scripts check if an object already exists before trying to create it (as shown in the full example). This makes your scripts safe to run multiple times.
- Permissions: The user running the script needs the correct permissions to connect to and modify the Cobbler API. This is usually handled by the
cobbleruser on the server.
