-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #246 from aristanetworks/release-1.3.0
Release 1.3.0
- Loading branch information
Showing
21 changed files
with
1,829 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
1.2.2 | ||
1.3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
docs/labs/lab03-configlet-management/get_applied_netelements.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Copyright (c) 2023 Arista Networks, Inc. | ||
# Use of this source code is governed by the Apache License 2.0 | ||
# that can be found in the COPYING file. | ||
|
||
from cvprac.cvp_client import CvpClient | ||
import ssl | ||
import argparse | ||
ssl._create_default_https_context = ssl._create_unverified_context | ||
import requests.packages.urllib3 | ||
requests.packages.urllib3.disable_warnings() | ||
|
||
# Create connection to CloudVision | ||
clnt = CvpClient() | ||
clnt.connect(nodes=['cvp1'], username="username", password="password") | ||
|
||
parser = argparse.ArgumentParser( | ||
description='Get the list of devices and containers a configlet is attached to') | ||
parser.add_argument('-c', '--configlet', required=True, help='The name of the configlet') | ||
args = parser.parse_args() | ||
|
||
configlet_name = args.configlet | ||
devices = clnt.api.get_applied_devices(configlet_name) | ||
|
||
containers = clnt.api.get_applied_containers(configlet_name) | ||
print(f"Total number of devices {configlet_name} is attached to: {devices['total']}\n") | ||
print(f"Total number of containers {configlet_name} is attached to: {containers['total']}\n") | ||
col1 = "Device FQDN/hostname" | ||
col2 = "IP Address" | ||
print(f"{col1:<40}{col2:<40}") | ||
print("="*80) | ||
for device in devices['data']: | ||
print(f"{device['hostName']:<40}{device['ipAddress']}") | ||
|
||
print("\nList of containers:\n") | ||
for container in containers['data']: | ||
print(container['containerName']) |
120 changes: 120 additions & 0 deletions
120
docs/labs/lab06-provisioning/atd_e2e_provisioning_workflow.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
# Copyright (c) 2021 Arista Networks, Inc. | ||
# Use of this source code is governed by the Apache License 2.0 | ||
# that can be found in the COPYING file. | ||
|
||
# This script is an example on provisioning registered devices in CloudVision that is based on | ||
# Arista Test Drive (ATD) and similar to what the ansible playbooks do in | ||
# https://github.com/arista-netdevops-community/atd-avd. | ||
# It does the following: | ||
# - creates and uploads configlets, | ||
# - creates the container hierarchy in Network Provisiong | ||
# - moves the devices to their target containers | ||
# - assigns the configlets to the devices | ||
# - creates a change control from the genereated tasks | ||
# - approves and executes the change control | ||
|
||
import uuid | ||
import time | ||
import ssl | ||
from datetime import datetime | ||
from cvprac.cvp_client import CvpClient | ||
ssl._create_default_https_context = ssl._create_unverified_context | ||
|
||
# Create connection to CloudVision | ||
clnt = CvpClient() | ||
clnt.connect(['cvp1'],'username', 'password') | ||
|
||
# Create container topology | ||
container_name = "DC1_LEAFS" | ||
container_topology = [{"containerName": "ATD_FABRIC", "parentContainerName": 'Tenant'}, | ||
{"containerName": "ATD_LEAFS", "parentContainerName": 'ATD_FABRIC'}, | ||
{"containerName": "pod1", "parentContainerName": 'ATD_LEAFS'}, | ||
{"containerName": "pod2", "parentContainerName": 'ATD_LEAFS'}, | ||
{"containerName": "ATD_SERVERS", "parentContainerName": 'ATD_FABRIC'}, | ||
{"containerName": "ATD_SPINES", "parentContainerName": 'ATD_FABRIC'}, | ||
{"containerName": "ATD_TENANT_NETWORKS", "parentContainerName": 'ATD_FABRIC'}] | ||
for container in container_topology: | ||
try: | ||
container_name = container['containerName'] | ||
# Get parent container information | ||
parent = clnt.api.get_container_by_name(container['parentContainerName']) | ||
print(f'Creating container {container_name}\n') | ||
clnt.api.add_container(container_name,parent["name"],parent["key"]) | ||
except Exception as e: | ||
if "Data already exists in Database" in str(e): | ||
print ("Container already exists, continuing...") | ||
|
||
# Create device mappers | ||
devices = [{'deviceName': "leaf1", | ||
'configlets': ["BaseIPv4_Leaf1", "AVD_leaf1"], | ||
"parentContainerName": "pod1"}, | ||
{'deviceName': "leaf2", | ||
'configlets': ["BaseIPv4_Leaf2", "AVD_leaf2"], | ||
"parentContainerName": "pod1"}, | ||
{'deviceName': "leaf3", | ||
'configlets': ["BaseIPv4_Leaf3", "AVD_leaf3"], | ||
"parentContainerName": "pod2"}, | ||
{'deviceName': "leaf4", | ||
'configlets': ["BaseIPv4_Leaf4", "AVD_leaf4"], | ||
"parentContainerName": "pod2"}, | ||
{'deviceName': "spine1", | ||
'configlets': ["BaseIPv4_Spine1", "AVD_spine1"], | ||
"parentContainerName": "ATD_SPINES"}, | ||
{'deviceName': "spine2", | ||
'configlets': ["BaseIPv4_Spine2", "AVD_spine2"], | ||
"parentContainerName": "ATD_SPINES"}] | ||
|
||
task_list = [] | ||
for device in devices: | ||
# Load the AVD configlets from file | ||
with open("./configlets/AVD_" + device['deviceName'] + ".cfg", "r") as file: | ||
configlet_file = file.read() | ||
avd_configlet_name = device['configlets'][1] | ||
base_configlet_name = device['configlets'][0] # preloaded configlet in an ATD environment | ||
container_name = device['parentContainerName'] | ||
base_configlet = clnt.api.get_configlet_by_name(base_configlet_name) | ||
configlets = [base_configlet] | ||
# Update the AVD configlets if they exist, otherwise upload them from the configlets folder | ||
print (f"Creating configlet {avd_configlet_name} for {device['deviceName']}\n") | ||
try: | ||
configlet = clnt.api.get_configlet_by_name(avd_configlet_name) | ||
clnt.api.update_configlet(configlet_file, configlet['key'], avd_configlet_name) | ||
configlets.append(configlet) | ||
except: | ||
clnt.api.add_configlet(avd_configlet_name, configlet_file) | ||
configlet = clnt.api.get_configlet_by_name(avd_configlet_name) | ||
configlets.append(configlet) | ||
# Get device data | ||
device_data = clnt.api.get_device_by_name(device['deviceName'] + ".atd.lab") | ||
# Get the parent container data for the device | ||
container = clnt.api.get_container_by_name(container_name) | ||
device_name = device['deviceName'] | ||
print(f"Moving device {device_name} to container {container_name}\n") | ||
# The move action will create the task first, however if the devices are already in the target | ||
# container, for instance if the script was run multiple times than the move action will | ||
# not generate a task anymore, therefore it's better to create the task list from the | ||
# Update Config action which will reuse the Move Device action's task if one exists, | ||
# otherwise will create a new one. | ||
move = clnt.api.move_device_to_container("python", device_data, container) | ||
apply_configlets = clnt.api.apply_configlets_to_device("", device_data, configlets) | ||
task_list = task_list + apply_configlets['data']['taskIds'] | ||
|
||
print(f"Generated task IDs are: {task_list}\n") | ||
|
||
# Generate unique ID for the change control | ||
cc_id = str(uuid.uuid4()) | ||
cc_name = f"Change_{datetime.now().strftime('%Y%m%d_%H%M%S')}" | ||
|
||
print("Creating Change control with the list of tasks") | ||
clnt.api.change_control_create_for_tasks(cc_id, cc_name, task_list, series=False) | ||
|
||
print("Approving Change Control") | ||
# adding a few seconds sleep to avoid small time diff between the local system and CVP | ||
time.sleep(2) | ||
approve_note = "Approving CC via cvprac" | ||
clnt.api.change_control_approve(cc_id, notes=approve_note) | ||
|
||
# Start the change control | ||
print("Executing Change Control...") | ||
start_note = "Start the CC via cvprac" | ||
clnt.api.change_control_start(cc_id, notes=start_note) |
Oops, something went wrong.