1
0
Fork 0

Merging upstream version 1.4.1+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-14 08:08:15 +02:00
parent 419af0eb9f
commit a9eef38502
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
9 changed files with 167 additions and 44 deletions

View file

@ -0,0 +1,6 @@
version: v1.0
allowed_secrets:
- filepath_literal: "docs/labs/lab07-aaa/svc_account_misc.py"
secret_literal: "9bfb39ff892c81d6ac9f25ff95d0389719595feb"
category: FALSE_POSITIVE
reason: Example token in documentation example file

3
.gitignore vendored
View file

@ -54,3 +54,6 @@ docs/_build/
docs/_modules/modules_by_category.rst docs/_modules/modules_by_category.rst
docs/_modules/list_of_*.rst docs/_modules/list_of_*.rst
docs/_modules/*_module.rst docs/_modules/*_module.rst
# .DS_Store
.DS_Store

View file

@ -20,3 +20,4 @@ exclude Jenkinsfile
exclude pre-commit.sh exclude pre-commit.sh
exclude report exclude report
exclude htmlcov exclude htmlcov
recursive-exclude .arista *.yaml

View file

@ -75,9 +75,10 @@ using the API methods.
### Requirements ### Requirements
- Python 2.7 or later - Python 3.7 or later
- Python logging module - Python logging module
- Python requests module version 1.0.0 or later - Python requests module with socks version 2.27.0 or later
- Python packaging module version 23.2 or later
## Installation ## Installation

View file

@ -1 +1 @@
1.4.0 1.4.1

View file

@ -32,5 +32,5 @@
''' RESTful API Client class for Cloudvision(R) Portal ''' RESTful API Client class for Cloudvision(R) Portal
''' '''
__version__ = '1.4.0' __version__ = '1.4.1'
__author__ = 'Arista Networks, Inc.' __author__ = 'Arista Networks, Inc.'

View file

@ -3930,6 +3930,15 @@ class CvpApi():
'time': '2022-05-03T15:38:53.725014447Z', 'type': 'INITIAL'}, ...] 'time': '2022-05-03T15:38:53.725014447Z', 'type': 'INITIAL'}, ...]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
url = '/api/resources/serviceaccount/v1/Token/all'
self.log.debug(f"v14 {url}")
# Pull list of tokens out of data key of return for new resource APIs
resp = self.clnt.get(url)
tokens = []
if "data" in resp:
tokens = resp["data"]
return tokens
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
url = '/api/v3/services/arista.serviceaccount.v1.TokenService/GetAll' url = '/api/v3/services/arista.serviceaccount.v1.TokenService/GetAll'
self.log.debug(f"v7 {url}") self.log.debug(f"v7 {url}")
@ -3939,6 +3948,8 @@ class CvpApi():
def svc_account_token_get_one(self, token_id): def svc_account_token_get_one(self, token_id):
''' Get a service account token's state using Resource APIs ''' Get a service account token's state using Resource APIs
Supported versions: CVP 2021.3.0 or newer and CVaaS. Supported versions: CVP 2021.3.0 or newer and CVaaS.
Args:
token_id (string): The id of the service account token.
Returns: Returns:
response (list): Returns a list of dict that contains... response (list): Returns a list of dict that contains...
Ex: [{'value': {'key': {'id': 'randomId'}, 'user': 'string', Ex: [{'value': {'key': {'id': 'randomId'}, 'user': 'string',
@ -3947,11 +3958,16 @@ class CvpApi():
'time': '2022-05-03T15:38:53.725014447Z', 'type': 'INITIAL'}] 'time': '2022-05-03T15:38:53.725014447Z', 'type': 'INITIAL'}]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
endpoint = '/api/resources/serviceaccount/v1/Token'
query_param = f"?key.id={token_id}"
self.log.debug(f'v14 {endpoint + query_param}')
return self.clnt.get(endpoint + query_param)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
endpoint = '/api/v3/services/arista.serviceaccount.v1.TokenService/GetOne'
payload = {"key": {"id": token_id}} payload = {"key": {"id": token_id}}
url = '/api/v3/services/arista.serviceaccount.v1.TokenService/GetOne' self.log.debug(f'v7 {endpoint} {payload}')
self.log.debug(f"v7 {url} {payload}") return self.clnt.post(endpoint, data=payload)
return self.clnt.post(url, data=payload)
return None return None
def svc_account_token_delete(self, token_id): def svc_account_token_delete(self, token_id):
@ -3965,11 +3981,15 @@ class CvpApi():
'time': '2022-07-26T15:29:03.687167871Z'}] 'time': '2022-07-26T15:29:03.687167871Z'}]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
endpoint = f'/api/resources/serviceaccount/v1/TokenConfig?key.id={token_id}'
self.log.debug(f'v14 {endpoint}')
return self.clnt.delete(endpoint)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
endpoint = '/api/v3/services/arista.serviceaccount.v1.TokenConfigService/Delete'
payload = {"key": {"id": token_id}} payload = {"key": {"id": token_id}}
url = '/api/v3/services/arista.serviceaccount.v1.TokenConfigService/Delete' self.log.debug(f'v7 {endpoint} {payload}')
self.log.debug(f"v7 {url} {payload}") return self.clnt.post(endpoint, data=payload)
return self.clnt.post(url, data=payload)
return None return None
def svc_account_token_set(self, username, duration, description): def svc_account_token_set(self, username, duration, description):
@ -3987,14 +4007,31 @@ class CvpApi():
'description': 'cvprac test', 'description': 'cvprac test',
'valid_for': '550s', 'token': '<ey...>'}] 'valid_for': '550s', 'token': '<ey...>'}]
''' '''
payload = {'value': {'description': description,
'user': username,
'valid_for': duration}}
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
payload = {
'key': {
'id': ''
},
'description': description,
'user': username,
'validFor': duration,
'token': ''
}
endpoint = '/api/resources/serviceaccount/v1/TokenConfig'
self.log.debug(f'v14 {endpoint} {payload}')
return self.clnt.post(endpoint, data=payload)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
url = '/api/v3/services/arista.serviceaccount.v1.TokenConfigService/Set' payload = {
self.log.debug(f"v7 {url} {payload}") 'value': {
return self.clnt.post(url, data=payload) 'description': description,
'user': username,
'valid_for': duration
}
}
endpoint = '/api/v3/services/arista.serviceaccount.v1.TokenConfigService/Set'
self.log.debug(f'v7 {endpoint} {payload}')
return self.clnt.post(endpoint, data=payload)
return None return None
def svc_account_get_all(self): def svc_account_get_all(self):
@ -4005,13 +4042,21 @@ class CvpApi():
Ex: [{'value': {'key': {'name': 'ansible'}, 'status': 'ACCOUNT_STATUS_ENABLED', Ex: [{'value': {'key': {'name': 'ansible'}, 'status': 'ACCOUNT_STATUS_ENABLED',
'description': 'lab-tests', 'groups': {'values': ['network-admin']}}, 'description': 'lab-tests', 'groups': {'values': ['network-admin']}},
'time': '2022-02-10T04:28:14.251684869Z', 'type': 'INITIAL'}, ...] 'time': '2022-02-10T04:28:14.251684869Z', 'type': 'INITIAL'}, ...]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
endpoint = '/api/resources/serviceaccount/v1/Account/all'
self.log.debug(f"v14 {endpoint}")
# Pull list of accounts out of data key of return for new resource APIs
resp = self.clnt.get(endpoint)
svc_accounts = []
if "data" in resp:
svc_accounts = resp["data"]
return svc_accounts
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
url = '/api/v3/services/arista.serviceaccount.v1.AccountService/GetAll' endpoint = '/api/v3/services/arista.serviceaccount.v1.AccountService/GetAll'
self.log.debug(f"v7 {url}") self.log.debug(f"v7 {endpoint}")
return self.clnt.post(url) return self.clnt.post(endpoint)
return None return None
def svc_account_get_one(self, username): def svc_account_get_one(self, username):
@ -4026,13 +4071,35 @@ class CvpApi():
'time': '2022-02-10T04:28:14.251684869Z'}] 'time': '2022-02-10T04:28:14.251684869Z'}]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
endpoint = '/api/resources/serviceaccount/v1/Account'
query_param = f"?key.name={username}"
self.log.debug(f"v14 {endpoint + query_param}")
return self.clnt.get(endpoint + query_param)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
endpoint = '/api/v3/services/arista.serviceaccount.v1.AccountService/GetOne'
payload = {"key": {"name": username}} payload = {"key": {"name": username}}
url = '/api/v3/services/arista.serviceaccount.v1.AccountService/GetOne' self.log.debug(f"v7 {endpoint} {payload}")
self.log.debug(f"v7 {url} {payload}") return self.clnt.post(endpoint, data=payload)
return self.clnt.post(url, data=payload)
return None return None
def _get_valid_role_ids(self, roles):
''' Helper function to validate and retrieve role IDs based on provided roles.
Args:
roles (list): The list of role names.
Returns:
role_ids (list): The list of role IDs.
'''
role_ids = []
all_roles = self.get_roles()
for role in all_roles['roles']:
if role['key'] in roles or role['name'] in roles:
role_ids.append(role['key'])
if len(roles) != len(role_ids):
self.log.warning(f"Not all provided roles {roles} are valid. "
f"Only using the found valid roles {role_ids}")
return role_ids
def svc_account_set(self, username, description, roles, status): def svc_account_set(self, username, description, roles, status):
''' Create a service account using Resource APIs. ''' Create a service account using Resource APIs.
Supported versions: CVP 2021.3.0 or newer and CVaaS. Supported versions: CVP 2021.3.0 or newer and CVaaS.
@ -4056,23 +4123,26 @@ class CvpApi():
'time': '2022-07-26T18:19:55.392173445Z'}] 'time': '2022-07-26T18:19:55.392173445Z'}]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
# Retrieve valid role IDs
role_ids = self._get_valid_role_ids(roles)
if self.cvp_version_compare('>=', 14.0, msg):
payload = {
'description': description,
'groups': {'values': role_ids},
'key': {'name': username},
'status': status
}
endpoint = '/api/resources/serviceaccount/v1/AccountConfig'
self.log.debug(f"v14 {endpoint} {payload}")
return self.clnt.post(endpoint, data=payload)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
role_ids = []
all_roles = self.get_roles()
for role in all_roles['roles']:
if role['key'] in roles or role['name'] in roles:
role_ids.append(role['key'])
if len(roles) != len(role_ids):
self.log.warning(f"Not all provided roles {roles} are valid. "
f"Only using the found valid roles {role_ids}")
payload = {'value': {'description': description, payload = {'value': {'description': description,
'groups': {'values': role_ids}, 'groups': {'values': role_ids},
'key': {'name': username}, 'key': {'name': username},
'status': status}} 'status': status}}
url = '/api/v3/services/arista.serviceaccount.v1.AccountConfigService/Set' endpoint = '/api/v3/services/arista.serviceaccount.v1.AccountConfigService/Set'
self.log.debug(f"v7 {url} {payload}") self.log.debug(f"v7 {endpoint} {payload}")
return self.clnt.post(url, data=payload) return self.clnt.post(endpoint, data=payload)
return None return None
def svc_account_delete(self, username): def svc_account_delete(self, username):
@ -4086,11 +4156,15 @@ class CvpApi():
'time': '2022-07-26T18:26:53.637425846Z'}] 'time': '2022-07-26T18:26:53.637425846Z'}]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.' msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
if self.cvp_version_compare('>=', 14.0, msg):
endpoint = f'/api/resources/serviceaccount/v1/AccountConfig?key.name={username}'
self.log.debug(f"v14 {endpoint}")
return self.clnt.delete(endpoint)
if self.cvp_version_compare('>=', 7.0, msg): if self.cvp_version_compare('>=', 7.0, msg):
payload = {"key": {"name": username}} payload = {"key": {"name": username}}
url = '/api/v3/services/arista.serviceaccount.v1.AccountConfigService/Delete' endpoint = '/api/v3/services/arista.serviceaccount.v1.AccountConfigService/Delete'
self.log.debug(f"v7 {url} {payload}") self.log.debug(f"v7 {endpoint} {payload}")
return self.clnt.post(url, data=payload) return self.clnt.post(endpoint, data=payload)
return None return None
def svc_account_delete_expired_tokens(self): def svc_account_delete_expired_tokens(self):
@ -4105,11 +4179,21 @@ class CvpApi():
'time': '2022-07-26T18:30:28.022504853Z','type': 'INITIAL'}, 'time': '2022-07-26T18:30:28.022504853Z','type': 'INITIAL'},
{'value': {'key': {'id': '2f6325d9c'},...] {'value': {'key': {'id': '2f6325d9c'},...]
''' '''
msg = 'Service Account Resource APIs are supported from 2021.3.0+.'
valid_until_format = "valid_until"
resource_api_schema = False
if self.cvp_version_compare('>=', 14.0, msg):
resource_api_schema = True
valid_until_format = "validUntil"
tokens = self.svc_account_token_get_all() tokens = self.svc_account_token_get_all()
expired_tokens = [] expired_tokens = []
for tok in tokens: for tok in tokens:
token = tok['value'] if resource_api_schema:
if datetime.strptime(token['valid_until'], "%Y-%m-%dT%H:%M:%SZ") < datetime.utcnow(): token_data = tok['result']['value']
self.svc_account_token_delete(token['key']['id']) else:
token_data = tok['value']
if (datetime.strptime(token_data[valid_until_format], "%Y-%m-%dT%H:%M:%SZ") <
datetime.utcnow()):
self.svc_account_token_delete(token_data['key']['id'])
expired_tokens.append(tok) expired_tokens.append(tok)
return expired_tokens return expired_tokens

View file

@ -123,7 +123,7 @@ class CvpClient():
# 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 = 9.0 LATEST_API_VERSION = 14.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'):
@ -213,7 +213,13 @@ class CvpClient():
For CVP versions 2020.2.4 through 2021.1.x, use api version 5.0 For CVP versions 2020.2.4 through 2021.1.x, use api version 5.0
For CVP versions 2021.2.x, use api version 6.0 For CVP versions 2021.2.x, use api version 6.0
For CVP versions 2021.3.x, use api version 7.0 For CVP versions 2021.3.x, use api version 7.0
For CVP versions 2022.1.0 and beyond, use api version 8.0 For CVP versions 2022.x.x, use api version 8.0
For CVP versions 2023.1.x, use api version 9.0
For CVP versions 2023.2.x, use api version 10.0
For CVP versions 2023.3.x, use api version 11.0
For CVP versions 2024.1.x, use api version 12.0
For CVP versions 2024.2.x, use api version 13.0
For CVP versions 2024.3.x and beyond, use api version 14.0
Args: Args:
version (str): The CVP version in use. version (str): The CVP version in use.
@ -221,6 +227,11 @@ class CvpClient():
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 14.0 for 2024.3.x
# Set apiversion to 13.0 for 2024.2.x
# Set apiversion to 12.0 for 2024.1.x
# Set apiversion to 11.0 for 2023.3.x
# Set apiversion to 10.0 for 2023.2.x
# Set apiversion to 9.0 for 2023.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 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
@ -242,7 +253,13 @@ class CvpClient():
' 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(full_version) >= parse('2024.1.0'): if parse(full_version) >= parse('2024.3.0'):
self.log.info('Setting API version to v14')
self.apiversion = 14.0
elif parse(full_version) >= parse('2024.2.0'):
self.log.info('Setting API version to v13')
self.apiversion = 13.0
elif parse(full_version) >= parse('2024.1.0'):
self.log.info('Setting API version to v12') self.log.info('Setting API version to v12')
self.apiversion = 12.0 self.apiversion = 12.0
elif parse(full_version) >= parse('2023.3.0'): elif parse(full_version) >= parse('2023.3.0'):

View file

@ -0,0 +1,11 @@
######
v1.4.1
######
2025-5-8
Enhancements
^^^^^^^^^^^^
* Add support new service account resource APIs. (`281 <https://github.com/aristanetworks/cvprac/pull/281>`_) [`noredistribution <https://github.com/noredistribution>`_]
* Updates for CVP 2024.3.0 suppot. (`282 <https://github.com/aristanetworks/cvprac/pull/282/>`_) [`mharista <https://github.com/mharista>`_]