Merging upstream version 1.3.2+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
77fa26eaf5
commit
aa182b4768
7 changed files with 127 additions and 29 deletions
40
README.md
40
README.md
|
@ -4,25 +4,31 @@
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
1. [Overview](#overview)
|
- [Arista Cloudvision® Portal RESTful API Client](#arista-cloudvision-portal-restful-api-client)
|
||||||
|
- [Table of Contents](#table-of-contents)
|
||||||
|
- [Overview](#overview)
|
||||||
- [Requirements](#requirements)
|
- [Requirements](#requirements)
|
||||||
1. [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Development: Run from Source](#development-run-from-source)
|
- [Development: Run from Source](#development-run-from-source)
|
||||||
1. [Getting Started](#getting-started)
|
- [Step 1: Clone the cvprac Github repo](#step-1-clone-the-cvprac-github-repo)
|
||||||
|
- [Step 2: Check out the desired version or branch](#step-2-check-out-the-desired-version-or-branch)
|
||||||
|
- [Step 3: Install cvprac using Pip with -e switch](#step-3-install-cvprac-using-pip-with--e-switch)
|
||||||
|
- [Step 4: Install cvprac development requirements](#step-4-install-cvprac-development-requirements)
|
||||||
|
- [Getting Started](#getting-started)
|
||||||
- [Connecting](#connecting)
|
- [Connecting](#connecting)
|
||||||
- [CVP On Premises](#cvp-on-premises)
|
- [CVP On Premises](#cvp-on-premises)
|
||||||
- [CVaaS](#cvaas)
|
- [CVaaS](#cvaas)
|
||||||
- [CVP Version Handling](#cvp-version-handling)
|
- [CVP Version Handling](#cvp-version-handling)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
1. [Notes For API Class Usage](#notes-for-api-class-usage)
|
- [Notes for API Class Usage](#notes-for-api-class-usage)
|
||||||
- [Containers](#containers)
|
- [Containers](#containers)
|
||||||
1. [Testing](#testing)
|
- [Testing](#testing)
|
||||||
1. [Contact or Questions](#contact-or-questions)
|
- [Contact or Questions](#contact-or-questions)
|
||||||
1. [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
- [Working With Git](#working-with-git)
|
- [Working With Git](#working-with-git)
|
||||||
- [Submitting Pull Requests](#submitting-pull-requests)
|
- [Submitting Pull Requests](#submitting-pull-requests)
|
||||||
- [Pull Request Semantics](#pull-request-semantics)
|
- [Pull Request Semantics](#pull-request-semantics)
|
||||||
1. [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
@ -151,7 +157,7 @@ examples below demonstrate connecting to CVP On Premises setups.
|
||||||
### CVaaS
|
### CVaaS
|
||||||
|
|
||||||
CVaaS is CloudVision as a Service. Users with CVaaS must use a REST API
|
CVaaS is CloudVision as a Service. Users with CVaaS must use a REST API
|
||||||
token for accessing CVP with REST APIs.
|
token (service account tokens) for accessing CVP with REST APIs.
|
||||||
|
|
||||||
- In the case where users authenticate with CVP (CVaaS) using Oauth a
|
- In the case where users authenticate with CVP (CVaaS) using Oauth a
|
||||||
- REST API token is required to be generated and used for running REST
|
- REST API token is required to be generated and used for running REST
|
||||||
|
@ -170,6 +176,22 @@ generic in this sense. If you are using the cvaas\_token parameter
|
||||||
please convert to api\_token because the cvaas\_token parameter will be
|
please convert to api\_token because the cvaas\_token parameter will be
|
||||||
deprecated in the future.
|
deprecated in the future.
|
||||||
|
|
||||||
|
Please note that the correct regional URL where the CVaaS tenant is deployed must be used. The following are the
|
||||||
|
cluster URLs used in production:
|
||||||
|
|
||||||
|
| Region | URL |
|
||||||
|
|--------|-----|
|
||||||
|
| United States 1a | [www.arista.io](https://www.arista.io) |
|
||||||
|
| United States 1c| [www.cv-prod-us-central1-c.arista.io](https://www.cv-prod-us-central1-c.arista.io)|
|
||||||
|
| Canada | [www.cv-prod-na-northeast1-b.arista.io](https://www.cv-prod-na-northeast1-b.arista.io)|
|
||||||
|
| Europe West 2| [www.cv-prod-euwest-2.arista.io](https://www.cv-prod-euwest-2.arista.io)|
|
||||||
|
| Japan| [www.cv-prod-apnortheast-1.arista.io](https://www.cv-prod-apnortheast-1.arista.io)|
|
||||||
|
| Australia | [www.cv-prod-ausoutheast-1.arista.io](https://www.cv-prod-ausoutheast-1.arista.io)|
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
|
||||||
|
URLs without `www` are not supported.
|
||||||
|
|
||||||
### CVP Version Handling
|
### CVP Version Handling
|
||||||
|
|
||||||
The CVP RESTful APIs often change between releases of CVP. Cvprac
|
The CVP RESTful APIs often change between releases of CVP. Cvprac
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
1.3.1
|
1.3.2
|
||||||
|
|
|
@ -32,5 +32,5 @@
|
||||||
''' RESTful API Client class for Cloudvision(R) Portal
|
''' RESTful API Client class for Cloudvision(R) Portal
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__version__ = '1.3.1'
|
__version__ = '1.3.2'
|
||||||
__author__ = 'Arista Networks, Inc.'
|
__author__ = 'Arista Networks, Inc.'
|
||||||
|
|
|
@ -572,7 +572,7 @@ class CvpApi(object):
|
||||||
'%s&queryparam=&startIndex=%d&endIndex=%d' %
|
'%s&queryparam=&startIndex=%d&endIndex=%d' %
|
||||||
(key, start, end), timeout=self.request_timeout)
|
(key, start, end), timeout=self.request_timeout)
|
||||||
|
|
||||||
def get_inventory(self, start=0, end=0, query=''):
|
def get_inventory(self, start=0, end=0, query='', provisioned=True):
|
||||||
''' Returns the a dict of the net elements known to CVP.
|
''' Returns the a dict of the net elements known to CVP.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -595,7 +595,7 @@ class CvpApi(object):
|
||||||
timeout=self.request_timeout)
|
timeout=self.request_timeout)
|
||||||
return data['netElementList']
|
return data['netElementList']
|
||||||
self.log.debug('v2 Inventory API Call')
|
self.log.debug('v2 Inventory API Call')
|
||||||
data = self.clnt.get('/inventory/devices?provisioned=true',
|
data = self.clnt.get('/inventory/devices?provisioned=%s' % provisioned,
|
||||||
timeout=self.request_timeout)
|
timeout=self.request_timeout)
|
||||||
containers = self.get_containers()
|
containers = self.get_containers()
|
||||||
for dev in data:
|
for dev in data:
|
||||||
|
@ -1463,7 +1463,7 @@ class CvpApi(object):
|
||||||
return self.clnt.post(url, data=data, timeout=self.request_timeout)
|
return self.clnt.post(url, data=data, timeout=self.request_timeout)
|
||||||
|
|
||||||
def apply_configlets_to_device(self, app_name, dev, new_configlets,
|
def apply_configlets_to_device(self, app_name, dev, new_configlets,
|
||||||
create_task=True, reorder_configlets=False):
|
create_task=True, reorder_configlets=False, validate=False):
|
||||||
''' Apply the configlets to the device.
|
''' Apply the configlets to the device.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1484,6 +1484,12 @@ class CvpApi(object):
|
||||||
directly. Set this parameter to True only with the full
|
directly. Set this parameter to True only with the full
|
||||||
list of configlets being applied to the device provided
|
list of configlets being applied to the device provided
|
||||||
via the new_configlets parameter.
|
via the new_configlets parameter.
|
||||||
|
validate (bool): Defaults to False. If set to True, the function
|
||||||
|
will validate and compare the configlets to be attached and
|
||||||
|
populate the configCompareCount field in the data dict. In case
|
||||||
|
all keys are 0, ie there is no difference between designed-config
|
||||||
|
and running-config after applying the configlets, no task will be
|
||||||
|
generated.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
response (dict): A dict that contains a status and a list of
|
response (dict): A dict that contains a status and a list of
|
||||||
|
@ -1536,6 +1542,16 @@ class CvpApi(object):
|
||||||
'nodeTargetIpAddress': dev['ipAddress'],
|
'nodeTargetIpAddress': dev['ipAddress'],
|
||||||
'childTasks': [],
|
'childTasks': [],
|
||||||
'parentTask': ''}]}
|
'parentTask': ''}]}
|
||||||
|
if validate:
|
||||||
|
validation_result = self.validate_configlets_for_device(dev['systemMacAddress'], ckeys)
|
||||||
|
data['data'][0].update({
|
||||||
|
"configCompareCount": {
|
||||||
|
"mismatch": validation_result['mismatch'],
|
||||||
|
"reconcile": validation_result['reconcile'],
|
||||||
|
"new": validation_result['new']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
self.log.debug('apply_configlets_to_device: saveTopology data:\n%s' %
|
self.log.debug('apply_configlets_to_device: saveTopology data:\n%s' %
|
||||||
data['data'])
|
data['data'])
|
||||||
self._add_temp_action(data)
|
self._add_temp_action(data)
|
||||||
|
@ -1545,7 +1561,7 @@ class CvpApi(object):
|
||||||
|
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
def remove_configlets_from_device(self, app_name, dev, del_configlets,
|
def remove_configlets_from_device(self, app_name, dev, del_configlets,
|
||||||
create_task=True):
|
create_task=True, validate=False):
|
||||||
''' Remove the configlets from the device.
|
''' Remove the configlets from the device.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1554,6 +1570,12 @@ class CvpApi(object):
|
||||||
del_configlets (list): List of configlet name and key pairs
|
del_configlets (list): List of configlet name and key pairs
|
||||||
create_task (bool): Determines whether or not to execute a save
|
create_task (bool): Determines whether or not to execute a save
|
||||||
and create the tasks (if any)
|
and create the tasks (if any)
|
||||||
|
validate (bool): Defaults to False. If set to True, the function
|
||||||
|
will validate and compare the configlets to be attached and
|
||||||
|
populate the configCompareCount field in the data dict. In case
|
||||||
|
all keys are 0, ie there is no difference between designed-config
|
||||||
|
and running-config after applying the configlets, no task will be
|
||||||
|
generated.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
response (dict): A dict that contains a status and a list of
|
response (dict): A dict that contains a status and a list of
|
||||||
|
@ -1612,6 +1634,16 @@ class CvpApi(object):
|
||||||
'nodeTargetIpAddress': dev['ipAddress'],
|
'nodeTargetIpAddress': dev['ipAddress'],
|
||||||
'childTasks': [],
|
'childTasks': [],
|
||||||
'parentTask': ''}]}
|
'parentTask': ''}]}
|
||||||
|
if validate:
|
||||||
|
validation_result = self.validate_configlets_for_device(dev['systemMacAddress'], keep_keys)
|
||||||
|
data['data'][0].update({
|
||||||
|
"configCompareCount": {
|
||||||
|
"mismatch": validation_result['mismatch'],
|
||||||
|
"reconcile": validation_result['reconcile'],
|
||||||
|
"new": validation_result['new']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
self.log.debug('remove_configlets_from_device: saveTopology data:\n%s'
|
self.log.debug('remove_configlets_from_device: saveTopology data:\n%s'
|
||||||
% data['data'])
|
% data['data'])
|
||||||
self._add_temp_action(data)
|
self._add_temp_action(data)
|
||||||
|
@ -3775,8 +3807,13 @@ class CvpApi(object):
|
||||||
'deviceId': 'BAD032986065E8DC14CBB6472EC314A6'},
|
'deviceId': 'BAD032986065E8DC14CBB6472EC314A6'},
|
||||||
'time': '2022-02-12T02:58:30.765459650Z'}
|
'time': '2022-02-12T02:58:30.765459650Z'}
|
||||||
'''
|
'''
|
||||||
device_info = self.get_device_by_serial(device_id)
|
device_exists = False
|
||||||
if device_info is not None and 'serialNumber' in device_info:
|
inventory = self.get_inventory(provisioned=False)
|
||||||
|
for device in inventory:
|
||||||
|
if device['serialNumber'] == device_id:
|
||||||
|
device_exists = True
|
||||||
|
break
|
||||||
|
if device_exists:
|
||||||
msg = 'Decommissioning via Resource APIs are supported from 2021.3.0 or newer.'
|
msg = 'Decommissioning via Resource APIs are supported from 2021.3.0 or newer.'
|
||||||
# For on-prem check the version as it is only supported from 2021.3.0+
|
# For on-prem check the version as it is only supported from 2021.3.0+
|
||||||
if self.cvp_version_compare('>=', 7.0, msg):
|
if self.cvp_version_compare('>=', 7.0, msg):
|
||||||
|
|
|
@ -114,7 +114,7 @@ class CvpClient(object):
|
||||||
# Maximum number of times to retry a get or post to the same
|
# Maximum number of times to retry a get or post to the same
|
||||||
# CVP node.
|
# CVP node.
|
||||||
NUM_RETRY_REQUESTS = 3
|
NUM_RETRY_REQUESTS = 3
|
||||||
LATEST_API_VERSION = 8.0
|
LATEST_API_VERSION = 9.0
|
||||||
|
|
||||||
def __init__(self, logger='cvprac', syslog=False, filename=None,
|
def __init__(self, logger='cvprac', syslog=False, filename=None,
|
||||||
log_level='INFO'):
|
log_level='INFO'):
|
||||||
|
@ -212,7 +212,8 @@ class CvpClient(object):
|
||||||
self.version = version
|
self.version = version
|
||||||
self.log.info('Version %s', version)
|
self.log.info('Version %s', version)
|
||||||
# Set apiversion to latest available API version for CVaaS
|
# Set apiversion to latest available API version for CVaaS
|
||||||
# Set apiversion to 8.0 for 2022.1.x
|
# Set apiversion to 9.0 for 2023.1.x
|
||||||
|
# Set apiversion to 8.0 for 2022.1.x - 2022.3.x
|
||||||
# Set apiversion to 7.0 for 2021.3.x
|
# Set apiversion to 7.0 for 2021.3.x
|
||||||
# Set apiversion to 6.0 for 2021.2.x
|
# Set apiversion to 6.0 for 2021.2.x
|
||||||
# Set apiversion to 5.0 for 2020.2.4 through 2021.1.x
|
# Set apiversion to 5.0 for 2020.2.4 through 2021.1.x
|
||||||
|
@ -232,7 +233,10 @@ class CvpClient(object):
|
||||||
' Appending 0. Updated Version String - %s',
|
' Appending 0. Updated Version String - %s',
|
||||||
".".join(version_components))
|
".".join(version_components))
|
||||||
full_version = ".".join(version_components)
|
full_version = ".".join(version_components)
|
||||||
if parse_version(full_version) >= parse_version('2022.1.0'):
|
if parse_version(full_version) >= parse_version('2023.1.0'):
|
||||||
|
self.log.info('Setting API version to v9')
|
||||||
|
self.apiversion = 9.0
|
||||||
|
elif parse_version(full_version) >= parse_version('2022.1.0'):
|
||||||
self.log.info('Setting API version to v8')
|
self.log.info('Setting API version to v8')
|
||||||
self.apiversion = 8.0
|
self.apiversion = 8.0
|
||||||
elif parse_version(full_version) >= parse_version('2021.3.0'):
|
elif parse_version(full_version) >= parse_version('2021.3.0'):
|
||||||
|
@ -561,6 +565,14 @@ class CvpClient(object):
|
||||||
# Alternative to adding token to headers it can be added to
|
# Alternative to adding token to headers it can be added to
|
||||||
# cookies as shown below.
|
# cookies as shown below.
|
||||||
# self.cookies = {'access_token': self.api_token}
|
# self.cookies = {'access_token': self.api_token}
|
||||||
|
url = self.url_prefix_short + '/api/v1/rest/'
|
||||||
|
response = self.session.get(url,
|
||||||
|
cookies=self.cookies,
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=self.connect_timeout,
|
||||||
|
verify=self.cert)
|
||||||
|
# Verify that the generic request was successful
|
||||||
|
self._is_good_response(response, 'Authenticate: %s' % url)
|
||||||
|
|
||||||
def logout(self):
|
def logout(self):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -5,10 +5,12 @@ to help users interact with Arista CloudVision easily and automate the provision
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
1. [Authentication](#authentication)
|
- [cvprac labs](#cvprac-labs)
|
||||||
|
- [Table of Contents](#table-of-contents)
|
||||||
|
- [Authentication](#authentication)
|
||||||
- [Password Authentication](#password-authentication)
|
- [Password Authentication](#password-authentication)
|
||||||
- [Service Account Token Authentication](#service-account-token-authentication)
|
- [Service Account Token Authentication](#service-account-token-authentication)
|
||||||
1. [Known Limitations](#known-limitations)
|
- [Known Limitations](#known-limitations)
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
|
@ -60,6 +62,8 @@ clnt = CvpClient()
|
||||||
clnt.connect(nodes=['10.83.13.33'], username='',password='',api_token=token)
|
clnt.connect(nodes=['10.83.13.33'], username='',password='',api_token=token)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Note that for CVaaS the correct regional URL must be used including `www.`. Please refer to the main page's [README.md](../../README.md#cvaas)
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
- for any APIs that interact with EOS devices, the service account name must match the name of the username
|
- for any APIs that interact with EOS devices, the service account name must match the name of the username
|
||||||
|
|
23
docs/release-notes-1.3.2.rst
Normal file
23
docs/release-notes-1.3.2.rst
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
######
|
||||||
|
v1.3.2
|
||||||
|
######
|
||||||
|
|
||||||
|
2023-12-14
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* Add handling of new password change logout functionality in 2023.1.0. (`254 <https://github.com/aristanetworks/cvprac/pull/254>`_) [`mharista <https://github.com/mharista>`_]
|
||||||
|
* Add support for config validation during config assign. (`255 <https://github.com/aristanetworks/cvprac/pull/255>`_) [`noredistribution <https://github.com/noredistribution>`_]
|
||||||
|
* Add support for config validation during config removal. (`256 <https://github.com/aristanetworks/cvprac/pull/256>`_) [`noredistribution <https://github.com/noredistribution>`_]
|
||||||
|
|
||||||
|
Fixed
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
* Add ability to use device_decommissioning for unprovisioned devices. (`253 <https://github.com/aristanetworks/cvprac/pull/253>`_) [`noredistribution <https://github.com/noredistribution>`_]
|
||||||
|
* Add check to connect() to ensure token works. (`258 <https://github.com/aristanetworks/cvprac/pull/258>`_) [`chetryan <https://github.com/chetryan>`_]
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* Add documentation for CVaaS regional URLs. (`259 <https://github.com/aristanetworks/cvprac/pull/259>`_) [`noredistribution <https://github.com/noredistribution>`_]
|
Loading…
Add table
Reference in a new issue