Skip to navigation

Working with ZTP Scripts

View as Markdown
# Imports (run once)
from air_sdk import AirApi
from air_sdk.endpoints import Simulation, ZTPScript
# Authentication (run once)
api = AirApi.with_ngc_config()
# OR api = AirApi.with_api_key(api_key="...")
# OR api = AirApi.with_device_login(email="...", org_num="...")
# ^ use in terminal only — not supported in Jupyter notebooks

Basic Info

Simulation instances have a ztp_script property which accesses any ZTPScript associated with the simulation.

A ZTPScript holds one entry per configured OS type in ztp_configs: cumulus is the provisioning script and nvos the ZTP JSON object. content is the Cumulus script, or None when only NVOS is configured.

sim_without_ztp_script: Simulation = api.simulations.get(
'...'
) # replace with actual sim id
assert sim_without_ztp_script.ztp_script is None
sim_with_ztp_script: Simulation = api.simulations.get('...') # replace with actual sim id
ztp_script = sim_with_ztp_script.ztp_script
assert ztp_script is not None
assert ztp_script.ztp_configs # e.g. {'cumulus': ..., 'nvos': {...}}

Adding ZTP Scripts during Import

ztp_script_path = '../files/ztp/basic_script.sh'
with open(ztp_script_path, 'r') as f:
ztp_script_content = f.read()
json_data = {
'format': 'JSON',
'name': 'JSON Sim',
'content': {
'nodes': {
'node1': {
'cpu': 2,
'memory': 1024,
'storage': 10,
'os': 'generic/ubuntu2204',
'cpu_arch': 'x86',
},
},
'oob': False,
},
'ztp': ztp_script_content,
}
sim: Simulation = api.simulations.import_from_data(**json_data)
assert isinstance(sim.ztp_script, ZTPScript)
assert sim.ztp_script.content == ztp_script_content

Adding ZTP Scripts after Creation

sim: Simulation = api.simulations.create(name='Blank Sim')
assert sim.ztp_script is None
ztp_script_path = '../files/ztp/basic_script.sh'
with open(ztp_script_path, 'r') as f:
ztp_script_content = f.read()
sim.create_ztp_script(content=ztp_script_content)
assert isinstance(sim.ztp_script, ZTPScript)
assert sim.ztp_script.content == ztp_script_content

Updating ZTP Script Content

sim_id = '...' # Replace with your simulation ID
sim_with_ztp_script: Simulation = api.simulations.get(sim_id)
ztp_script = sim_with_ztp_script.ztp_script
assert ztp_script is not None
ztp_script_path = '../files/ztp/basic_script.sh'
with open(ztp_script_path, 'r') as f:
ztp_script_content = f.read() # New content
ztp_script.update(content=ztp_script_content)

Configuring ZTP Per Os Type

A simulation can carry a Cumulus script, an NVOS ZTP configuration, or both. Updates change only the OS types they are given, each replaced whole (nothing is merged inside an OS type’s configuration), and remove an OS type set to None; removing the last one needs delete_ztp_script(). Changes need the simulation to be INACTIVE. These cells need an Air release with per-OS ZTP support.

Saving doesn’t provision anything by itself: Air serves the configuration from the simulation’s OOB server, so the simulation needs automatic OOB with DHCP (enable_auto_oob(), DHCP on by default). The OOB server rebuilds its ZTP files each time the simulation starts, and a switch gets the change the next time it runs ZTP, as on a clean start (start(checkpoint=None)). A switch restored from a checkpoint resumes from its snapshot and may not run ZTP again.

sim_id = '...' # Replace with your simulation ID
sim: Simulation = api.simulations.get(sim_id)
cumulus_script = '#!/bin/bash\n#CUMULUS-AUTOPROVISIONING\n'
nvos_config = {
'ztp': {'01-image': {'install': {'url': 'http://<server>/images/<nvos-image>.bin'}}}
}
# Configure both OS types (use update_ztp_script() if the simulation has a configuration)
sim.create_ztp_script(ztp_configs={'cumulus': cumulus_script, 'nvos': nvos_config})
# Change only the NVOS configuration; the Cumulus script is kept
sim.update_ztp_script(ztp_configs={'nvos': {'ztp': {'01-image': {'uninstall': True}}}})
# Read one OS type
assert sim.ztp_script.ztp_configs['nvos'] == {'ztp': {'01-image': {'uninstall': True}}}
# Remove one OS type; the Cumulus script is kept
sim.update_ztp_script(ztp_configs={'nvos': None})
assert set(sim.ztp_script.ztp_configs) == {'cumulus'}

Deleting a ZTP Script from a Simulation

sim_id = '...' # Replace with your simulation ID
sim_with_ztp_script: Simulation = api.simulations.get(sim_id)
ztp_script = sim_with_ztp_script.ztp_script
assert ztp_script is not None
ztp_script.delete()
assert sim_with_ztp_script.ztp_script is None