Skip to content
This repository has been archived by the owner on Nov 21, 2024. It is now read-only.

Commit

Permalink
dev: sync with 0.36.0 (#848)
Browse files Browse the repository at this point in the history
* csr generation as task for >=20.16 (#838)

* Bump actions/checkout from 4.2.0 to 4.2.1

Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@d632683...eef6144)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* Multithreading Auth (#842)

* Bump actions/checkout from 4.2.1 to 4.2.2 (#846)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@eef6144...11bd719)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump abatilo/actions-poetry from 3.0.0 to 3.0.1 (#845)

Bumps [abatilo/actions-poetry](https://github.com/abatilo/actions-poetry) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/abatilo/actions-poetry/releases)
- [Changelog](https://github.com/abatilo/actions-poetry/blob/master/.releaserc)
- [Commits](abatilo/actions-poetry@7b6d33e...e78f54a)

---
updated-dependencies:
- dependency-name: abatilo/actions-poetry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump actions/setup-python from 5.2.0 to 5.3.0 (#844)

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@f677139...0b93645)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* bump dev version

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: PrzeG <[email protected]>
  • Loading branch information
3 people authored Oct 29, 2024
1 parent 1999e61 commit 3a6034e
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 65 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ jobs:
shell: sh

steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: ${{ matrix.python-version }}
- name: Set Up Poetry
uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 # v3.0.0
uses: abatilo/actions-poetry@e78f54a89cb052fff327414dd9ff010b5d2b4dbd # v3.0.1
with:
poetry-version: 1.3.1
- name: Install dependencies
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ jobs:
run:
shell: bash
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: 3.8
- name: Set Up Poetry
uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 # v3.0.0
uses: abatilo/actions-poetry@e78f54a89cb052fff327414dd9ff010b5d2b4dbd # v3.0.1
with:
poetry-version: 1.3.1
- name: Publish catalystwan
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ jobs:
shell: bash

steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: ${{ matrix.python-version }}
- name: Set Up Poetry
uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 # v3.0.0
uses: abatilo/actions-poetry@e78f54a89cb052fff327414dd9ff010b5d2b4dbd # v3.0.1
with:
poetry-version: 1.3.1
- name: Install dependencies
Expand Down
11 changes: 6 additions & 5 deletions ENDPOINTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
**THIS FILE WAS AUTO-GENERATED DO NOT EDIT**

Generated for: catalystwan-0.35.5.dev3
Generated for: catalystwan-0.36.0.dev0

All URIs are relative to */dataservice*
HTTP request | Supported Versions | Method | Payload Type | Return Type | Tenancy Mode
Expand All @@ -26,10 +26,11 @@ PUT /admin/user/profile/password||[**AdministrationUserAndGroup.update_profile_p
PUT /admin/user/{username}||[**AdministrationUserAndGroup.update_user**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/administration_user_and_group.py#L331)|[**UserUpdateRequest**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/administration_user_and_group.py#L34)|None|
PUT /admin/usergroup/{group_name}||[**AdministrationUserAndGroup.update_user_group**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/administration_user_and_group.py#L335)|[**UserGroup**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/administration_user_and_group.py#L84)|None|
DELETE /certificate/{uuid}||[**CertificateManagementDevice.delete_configuration**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L113)||[**DeviceDeletionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L15)|
POST /certificate/generate/csr||[**CertificateManagementDevice.generate_csr**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L117)|[**TargetDevice**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L22)|DataSequence[[**DeviceCsrGenerationResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L28)]|
POST /certificate/save/vedge/list||[**CertificateManagementDevice.change_vedge_list_validity**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L121)|list[[**VedgeListValidityPayload**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L100)]|[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/vedge/list?action={action}||[**CertificateManagementDevice.send_to_controllers**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L125)||[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/vsmart/list||[**CertificateManagementDevice.send_to_vbond**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L129)||[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/generate/csr|<20.16|[**CertificateManagementDevice.generate_csr**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L117)|[**TargetDevice**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L22)|DataSequence[[**DeviceCsrGenerationResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L28)]|
POST /certificate/generate/csr|>=20.16|[**CertificateManagementDevice.generate_csr_task**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L122)|[**TargetDevice**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L22)|[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/save/vedge/list||[**CertificateManagementDevice.change_vedge_list_validity**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L127)|list[[**VedgeListValidityPayload**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L100)]|[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/vedge/list?action={action}||[**CertificateManagementDevice.send_to_controllers**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L131)||[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
POST /certificate/vsmart/list||[**CertificateManagementDevice.send_to_vbond**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L135)||[**CertActionResponse**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_device.py#L108)|
GET /setting/configuration/webserver/certificate||[**CertificateManagementVManage.show_info**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_vmanage.py#L46)||[**WebServerCertificateInfo**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/certificate_management_vmanage.py#L11)|
GET /client/server||[**Client.server**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/client.py#L86)||[**ServerInfo**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/client.py#L23)|
GET /client/server/ready||[**Client.server_ready**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/client.py#L90)||[**ServerReady**](https://github.com/cisco-open/cisco-catalyst-wan-sdk/blob/main/catalystwan/endpoints/client.py#L80)|
Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,54 @@ with create_apigw_session(
```
</details>

<details>
<summary> <b>Threading</b> <i>(click to expand)</i></summary>

```python
from threading import Thread
from catalystwan.session import ManagerSession
from catalystwan.vmanage_auth import vManageAuth
from copy import copy

def print_devices(manager: ManagerSession):
# using context manager (recommended)
with manager.login() as session:
print(session.api.devices.get())

if __name__ =="__main__":

# 1. Create shared authentication handler for user session
auth = vManageAuth(username="username", password="password")
# 2. Configure session with base url and attach authentication handler
manager = ManagerSession(base_url="https://url:port", auth=auth)

# 3. Make sure each thread gets own copy of ManagerSession object
t1 = Thread(target=print_devices, args=(manager,))
t2 = Thread(target=print_devices, args=(copy(manager),))
t3 = Thread(target=print_devices, args=(copy(manager),))

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

print("Done!")
```
Threading can be achieved by using a shared auth object with sessions in each thread. As `ManagerSession` is not guaranteed to be thread-safe, it is recommended to create one session per thread. `ManagerSession` also comes in with a default `RequestLimiter`, which limits the number of concurrent requests to 50. It keeps `ManagerSession` from overloading the server and avoids HTTP 503 and HTTP 429 errors.
If you wish to modify the limit, you can pass a modified `RequestLimiter` to `ManagerSession`:
```python
from catalystwan.session import ManagerSession
from catalystwan.vmanage_auth import vManageAuth
from catalystwan.request_limiter import RequestLimiter

auth = vManageAuth(username="username", password="password")
limiter = RequestLimiter(max_requests=30)
manager = ManagerSession(base_url="https://url:port", auth=auth, request_limiter=limiter)
```
</details>

## API usage examples
All examples below assumes `session` variable contains logged-in [Manager Session](#Manager-Session) instance.
Expand Down
9 changes: 8 additions & 1 deletion catalystwan/abstractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Optional, Protocol, Type, TypeVar

from packaging.version import Version # type: ignore
from requests import PreparedRequest

from catalystwan.typed_list import DataSequence
from catalystwan.utils.session_type import SessionType
Expand Down Expand Up @@ -66,5 +67,11 @@ class AuthProtocol(Protocol):
def logout(self, client: APIEndpointClient) -> None:
...

def clear(self) -> None:
def clear(self, last_request: Optional[PreparedRequest]) -> None:
...

def increase_session_count(self) -> None:
...

def decrease_session_count(self) -> None:
...
36 changes: 32 additions & 4 deletions catalystwan/apigw_auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from threading import RLock
from typing import Literal, Optional
from urllib.parse import urlparse

Expand Down Expand Up @@ -37,13 +38,16 @@ def __init__(self, login: ApiGwLogin, logger: Optional[logging.Logger] = None, v
self.token = ""
self.logger = logger or logging.getLogger(__name__)
self.verify = verify
self.session_count: int = 0
self.lock: RLock = RLock()

def __str__(self) -> str:
return f"ApiGatewayAuth(mode={self.login.mode})"

def __call__(self, request: PreparedRequest) -> PreparedRequest:
self.handle_auth(request)
self.build_digest_header(request)
with self.lock:
self.handle_auth(request)
self.build_digest_header(request)
return request

def handle_auth(self, request: PreparedRequest) -> None:
Expand Down Expand Up @@ -92,5 +96,29 @@ def get_token(
def logout(self, client: APIEndpointClient) -> None:
return None

def clear(self) -> None:
self.token = ""
def _clear(self) -> None:
with self.lock:
self.token = ""

def increase_session_count(self) -> None:
with self.lock:
self.session_count += 1

def decrease_session_count(self) -> None:
with self.lock:
self.session_count -= 1

def clear(self, last_request: Optional[PreparedRequest]) -> None:
with self.lock:
# extract previously used jsessionid
if last_request is None:
token = None
else:
token = last_request.headers.get("Authorization")

if self.token == "" or f"Bearer {self.token}" == token:
# used auth was up-to-date, clear state
return self._clear()
else:
# used auth was out-of-date, repeat the request with a new one
return
8 changes: 7 additions & 1 deletion catalystwan/endpoints/certificate_management_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from pydantic import BaseModel, ConfigDict, Field

from catalystwan.endpoints import APIEndpoints, delete, post
from catalystwan.endpoints import APIEndpoints, delete, post, versions
from catalystwan.typed_list import DataSequence


Expand Down Expand Up @@ -114,10 +114,16 @@ class CertificateManagementDevice(APIEndpoints):
def delete_configuration(self, uuid: str) -> DeviceDeletionResponse:
...

@versions("<20.16")
@post("/certificate/generate/csr", "data")
def generate_csr(self, payload: TargetDevice) -> DataSequence[DeviceCsrGenerationResponse]:
...

@versions(">=20.16")
@post("/certificate/generate/csr")
def generate_csr_task(self, payload: TargetDevice) -> CertActionResponse:
...

@post("/certificate/save/vedge/list")
def change_vedge_list_validity(self, payload: List[VedgeListValidityPayload]) -> CertActionResponse:
...
Expand Down
18 changes: 18 additions & 0 deletions catalystwan/request_limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations

from contextlib import AbstractContextManager
from threading import Semaphore


class RequestLimiter(AbstractContextManager):
def __init__(self, max_requests: int = 49):
self._max_requests: int = max_requests
self._semaphore: Semaphore = Semaphore(value=self._max_requests)

def __enter__(self) -> RequestLimiter:
self._semaphore.acquire()
return self

def __exit__(self, *exc_info) -> None:
self._semaphore.release()
return
Loading

0 comments on commit 3a6034e

Please sign in to comment.