Skip to content

Commit 61f15fe

Browse files
committed
parallelize demo routers
1 parent 6bb3676 commit 61f15fe

File tree

1 file changed

+50
-25
lines changed

1 file changed

+50
-25
lines changed

netfoundry/ctl.py

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import signal
1414
import jwt
1515
import tempfile
16+
from concurrent.futures import ThreadPoolExecutor, as_completed
1617
from json import dumps as json_dumps
1718
from json import load as json_load
1819
from json import loads as json_loads
@@ -22,6 +23,7 @@
2223
from subprocess import CalledProcessError
2324
from sys import exit as sysexit
2425
from sys import stderr, stdin, stdout
26+
from threading import Lock
2527
from xml.sax.xmlreader import InputSource
2628

2729
from jwt.exceptions import PyJWTError
@@ -961,32 +963,55 @@ def demo(cli):
961963
else:
962964
spinner.succeed(f"Found a hosted router in {region}")
963965

964-
spinner.text = f"Creating {len(fabric_placements)} hosted router(s)"
965-
with spinner:
966-
for region in fabric_placements:
967-
er_name = f"Hosted Router {region} [{cli.config.demo.provider}]"
968-
if not network.edge_router_exists(er_name):
969-
er = network.create_edge_router(
970-
name=er_name,
971-
attributes=[
972-
"#hosted_routers",
973-
"#demo_exits",
974-
f"#{cli.config.demo.provider}",
975-
],
976-
provider=cli.config.demo.provider,
977-
location_code=region,
978-
tunneler_enabled=False, # workaround for MOP-18098 (missing tunneler binding in ziti-router config)
979-
)
980-
hosted_edge_routers.extend([er])
981-
spinner.succeed(f"Created {cli.config.demo.provider} router in {region}")
966+
# Helper function to create or validate a single router (runs in parallel)
967+
def create_or_validate_router(region):
968+
"""Create or validate router for a region. Returns (region, router_dict, message)."""
969+
er_name = f"Hosted Router {region} [{cli.config.demo.provider}]"
970+
if not network.edge_router_exists(er_name):
971+
er = network.create_edge_router(
972+
name=er_name,
973+
attributes=[
974+
"#hosted_routers",
975+
"#demo_exits",
976+
f"#{cli.config.demo.provider}",
977+
],
978+
provider=cli.config.demo.provider,
979+
location_code=region,
980+
tunneler_enabled=False, # workaround for MOP-18098 (missing tunneler binding in ziti-router config)
981+
)
982+
message = f"Created {cli.config.demo.provider} router in {region}"
983+
return (region, er, message)
984+
else:
985+
er_matches = network.edge_routers(name=er_name, only_hosted=True)
986+
if len(er_matches) == 1:
987+
er = er_matches[0]
982988
else:
983-
er_matches = network.edge_routers(name=er_name, only_hosted=True)
984-
if len(er_matches) == 1:
985-
er = er_matches[0]
986-
else:
987-
raise RuntimeError(f"unexpectedly found more than one matching router for name '{er_name}'")
988-
if er['status'] in RESOURCES["edge-routers"].status_symbols["error"] + RESOURCES["edge-routers"].status_symbols["deleting"] + RESOURCES["edge-routers"].status_symbols["deleted"]:
989-
raise RuntimeError(f"hosted router '{er_name}' has unexpected status '{er['status']}'")
989+
raise RuntimeError(f"unexpectedly found more than one matching router for name '{er_name}'")
990+
if er['status'] in RESOURCES["edge-routers"].status_symbols["error"] + RESOURCES["edge-routers"].status_symbols["deleting"] + RESOURCES["edge-routers"].status_symbols["deleted"]:
991+
raise RuntimeError(f"hosted router '{er_name}' has unexpected status '{er['status']}'")
992+
return (region, er, None) # No message for existing routers
993+
994+
# Parallelize router creation with thread-safe spinner updates
995+
spinner.text = f"Creating {len(fabric_placements)} hosted router(s)"
996+
spinner_lock = Lock()
997+
new_routers = []
998+
999+
with ThreadPoolExecutor(max_workers=min(len(fabric_placements), 5)) as executor:
1000+
# Submit all router creation tasks
1001+
future_to_region = {executor.submit(create_or_validate_router, region): region for region in fabric_placements}
1002+
1003+
# Collect results as they complete
1004+
for future in as_completed(future_to_region):
1005+
region, er, message = future.result()
1006+
new_routers.append(er)
1007+
1008+
# Thread-safe spinner update for newly created routers
1009+
if message:
1010+
with spinner_lock:
1011+
spinner.succeed(message)
1012+
1013+
# Add all new routers to the list
1014+
hosted_edge_routers.extend(new_routers)
9901015

9911016
if not len(hosted_edge_routers) > 0:
9921017
raise RuntimeError("unexpected problem with router placements, found zero hosted routers")

0 commit comments

Comments
 (0)