Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.12", "3.13", "3.14"]

steps:
- name: Check out repository
Expand Down
88 changes: 82 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,83 @@
# Changelog
> * Pre-v1.00, 11.2020 -- Initial release - Marcel Zehnder
> * v1.00, 11.2020 -- Adjustments for OpenSource - Andreas Graber
> * v1.3, 06.2021 -- Snapshot creation added - Dario Kaelin
> * v1.5, 01.2023 -- Dependency Update
> * v1.6, 06.2024 -- Improvement for subscription - Dario Kaelin
> * v1.7, 12.2025 -- Dependency Update - Dario Kaelin

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0] - 2026-10-26

### Added

- Typed, thread-safe `AciClient` for direct APIC and Nexus Dashboard gateway
access, with password and certificate authentication.
- Structured queries, APIC filter helpers, generic response models, explicit
pagination, and connection-pool limits.
- Subscription handles, snapshot job monitoring, and `session_token` for
external WebSocket integrations.
- Injectable HTTP transports and deterministic pytest helpers, with expanded
examples and offline/live APIC testing guides.
- A runnable README example testing an automation function with a reusable
pytest fixture.

### Changed

- Requires Python 3.12 or newer.
- Modern clients verify TLS by default, use `cryptography` for certificate
signing, and exclude secure fields from snapshots by default.
- Authentication sessions and response decoding now live in dedicated internal
modules, keeping the public client focused on HTTP routing and operations.
- Snapshot waits and pagination deadlines include authentication and HTTP
requests, cap phase timeouts, and reject late results.

### Fixed

- Require patched certifi, urllib3, and cryptography releases in installed
distributions, with a compatible pyOpenSSL minimum.
- Redact APIC shared keys and nested credential fields in test request history,
including credential queries and Nexus Dashboard proxy paths.
- Raise `ResponseDecodeError` for malformed managed objects, authentication,
login-domain, and subscription responses.
- Include guides and examples in source distributions and use repository links
for documentation rendered on PyPI.

### Deprecated

- `ACI` and `ACICert` emit `LegacyAPIWarning`; their existing interfaces remain
compatible in 2.0.

## [1.7] - 2025-12

### Changed

- Updated project dependencies.

## [1.6] - 2024-06

### Changed

- Improved subscription support.

## [1.5] - 2023-01

### Changed

- Updated project dependencies.

## [1.3] - 2021-06

### Added

- Added snapshot creation.

## [1.0.0] - 2020-11

### Changed

- Prepared the project for open-source distribution.

## [0.x] - 2020-11

### Added

- Initial release.
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Releases are done from the upstream repository:
2. The upstream CI workflow runs tests and lint checks for the pull request.
3. After review, the pull request is merged into `netcloud/aciClient`.
4. When maintainers want to publish a release, they update the version in `pyproject.toml` if needed.
5. Maintainers create a version tag such as `v1.9.0` in `netcloud/aciClient`.
5. Maintainers create a version tag such as `v2.0.0` in `netcloud/aciClient`.
6. The upstream publish workflow builds the package with `uv build` and publishes it to PyPI.

Publishing requires PyPI trusted publishing to be configured for `netcloud/aciClient`.
Expand All @@ -54,6 +54,11 @@ Publishing requires PyPI trusted publishing to be configured for `netcloud/aciCl

## Local Development

Tests in `test/` are grouped by behavior: client configuration, authentication,
gateway routing, responses, pagination, snapshots, subscriptions, and consumer
test helpers. Shared factories live in `test/helpers.py`; `test/test_aci.py`
covers the legacy `ACI` interface. Add tests to the relevant behavior module.

```bash
uv sync --group dev
uv run pytest
Expand Down
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include CHANGELOG.md CONTRIBUTING.md TESTING.md
recursive-include examples *.md *.py
recursive-include test *.py
183 changes: 72 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,144 +1,105 @@
# aciClient
# aciClient 2.0

