Skip to content

Commit 90b7f21

Browse files
authored
Merge pull request #19 from cisco-open/dev-2.0.12
Dev 2.0.12
2 parents 9a8aed3 + 78fd6ad commit 90b7f21

13 files changed

+218
-111
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
# Catalyst SD-WAN Lab 2.0.10 [May 13, 2024]
1+
# Catalyst SD-WAN Lab 2.0.12 [Jun 18, 2024]
2+
3+
- Added CML PATty support
4+
- In delete task, print lab name when asking user to confirm if lab should be deleted
5+
- In add task, added check to avoid deploying labs with duplicate names (although CML allows labs with duplicate names, this creates confusion for other tasks where lab name is used)
6+
7+
# Catalyst SD-WAN Lab 2.0.11 [May 13, 2024]
28

39
- Added sign task
410

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ The easiest way to run the tool is to provide all the lab variables in the rc fi
139139

140140
Note that if password was not defined, the user will be prompted for a password.
141141

142+
Note that MANAGER_IP can be:
143+
- an IP address: SD-WAN Manager will be reachable over this IP address. By default the IP address should come from the same subnet as CML IP, unless custom bridge is specified during deploy task.
144+
- a PATty port in format "pat:<outside-port>": SD-WAN Manager will be reachable over CML IP port <outside-port>. Before using this option, PATTy needs to be enabled on the CML server as per [CML documentation](https://developer.cisco.com/docs/modeling-labs/patty-tool-overview/).
145+
142146
### Task-specific Parameters
143147
Task-specific parameters and options are defined after the task is provided. Each task has its own set of parameters. Check the task documentation to learn more about task-specific parameters.
144148

catalyst_sdwan_lab/__main__.py

+42-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
import argparse
1515
import logging
16+
import re
1617
import sys
18+
from typing import Tuple
1719

1820
import urllib3
1921
from cisco_sdwan.tasks.utils import EnvVar, PromptArg, non_empty_type
@@ -531,10 +533,14 @@ def main() -> None:
531533
if cli_args.task == "setup":
532534
setup.main(cml, cli_args.loglevel, cli_args.list)
533535
elif cli_args.task == "deploy":
536+
patty_used, manager_ip, manager_port = set_manager_details(
537+
cli_args.cml, cli_args.manager
538+
)
534539
deploy.main(
535540
cml,
536541
cli_args.cml,
537-
cli_args.manager,
542+
manager_ip,
543+
manager_port,
538544
cli_args.mmask,
539545
cli_args.mgateway,
540546
cli_args.muser,
@@ -543,15 +549,20 @@ def main() -> None:
543549
cli_args.lab,
544550
cli_args.bridge,
545551
cli_args.dns,
552+
patty_used,
546553
cli_args.retry,
547554
cli_args.loglevel,
548555
)
549556
elif cli_args.task == "add":
557+
patty_used, manager_ip, manager_port = set_manager_details(
558+
cli_args.cml, cli_args.manager
559+
)
550560
add.main(
551561
cml,
552562
cli_args.user,
553563
cli_args.password,
554-
cli_args.manager,
564+
manager_ip,
565+
manager_port,
555566
cli_args.muser,
556567
cli_args.mpassword,
557568
cli_args.lab,
@@ -561,28 +572,37 @@ def main() -> None:
561572
cli_args.loglevel,
562573
)
563574
elif cli_args.task == "backup":
575+
patty_used, manager_ip, manager_port = set_manager_details(
576+
cli_args.cml, cli_args.manager
577+
)
564578
backup.main(
565579
cml,
566580
cli_args.user,
567581
cli_args.password,
568-
cli_args.manager,
582+
manager_ip,
583+
manager_port,
569584
cli_args.muser,
570585
cli_args.mpassword,
571586
cli_args.lab,
572587
cli_args.workdir,
573588
cli_args.loglevel,
574589
)
575590
elif cli_args.task == "restore":
591+
patty_used, manager_ip, manager_port = set_manager_details(
592+
cli_args.cml, cli_args.manager
593+
)
576594
restore.main(
577595
cml,
578596
cli_args.cml,
579-
cli_args.manager,
597+
manager_ip,
598+
manager_port,
580599
cli_args.mmask,
581600
cli_args.mgateway,
582601
cli_args.muser,
583602
cli_args.mpassword,
584603
cli_args.workdir,
585604
cli_args.lab,
605+
patty_used,
586606
cli_args.deleteexisting,
587607
cli_args.retry,
588608
cli_args.loglevel,
@@ -603,5 +623,23 @@ def verify_cml_version(cml: ClientLibrary) -> None:
603623
exit("Upgrade CML to 2.6 or later to use the tool.")
604624

605625

626+
def set_manager_details(cml_ip: str, manager_ip: str) -> Tuple[bool, str, int]:
627+
patty_used = False
628+
manager_port = 443
629+
if manager_ip.startswith("pat:"):
630+
# PATty should be used for SD-WAN Manager reachability.
631+
patty_used = True
632+
manager_port_search = re.search(r"pat:(\d+)", manager_ip)
633+
if manager_port_search:
634+
manager_port = int(manager_port_search.group(1))
635+
else:
636+
exit(
637+
"Wrong PATty configuration for manager_ip (expected pat:<outside_port>)."
638+
)
639+
manager_ip = cml_ip
640+
641+
return patty_used, manager_ip, manager_port
642+
643+
606644
if __name__ == "__main__":
607645
main()

catalyst_sdwan_lab/data/cml_lab_definition/deploy/cml-base-topology.j2

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ nodes:
1515
label: Manager0{{ manager_num }}
1616
node_definition: cat-sdwan-manager
1717
ram: null
18+
{% if patty_used %}
19+
tags:
20+
- pat:{{ manager_port }}:443
21+
{% else %}
1822
tags: []
23+
{% endif %}
1924
x: -280
2025
y: -80
2126
interfaces:
@@ -773,7 +778,7 @@ lab:
773778
description: This lab was deployed using SD-WAN lab automation.
774779
notes: |-
775780
-- Do not delete this text --
776-
manager_external_ip = {{ manager_external_ip }}
781+
manager_external_ip = {{ manager_external_ip }}:{{ manager_port }}
777782
-- Do not delete this text --
778783
title: '{{ title }}'
779784
version: 0.2.1

catalyst_sdwan_lab/data/cml_lab_definition/deploy/manager-cloud-init.j2

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ write_files:
8888
</vpn-instance>
8989
<vpn-instance>
9090
<vpn-id>512</vpn-id>
91+
{% if not patty_used %}
9192
<ip>
9293
<route>
9394
<prefix>0.0.0.0/0</prefix>
@@ -96,10 +97,15 @@ write_files:
9697
</next-hop>
9798
</route>
9899
</ip>
100+
{% endif %}
99101
<interface>
100102
<if-name>eth0</if-name>
101103
<ip>
104+
{% if patty_used %}
105+
<dhcp-client>true</dhcp-client>
106+
{% else %}
102107
<address>{{ manager_external_ip }}{{ external_subnet_mask }}</address>
108+
{% endif %}
103109
</ip>
104110
<shutdown>false</shutdown>
105111
</interface>

catalyst_sdwan_lab/tasks/add.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def main(
6060
cml_user: str,
6161
cml_password: str,
6262
manager_ip: str,
63+
manager_port: int,
6364
manager_user: str,
6465
manager_password: str,
6566
lab_name: str,
@@ -124,7 +125,10 @@ def main(
124125

125126
log.info("Logging in to SD-WAN Manager...")
126127
manager_session = create_manager_session(
127-
url=manager_ip, username=manager_user, password=manager_password
128+
url=manager_ip,
129+
username=manager_user,
130+
password=manager_password,
131+
port=manager_port,
128132
)
129133
manager_config_settings = manager_session.endpoints.configuration_settings
130134
org_name = manager_config_settings.get_organizations()[0].org

catalyst_sdwan_lab/tasks/backup.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from cisco_sdwan.tasks.implementation import BackupArgs, TaskBackup
1919
from jinja2 import Environment, FileSystemLoader
2020
from ruamel.yaml import YAML
21+
from ruamel.yaml.scalarstring import LiteralScalarString
2122
from virl2_client import ClientLibrary
2223
from virl2_client.models.cl_pyats import ClPyats
2324

@@ -160,6 +161,7 @@ def main(
160161
cml_user: str,
161162
cml_password: str,
162163
manager_ip: str,
164+
manager_port: int,
163165
manager_user: str,
164166
manager_password: str,
165167
lab_name: str,
@@ -192,7 +194,10 @@ def main(
192194
# Login to SD-WAN Manager
193195
log.info("Logging in to SD-WAN Manager...")
194196
manager_session = create_manager_session(
195-
url=manager_ip, username=manager_user, password=manager_password
197+
url=manager_ip,
198+
username=manager_user,
199+
password=manager_password,
200+
port=manager_port,
196201
)
197202
manager_config_settings = manager_session.endpoints.configuration_settings
198203
org_name = manager_config_settings.get_organizations()[0].org
@@ -369,9 +374,9 @@ def main(
369374
"cat-sdwan-controller",
370375
"cat-sdwan-edge",
371376
]:
372-
lab_extract["nodes"][i]["configuration"] = custom_node_backup[
373-
lab_extract["nodes"][i]["label"]
374-
]
377+
lab_extract["nodes"][i]["configuration"] = LiteralScalarString(
378+
custom_node_backup[lab_extract["nodes"][i]["label"]]
379+
)
375380

376381
os.mkdir(workdir)
377382
with open(rf"{workdir}/cml_topology.yaml", "w") as file:
@@ -388,7 +393,7 @@ def main(
388393
)
389394

390395
with Rest(
391-
base_url=f"https://{manager_ip}",
396+
base_url=f"https://{manager_ip}:{manager_port}",
392397
username=manager_user,
393398
password=manager_password,
394399
) as api:

catalyst_sdwan_lab/tasks/delete.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ def main(
2626
# so we ask user to make sure the lab names are unique
2727
if len(lab) > 1:
2828
exit(
29-
f'There are multiple labs/topologies with name "{lab_name}". Please make sure '
29+
f"There are multiple labs/topologies with name '{lab_name}'. Please make sure "
3030
f"lab names are unique and rerun the delete task."
3131
)
3232
lab = lab[0]
3333

3434
if not force:
3535
confirmation = input(
36-
"\nThis will remove lab and all its data. "
36+
f"\nThis will remove '{lab_name}' lab and all its data. "
3737
"Are you sure you want to proceed? (yes/no): "
3838
)
3939
if confirmation.lower() != "yes":

catalyst_sdwan_lab/tasks/deploy.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def main(
3838
cml: ClientLibrary,
3939
cml_ip: str,
4040
manager_ip: str,
41+
manager_port: int,
4142
manager_mask: str,
4243
manager_gateway: str,
4344
manager_user: str,
@@ -46,6 +47,7 @@ def main(
4647
lab_name: str,
4748
bridge: str,
4849
dns_server: str,
50+
patty_used: bool,
4951
retry: bool,
5052
loglevel: Union[int, str],
5153
) -> None:
@@ -78,7 +80,17 @@ def main(
7880
# Prepare the CA for controllers certificate signing
7981
ca_cert, ca_key, ca_chain = load_certificate_details()
8082

81-
if not lab_name:
83+
if lab_name:
84+
# Verify lab name is not duplicated
85+
# Although CML allows labs with same name,
86+
# this crete confusion for other tasks where lab name is used
87+
existing_lab_names = [lab.title for lab in cml.all_labs(show_all=True)]
88+
if lab_name in existing_lab_names:
89+
exit(
90+
f"Lab with name '{lab_name}' already exists. "
91+
f"Please provide a different name to avoid confusion."
92+
)
93+
else:
8294
# User didn't provide lab name, generate by default
8395
# Find existing sdwan labs names
8496
lab_list_search = [
@@ -102,6 +114,10 @@ def main(
102114
# Encrypt SD-WAN Manager password to SHA512. The encrypted password will be used in bootstrap configuration.
103115
encrypted_manager_password = sha512_crypt.encrypt(manager_password, rounds=5000)
104116

117+
if patty_used:
118+
# PATty should be used for SD-WAN Manager reachability. This means bridge configuration needs to be set to NAT
119+
bridge = "NAT"
120+
105121
cml_topology = cml_tp_tmpl.render(
106122
title=lab_name,
107123
manager_image=manager_image,
@@ -120,6 +136,8 @@ def main(
120136
external_gateway=manager_gateway,
121137
bridge=bridge,
122138
dns_server=dns_server,
139+
manager_port=manager_port,
140+
patty_used=patty_used,
123141
)
124142

125143
if retry:
@@ -134,8 +152,10 @@ def main(
134152
)
135153
else:
136154
# Prepare and deploy the lab to CML
137-
# Check if the IP allocated for SD-WAN Manager is not already it use.
138-
check_manager_ip_is_free(manager_ip)
155+
156+
if not patty_used:
157+
# If PATty is not used, check if the IP allocated for SD-WAN Manager is not already it use.
158+
check_manager_ip_is_free(manager_ip)
139159
log.info("Importing the lab...")
140160
lab = cml.import_lab(cml_topology, lab_name)
141161
track_progress(log, "Waiting for nodes to boot...")
@@ -144,7 +164,7 @@ def main(
144164

145165
# Wait for SD-WAN Manager API to be available
146166
manager_session = wait_for_manager_session(
147-
manager_ip, manager_user, manager_password, log
167+
manager_ip, manager_port, manager_user, manager_password, log
148168
)
149169
# Configure basic settings like org-name, validator fqdn etc.
150170
configure_manager_basic_settings(manager_session, ca_chain, log)
@@ -175,6 +195,7 @@ def main(
175195

176196
restore_manager_configuration(
177197
manager_ip,
198+
manager_port,
178199
manager_user,
179200
manager_password,
180201
join(MANAGER_CONFIGS_DIR, f"v{config_version}"),
@@ -191,7 +212,7 @@ def main(
191212
f"#############################################\n"
192213
f"Lab is deployed.\n"
193214
f"CML URL: https://{cml_ip}\n"
194-
f"SD-WAN Manager URL: https://{manager_ip}:8443\n"
215+
f"SD-WAN Manager URL: https://{manager_ip}:{manager_port}\n"
195216
f"Use the username/password set with the script for CML and SD-WAN Manager login.\n"
196217
f"All other nodes use default username/password.\n"
197218
f"#############################################"

0 commit comments

Comments
 (0)