Import and Export Functionality

View as Markdown
# Imports (run once)
import json
from air_sdk import AirApi, InstructionExportChoice, SimState
from air_sdk.endpoints import Simulation
# 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

Import

Import a Simulation from a JSON Simulation Manifest File

file_path = '../files/exports/export_without_oob.json'
sim: Simulation = api.simulations.import_from_simulation_manifest(
simulation_manifest=file_path
)
print(f'Current state of simulation: {sim.state}')
print('waiting for simulation to finish importing...', end='')
sim.wait_for_state(SimState.INACTIVE, error_states=SimState.INVALID)
print(f'Current state of simulation: {sim.state}')
Current state of simulation: IMPORTING
waiting for simulation to finish importing....
Current state of simulation: INACTIVE

Import from Data

ztp_script_path = '../files/ztp/basic_script.sh'
with open(ztp_script_path, 'r') as f:
ztp_script = 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,
}
sim: Simulation = api.simulations.import_from_data(**json_data)
print(f'Current state of simulation: {sim.state}')
print('waiting for simulation to finish importing...')
sim.wait_for_state(SimState.INACTIVE, error_states=SimState.INVALID)
print(f'Current state of simulation: {sim.state}')
Current state of simulation: IMPORTING
waiting for simulation to finish importing....
Current state of simulation: INACTIVE

Import a Topology That Declares Services and Instructions

A JSON topology may declare top-level services (exposed ports) and instructions (setup commands run on nodes) lists, alongside nodes and links. They are top-level (rather than nested under a node) so that the oob-mgmt-server can be targeted too. When present, they are imported with the simulation.

topology_with_extras = {
'format': 'JSON',
'name': 'Sim with Services and Instructions',
'content': {
'nodes': {
'server1': {
'cpu': 2,
'memory': 1024,
'storage': 10,
'os': 'generic/ubuntu2204',
'cpu_arch': 'x86',
},
},
'oob': False,
# Top-level services: exposed ports on a node's interface.
'services': [
{
'name': 'SSH',
'service_type': 'SSH',
'node': 'server1',
'interface': 'eth0',
'port': 22,
},
],
# Top-level instructions: setup commands run on nodes.
'instructions': [
{
'node': 'server1',
'executor': 'shell',
'data': 'echo "hello from server1"',
},
],
},
}
sim: Simulation = api.simulations.import_from_data(**topology_with_extras)
print(f'Current state of simulation: {sim.state}')
print('waiting for simulation to finish importing...')
sim.wait_for_state(SimState.INACTIVE, error_states=SimState.INVALID)
print(f'Current state of simulation: {sim.state}')

Export

Export an Existing Simulation

sim_id = '...' # Replace with your simulation ID
sim: Simulation = api.simulations.get(sim_id)
export_data = sim.export()
with open('my_export.json', 'w') as f:
json.dump(export_data, f)

Export including Instructions and Services

By default an export omits instructions and services. Opt in with include_instructions (an InstructionExportChoice — NONE, REPEATABLE, or REPEATABLE_OR_NOT_READY) and include_services=True. The exported topology then carries top-level services and instructions lists, so it round-trips back through import_from_data / import_from_simulation_manifest.

sim_id = '...' # Replace with your simulation ID
sim: Simulation = api.simulations.get(sim_id)
export_data = sim.export(
include_instructions=InstructionExportChoice.REPEATABLE,
include_services=True,
)
# The export now carries top-level 'services' and 'instructions' lists.
print('services:', export_data['content'].get('services'))
print('instructions:', export_data['content'].get('instructions'))
with open('my_export_with_extras.json', 'w') as f:
json.dump(export_data, f)