![PyPi](https://img.shields.io/pypi/v/aciClient)
A lightweight, typed, thread-safe Python 3.12+ client for Cisco ACI automation
and pytest. Connect directly to APIC or through the Nexus Dashboard ACI gateway.

A python wrapper to the Cisco ACI REST-API.

## Python Version

We support Python 3.10 and up.
[Examples](https://github.com/netcloud/aciClient/blob/master/examples/README.md) · [Testing](https://github.com/netcloud/aciClient/blob/master/TESTING.md) · [Migration](https://github.com/netcloud/aciClient/blob/master/examples/README.md#legacy-migration) · [Contributing](https://github.com/netcloud/aciClient/blob/master/CONTRIBUTING.md)

## Installation
With `pip`:

```bash
pip install aciClient
```

With `uv`:

```bash
uv add aciClient
```

## Installation for Developing
```bash
git clone https://github.com/netcloud/aciClient.git
uv sync --group dev
```

## Usage
## Quick start

### Initialisation
The examples use Cisco's shared
[Always-On ACI Simulator](https://developer.cisco.com/docs/aci/sandbox/) and
tenant `aciclient`.
Run the [create example](https://github.com/netcloud/aciClient/blob/master/examples/README.md#create-a-bridge-domain-in-a-tenant)
first, then read the tenant using the public sandbox credentials:

### Username/password
```python
import aciClient
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

proxies = {
'http': 'socks5://127.0.0.1:1080',
'https': 'socks5://127.0.0.1:1080'
}

aciclient = aciClient.ACI(apic_hostname, apic_username, apic_password, refresh=False, proxies=proxies)
try:
aciclient.login()

aciclient.getJson(uri)
aciclient.postJson(config)
aciclient.deleteMo(dn)

aciclient.logout()
except Exception as e:
logger.exception("Stack Trace")
```
from aciClient import AciClient, PasswordAuth

For automatic authentication token refresh you can set variable ```refresh``` to True

```python
aciclient = aciClient.ACI(apic_hostname, apic_username, apic_password, refresh=True)
with AciClient(
"sandboxapicdc.cisco.com", PasswordAuth("admin", "!v3G@!4@Y")
) as client:
tenant = client.get_mo("uni/tn-aciclient").one()
print(tenant.attributes["name"])
```

Construction performs no network traffic. Login is lazy and coordinated
across threads; the context manager closes the client. `one()` raises
`NoResultError` when the tenant does not exist.

### Certificate/signature
```python
import aciClient
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
## Examples

aciclient = aciClient.ACICert(apic_hostname, path_to_privatekey_file, certificate_dn)
| Task | Where to start |
| --- | --- |
| Create, read, update, or delete bridge domains | [Tenant management](https://github.com/netcloud/aciClient/blob/master/examples/README.md#tenant-management) |
| Work with child objects and APIC filter operators | [Children and filtering](https://github.com/netcloud/aciClient/blob/master/examples/README.md#read-a-tenants-child-bridge-domains) |
| Integrate a shared client into an application or FastAPI | [Client lifecycle](https://github.com/netcloud/aciClient/blob/master/examples/README.md#client-lifecycle) |
| Receive APIC notifications with an external WebSocket | [Subscription workflow](https://github.com/netcloud/aciClient/blob/master/examples/README.md#subscriptions) |
| Test automation with an injected HTTP transport | [Pytest guide](https://github.com/netcloud/aciClient/blob/master/TESTING.md) |

try:
aciclient.getJson(uri)
aciclient.postJson(config)
aciclient.deleteMo(dn)
except Exception as e:
logger.exception("Stack Trace")
```
## Nexus Dashboard gateway

## Examples
Nexus Dashboard provides an
[APIC API Proxy](https://developer.cisco.com/docs/nexus-dashboard/latest/get-apic-data/).
For ordinary APIC requests, change only client creation: use the Nexus
Dashboard IP or hostname as `endpoint` and the ACI cluster name shown in
Nexus Dashboard as `nexus_dashboard_cluster_name`. Request methods, DNs,
payloads, filters, responses, and pagination stay the same.

### get config
```python
tenants = aciclient.getJson('class/fvTenant.json?order-by=fvTenant.dn|asc')
from aciClient import AciClient, NexusDashboardPasswordAuth

for mo in tenants:
print(f'tenant DN: {mo["fvTenant"]["attributes"]["dn"]}')
```

### post config
```python
config = {
"fvTenant": {
"attributes": {
"dn": "uni/tn-XYZ"
}
}
}

aciclient.postJson(config)
client = AciClient(
endpoint="nd.example.test",
auth=NexusDashboardPasswordAuth("admin", "secret"),
nexus_dashboard_cluster_name="production-fabric",
)
```

### delete MOs
```python
aciclient.deleteMo('uni/tn-XYZ')
```
Gateway access requires an enabled APIC Proxy Mode and a Super-Admin account.
Only `NexusDashboardPasswordAuth` is supported in this mode; subscriptions
are unavailable. See [gateway setup and limitations](https://github.com/netcloud/aciClient/blob/master/examples/README.md#nexus-dashboard-gateway)
for authentication, per-cluster clients, and session lifecycle details.

### create snapshot
You can specify a tenant in variable ```target_dn``` or not provide any to do a fabric-wide snapshot.
```python
aci.snapshot(description='test', target_dn='/uni/tn-test')
```
## Client behavior

### Subscriptions
You can subscribe to an ACI object with websocket and get near-instant updates on-change.
To use the subscriptions you have to:
- Login to ACI
- Open websocket to ACI
- Subscribe to an ACI object via aciClient.subscribe
- Refresh subscription to an ACI object via aciClient.subscription_refresh
- Handle messages sent from ACI through websocket
| Area | What to expect |
| --- | --- |
| Authentication | Direct APIC supports `PasswordAuth` and `CertificateAuth`. See [domains and certificate keys](https://github.com/netcloud/aciClient/blob/master/examples/README.md#authentication-and-tls). |
| TLS | Verification is enabled by default. CA paths and `SSLContext` are supported; `verify=False` emits `InsecureTLSWarning`. |
| Results | Methods return `AciResponse` with immutable generic `ManagedObject` objects. Unknown classes and attributes are preserved; APIC attribute values remain strings. |
| Writes | Build explicit payloads: read objects may contain blank sensitive attributes. |
| Pagination | Requests do not paginate automatically. Use `iter_pages`, `iter_objects`, `collect_pages`, or `collect_objects` with `PaginationPolicy`; effective page size is capped at 2,000. [Limits and consistency](https://github.com/netcloud/aciClient/blob/master/examples/README.md#responses-and-pagination). |
| Connections | Share one client per connection identity across threads and create separate clients per process. Applications own shutdown and registries. [Lifecycle details](https://github.com/netcloud/aciClient/blob/master/examples/README.md#client-lifecycle). |
| Retries | Each request is sent once. Applications own retries, queuing, and metrics. |
| Snapshots | `create_snapshot()` returns a job; `job.wait()` waits for completion. Secure fields are excluded by default. [Snapshot example](https://github.com/netcloud/aciClient/blob/master/examples/README.md#snapshots). |

You can find example code here: examples/subscription.py
## Testing with pytest

## Contributing
Test your automation offline using scripted APIC responses. Start with the
[runnable pytest example](https://github.com/netcloud/aciClient/blob/master/examples/test_automation.py), or see the
[testing guide](https://github.com/netcloud/aciClient/blob/master/TESTING.md) for fixtures and error handling.

Please read [CONTRIBUTING.md](https://github.com/netcloud/aciClient/blob/master/CONTRIBUTING.md) for details on our code
of conduct, and the process for submitting pull requests to this project.
## Legacy migration

## Authors
`ACI` and `ACICert` remain available in 2.0 and emit `LegacyAPIWarning`.
Version 2.1, targeted for October 2027, will require explicit
`allow_legacy=True`. See the [migration guide](https://github.com/netcloud/aciClient/blob/master/examples/README.md#legacy-migration)
for compatibility details, method replacements, and the removal timeline.

* **Marcel Zehnder** - *Initial work*
* **Andreas Graber** - *Migration to open source*
* **Richard Strnad** - *Paginagtion for large requests, various small stuff*
* **Dario Kaelin** - *Added snapshot creation*
## Development

## License
```bash
uv sync --group dev
uv run pytest
uv run ruff check .
```

This project is licensed under MIT - see the [LICENSE.md](https://github.com/netcloud/aciClient/blob/master/LICENSE.md) file for details.
Repository tests use mocked transports and require no APIC or Nexus Dashboard.
See [CONTRIBUTING.md](https://github.com/netcloud/aciClient/blob/master/CONTRIBUTING.md) for contribution and release procedures.
Loading
Loading