Skip to content

Commit aa593ea

Browse files
authored
Merge pull request #14 from cisco-open/dev-2.0.10
Dev 2.0.10
2 parents 07e11e8 + 8b245e5 commit aa593ea

File tree

8 files changed

+459
-395
lines changed

8 files changed

+459
-395
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
- '3.9'
4040
- '3.10'
4141
- '3.11'
42+
- '3.12'
4243
steps:
4344
- name: Checkout
4445
uses: actions/checkout@v4

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Catalyst SD-WAN Lab 2.0.10 [May 10, 2024]
2+
3+
- Added support for Python 3.12
4+
- In setup task, added functionality to covert refplat ISO SD-WAN images to proper format so script can use them
5+
- In setup task, added --list parameter to list all SD-WAN software images available on CML server
6+
- Fixed problem where setup task might fail with "Cannot modify read-only node definition"
7+
- Fixed problem where add task could fail with undescriptive error "IndexError: list index out of range"
8+
- Updated README with installation guide for Windows
9+
110
# Catalyst SD-WAN Lab 2.0.9 [Apr 26, 2024]
211

312
#### Fixes:

README.md

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
[![Tests](https://github.com/cisco-open/sdwan-lab-deployment-tool/actions/workflows/test.yml/badge.svg)](https://github.com/netascode/iac-validate/actions/workflows/test.yml)
2-
![Python Support](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11-informational "Python Support: 3.9, 3.10, 3.11")
2+
![Python Support](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-informational "Python Support: 3.9, 3.10, 3.11, 3.12")
33

44
# Catalyst SD-WAN Lab Deployment Tool for Cisco Modeling Labs
55

66
This tool automates [Cisco Catalyst SD-WAN](https://www.cisco.com/site/us/en/solutions/networking/sdwan/index.html) lab deployment inside [Cisco Modeling Labs (CML)](https://www.cisco.com/c/en/us/products/cloud-systems-management/modeling-labs/index.html).
77

8+
The tool will help you automate your CML lab deployments with SD-WAN Manager, Controllers and Validators and up to 20 SD-WAN edges. You can build as pods as your CML platform can host. Please refer to the [Limitations and scale](#limitations-and-scale) for details.
9+
10+
11+
812
## Getting Started
913

1014
### Prerequisites
11-
Catalyst SD-WAN Lab tool requires Python 3.8 or newer. This can be verified by pasting the following to a terminal window:
15+
Catalyst SD-WAN Lab Deployment Tool requires Linux or macOS system.
16+
To run is on Windows, please use [Linux on Windows with WSL](/README.md#appendix---wsl-installation) or set up Linux VM/container.
1217

13-
% python3 -c "import sys;assert sys.version_info>(3,8)" && echo "ALL GOOD"
18+
Catalyst SD-WAN Lab Deployment Tool requires Python 3.9 or newer. This can be verified by pasting the following to a terminal window:
19+
20+
% python3 -c "import sys;assert sys.version_info>(3,9)" && echo "ALL GOOD"
1421

1522
If 'ALL GOOD' is printed it means Python requirements are met. If not, download and install the latest 3.x version at Python.org (https://www.python.org/downloads/).
1623

@@ -54,7 +61,7 @@ You can also use the following shortcut to run any lab task:
5461

5562
Notes:
5663
- The virtual environment is deactivated by typing 'deactivate' at the command prompt.
57-
- Before running SD-WAN Lab again, make sure to activate the virtual environment back again (source venv/bin/activate).
64+
- Before running Catalyst SD-WAN Lab Deployment Tool again, make sure to activate the virtual environment back again (source venv/bin/activate).
5865

5966
## Usage
6067
Simmilar to [Sastre](https://github.com/CiscoDevNet/sastre), the command line is structured as a set of base parameters, the task specification followed by task-specific parameters:
@@ -302,6 +309,37 @@ This task has several task-specific parameters.
302309
--lab <lab_name> Lab name
303310
--force Delete the lab without asking for confirmation. Note the all lab data will be lost!
304311

312+
## Limitations and scale
313+
The tool supports the following scale per CML lab:
314+
315+
- 1 SD-wan Manager instance (Cluster is not yet supported)
316+
- 8 SD-WAN Validators (Documented support from CCO)
317+
- 12 SD-WAN Controllers (Documented support from CCO)
318+
- 20 SD-WAN Edges
319+
- 10 SD-Routing edges
320+
321+
322+
323+
## Appendix - WSL Installation
324+
325+
To install WSL on your Windows VM or Physical machine. Ensure that the HW Virutalization is enabled in the BIOS or VM Defintion.
326+
327+
If its on Windows server you may need to run this command to allow the WSL to function properly
328+
329+
Open PowerShell as Administrator and run:
330+
331+
`Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux`
332+
333+
Install WSL with default distribution (Ubuntu)
334+
Open PowerShell and run
335+
336+
`wsl --install`
337+
338+
Once the installation is finished and you have restarted Windows you are able to continue the installation of this tool as described in the [installation section](README.md#installing) of this document.
339+
340+
You can read more about [Linux on Windows with WSL here](https://learn.microsoft.com/en-us/windows/wsl/install).
341+
342+
305343
## Authors
306344
Tomasz Zarski (tzarski@cisco.com)
307345

@@ -311,4 +349,4 @@ BSD-3-Clause
311349

312350
## Acknowledgments
313351
- Marcelo Reis and [Sastre](https://github.com/CiscoDevNet/sastre)
314-
- Inigo Alonso
352+
- Inigo Alonso

catalyst_sdwan_lab/__main__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,12 @@ def main() -> None:
101101
"setup", help="Setup on-prem CML to use Catalyst SD-WAN Lab automation."
102102
)
103103
setup_parser.add_argument(
104-
"--migrate",
104+
"--list",
105105
action="store_const",
106-
dest="migrate",
106+
dest="list",
107107
const=True,
108108
default=False,
109-
help="Migrate node and image definitions from SD-WAN Lab v1.x to v2.x. "
110-
"This task should be run once if CML server was using "
111-
"SD-WAN LAb Tool v1.x in the past.",
109+
help="After running setup task, list the available SD-WAN software per node type.",
112110
)
113111

114112
deploy_parser = task_subparsers.add_parser(
@@ -522,7 +520,7 @@ def main() -> None:
522520
)
523521
verify_cml_version(cml)
524522
if cli_args.task == "setup":
525-
setup.main(cml, cli_args.loglevel, cli_args.migrate)
523+
setup.main(cml, cli_args.loglevel, cli_args.list)
526524
elif cli_args.task == "deploy":
527525
deploy.main(
528526
cml,

catalyst_sdwan_lab/tasks/add.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,12 @@ def main(
357357
)
358358
]
359359

360+
if number_of_devices > len(free_uuids):
361+
exit(
362+
f"Cannot onboard {number_of_devices} WAN Edges as there are only "
363+
f"{len(free_uuids)} unused UUIDs available."
364+
)
365+
360366
new_nodes_nums = []
361367
for i in range(1, number_of_devices + 1):
362368
new_nodes_nums.append(f"{biggest_num + i}")
@@ -602,6 +608,12 @@ def main(
602608
)
603609
]
604610

611+
if number_of_devices > len(free_uuids):
612+
exit(
613+
f"Cannot onboard {number_of_devices} WAN Edges as there are only "
614+
f"{len(free_uuids)} unused UUIDs available."
615+
)
616+
605617
uuid_to_token = {
606618
device.uuid: device.serial_number
607619
for device in device_list.filter(

catalyst_sdwan_lab/tasks/setup.py

Lines changed: 59 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from os.path import join
1212
from typing import List, Union
1313

14-
from httpx import HTTPStatusError
1514
from ruamel.yaml import YAML
1615
from virl2_client import ClientLibrary
1716

@@ -26,14 +25,14 @@
2625
def upload_image_and_create_definition(
2726
log: Logger,
2827
cml: ClientLibrary,
29-
existing_image_definitions: List[str],
28+
existing_image_definitions_ids: List[str],
3029
node_type: str,
3130
software_version: str,
3231
node_label: str,
3332
software_images_dir: str,
3433
filename: str,
3534
) -> None:
36-
if f"{node_type}-{software_version}" in existing_image_definitions:
35+
if f"{node_type}-{software_version}" in existing_image_definitions_ids:
3736
log.info(
3837
f"Skipping {filename} as {node_type}-{software_version} image definition already exists."
3938
)
@@ -49,7 +48,7 @@ def upload_image_and_create_definition(
4948
cml.definitions.upload_image_definition(body=json.dumps(image_def))
5049

5150

52-
def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
51+
def main(cml: ClientLibrary, loglevel: Union[int, str], list: bool) -> None:
5352
# Setup logging
5453
log = setup_logging(loglevel)
5554

@@ -85,6 +84,13 @@ def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
8584
)
8685
else:
8786
# If dicts are not the same, then we need to update the node definition
87+
# Before update, check if node definition is read only
88+
if current_node_definition["general"]["read_only"]:
89+
# Remove read-only flag
90+
cml.definitions.set_node_definition_read_only(
91+
current_node_definition["id"], False
92+
)
93+
8894
log.info(
8995
f'[UPDATE] Updating node {new_node_definition["id"]} with '
9096
f'{new_node_definition["sim"]["linux_native"]["cpus"]} CPUs and '
@@ -102,22 +108,46 @@ def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
102108
# If node is not yet created, we need to create it
103109
log.info(f'[CREATE] Creating node {new_node_definition["id"]}...')
104110
cml.definitions.upload_node_definition(new_node_definition, json=True)
111+
112+
# Refresh node definitions
113+
node_definitions = cml.definitions.node_definitions()
105114
track_progress(log, "Verifying software images...")
106115
# Get the list of all image definitions already created in CML.
107116
# This is to avoid image duplication during upload.
108-
existing_image_definitions = [
109-
image_definition["id"]
110-
for image_definition in cml.definitions.image_definitions()
117+
existing_image_definitions = cml.definitions.image_definitions()
118+
existing_image_definitions_ids = [
119+
image_definition["id"] for image_definition in existing_image_definitions
111120
]
121+
for image_definition in existing_image_definitions:
122+
match = re.match(
123+
r"^cat-sdwan-(edge|controller|validator|manager)-([\w\-]+)$",
124+
image_definition["id"],
125+
)
126+
if match:
127+
# Migrate image from using - in software version to using .
128+
# For example from cat-sdwan-manager-20-13-1 to cat-sdwan-manager-20.13.1
129+
# Before update, check if node definition is read only
130+
if image_definition["read_only"]:
131+
# Remove read-only flag
132+
cml.definitions.set_image_definition_read_only(
133+
image_definition["id"], False
134+
)
135+
cml.definitions.remove_image_definition(image_definition["id"])
136+
# Set new ID and disk folder
137+
image_definition["id"] = (
138+
f"cat-sdwan-{match.group(1)}-{match.group(2).replace('-', '.')}"
139+
)
140+
image_definition["disk_subfolder"] = image_definition["id"]
141+
cml.definitions.upload_image_definition(image_definition)
142+
112143
log.info(f"Looking for new software images in {os.getcwd()}...")
113144
software_type_to_node_type_mapping = {
114145
"edge": "cat-sdwan-validator",
115146
"bond": "cat-sdwan-validator",
116147
"smart": "cat-sdwan-controller",
117148
"vmanage": "cat-sdwan-manager",
118149
}
119-
# Refresh node definitions
120-
node_definitions = cml.definitions.node_definitions()
150+
121151
# Check for any software that is present in software_images folder.
122152
for filename in os.listdir(SOFTWARE_IMAGES_DIR):
123153
if software_parser := re.match(r"viptela-(\w+)-([\d.]+)-", filename):
@@ -132,7 +162,7 @@ def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
132162
upload_image_and_create_definition(
133163
log,
134164
cml,
135-
existing_image_definitions,
165+
existing_image_definitions_ids,
136166
node_type,
137167
software_version,
138168
node_label,
@@ -154,7 +184,7 @@ def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
154184
upload_image_and_create_definition(
155185
log,
156186
cml,
157-
existing_image_definitions,
187+
existing_image_definitions_ids,
158188
node_type,
159189
software_version,
160190
node_label,
@@ -165,71 +195,22 @@ def main(cml: ClientLibrary, loglevel: Union[int, str], migrate: bool) -> None:
165195
else:
166196
log.debug(f"Skipping file {filename} (not a valid image).")
167197

168-
if migrate:
169-
node_definition_map = {
170-
"vmanage": "cat-sdwan-manager",
171-
"vsmart": "cat-sdwan-controller",
172-
"vedge": "cat-sdwan-validator",
173-
"cedge": "cat-sdwan-edge",
174-
}
175-
node_label_map = {
176-
"vmanage": "Catalyst SD-WAN Manager",
177-
"vsmart": "Catalyst SD-WAN Controller",
178-
"vedge": "Catalyst SD-WAN Validator",
179-
"cedge": "Catalyst SD-WAN Edge",
180-
}
181-
track_progress(log, "Running migration of node/image definitions...")
182-
# Migrate SD-WAN Lab Tool v1.x image definitions to v2.x
183-
all_migrated = True
184-
for image_definition in cml.definitions.image_definitions():
185-
current_id = image_definition["id"]
186-
current_node_definition = image_definition["node_definition_id"]
187-
if current_node_definition in ["vmanage", "vsmart", "vedge", "cedge"]:
188-
try:
189-
software_version = image_definition["id"].split("-")[1]
190-
new_image_definition = {
191-
"node_definition_id": node_definition_map[
192-
current_node_definition
193-
],
194-
"id": f"{node_definition_map[current_node_definition]}-{software_version}",
195-
"read_only": False,
196-
"label": f"{node_label_map[current_node_definition]} {software_version}",
197-
"disk_image": image_definition["disk_image"],
198-
}
199-
200-
cml.definitions.remove_image_definition(current_id)
201-
cml.definitions.upload_image_definition(new_image_definition)
202-
log.info(
203-
f"Migrated image definition {current_id} to "
204-
f"{node_definition_map[current_node_definition]}-{software_version}"
205-
)
206-
207-
except HTTPStatusError as e:
208-
all_migrated = False
209-
error = e.response.json()
210-
if error["code"] == 400 and error["description"].startswith(
211-
"Image Definition in use:"
212-
):
213-
log.info(
214-
f"Cannot migrate image definition {current_id} as it is currently in use."
215-
)
216-
217-
for node_definition in cml.definitions.node_definitions():
218-
node_id = node_definition["id"]
219-
if node_id in ["vmanage", "vsmart", "vedge", "cedge"]:
220-
if cml.definitions.image_definitions_for_node_definition(node_id):
221-
log.info(
222-
f"Cannot delete node definition {node_id} as it is currently in use."
223-
)
224-
all_migrated = False
225-
else:
226-
cml.definitions.remove_node_definition(node_id)
227-
log.info(f"Node definition {node_id} successfully removed.")
228-
229-
if not all_migrated:
230-
print(
231-
"\rSome node/image definitions could not be migrated as they are in use. "
232-
"Please remove the labs using the old definitions are rerun the setup with --migrate option."
233-
)
234-
235198
track_progress(log, "Setup task done\n")
199+
200+
if list:
201+
print("Available Software Versions:")
202+
for node_definition_id in [
203+
"cat-sdwan-manager",
204+
"cat-sdwan-controller",
205+
"cat-sdwan-validator",
206+
"cat-sdwan-edge",
207+
]:
208+
available_software_versions = []
209+
# List available SD-WAN software
210+
for (
211+
image_definition
212+
) in cml.definitions.image_definitions_for_node_definition(
213+
node_definition_id
214+
):
215+
available_software_versions.append(image_definition["id"].split("-")[3])
216+
print(f"- {node_definition_id}: {available_software_versions}")

0 commit comments

Comments
 (0)