A Python client library for interacting with the AtlanticWave-SDX L2VPN API
Project description
SDXClient
A thin Python client that wraps the SDX HTTP routes, stages L2VPN payload metadata, guides endpoint selection, and keeps responses consistent.
- Returns dict everywhere: {"status_code": int, "data": Any, "error": Optional[str]}
- No user-facing tracebacks; friendly errors only.
Key Points
- Uses FABRIC authentication (token loaded via fablib; no token argument needed).
- Provides a guided flow: set first endpoint → set second endpoint → preview → create.
- One unified method:
set_endpoint(endpoint_position="first", ...)set_endpoint(endpoint_position="second", ...)
- VLAN choice is derived from
/device_info; supports preferring untagged. - Consistent return shape across all methods:
Initialization
from sdxclient import SDXClient
client = SDXClient() # tries FABRIC token
Return Shape (always)
{
"status_code": int,
"data": Any,
"error": Optional[str]
}
- status_code == 0 → client-side validation / network failure
- status_code >= 400 → server-side error (with best-effort error message)
Requirements
- Python 3.9 – 3.12
requestsfabrictestbed-extensions(for automatic FABRIC token loading)- A valid FABRIC token (fablib locates it automatically)
Core Read APIs (pass-through)
client.get_topology()
client.get_available_ports(search=None, filter=None, limit=None, fields=None, format="html|json")
client.get_all_vlans_available()
client.get_port_vlans_available(port_id)
Notes:
- filter wins over search.
- format="html" returns HTML table (string). format="json" returns structured JSON.
Selection Flow (endpoints)
client.clear_selection()
client.set_endpoint(
endpoint_position="first" | "second",
filter=None, search=None,
port_id=None, vlan=None,
prefer_untagged=False
)
client.get_selected_endpoints()
Rules:
- Use port_id for precise selection, or filter/search to resolve a single row.
- If multiple candidates match, you get an ambiguity error with a short candidate list.
- VLAN availability is checked inline against /available_vlans.
L2VPN Payload: Stage → Preview → Create
1) Stage payload metadata once
client.set_l2vpn_payload(
name="project-alpha-l2vpn",
notifications=["ops@example.org", "noc@example.org"]
)
- Validates name (non-empty, ≤ 50 chars).
- Validates notifications (1–10 emails; str input is normalized to a list).
2) Build payload locally (no network)
payload_result = client.get_l2vpn_payload()
# -> {"name": "...", "notifications": [...], "endpoints": [{...}, {...}]}
- Requires both endpoints to be selected and metadata to be staged.
- Re-validates endpoint shape and rejects same-VLAN per policy (see “VLAN Rules”).
- No availability calls here.
3) Preview payload with availability checks
preview_result = client.preview_l2vpn_payload()
# Re-checks VLAN availability via /available_vlans for both endpoints.
4) Create L2VPN (uses previewed payload)
create_result = client.create_l2vpn_from_selection()
- Uses the staged name/notifications + selected endpoints.
- Performs preview internally first (includes availability checks).
- No need to pass name/notifications again here.
CRUD Mirrors
- client.get_l2vpns(**query)
- client.get_l2vpn(service_id)
- client.update_l2vpn(service_id, **fields)
- client.delete_l2vpn(service_id)
Minimal End-to-End Example
from sdxclient import SDXClient
client = SDXClient()
1) Start fresh
client.clear_selection()
2) Choose endpoints
client.set_endpoint(endpoint_position="first", filter="SW17:7")
client.set_endpoint(endpoint_position="second", filter="SW17:27", prefer_untagged=True)
3) Stage metadata once
client.set_l2vpn_payload(
name="proj-alpha-mia-test",
notifications="noc@example.org"
)
4) Optional: local payload (no network)
local_payload = client.get_l2vpn_payload()
5) Preview with availability checks
preview = client.preview_l2vpn_payload()
6) Create
created = client.create_l2vpn_from_selection()
Error Examples (friendly)
client.get_port_vlans_available(None)
# {'status_code': 0, 'data': None, 'error': 'missing required parameter(s): port_id'}
client.set_endpoint(endpoint_position="first", filter="too-broad")
# {'status_code': 0, 'data': {'candidates': [...]}, 'error': 'ambiguous filter/search matched ...'}
client.get_l2vpn_payload() # without staging metadata
# {'status_code': 0, 'data': None, 'error': 'missing L2VPN name (set via set_l2vpn_payload)'}
VLAN Validation Rules for L2VPN
Allowed forms
- Numeric VLANs: 1..4095
- Ranges: A:B where 1 ≤ A < B ≤ 4095
- Keywords: any, untagged
- (all is not allowed)
Mixing rules
- Numeric ↔ Range (e.g., 200 with 100:300)
- any ↔ untagged
- any/untagged mixed with numeric/range
Rejection rules
- all mixed with anything (since all is not allowed at all)
- Same numeric VLAN twice (e.g., 200 & 200)
- Same exact range twice (e.g., 100:200 & 100:200)
Tips
-
Prefer format="json" for machine workflows; parse ports from /available_ports.
-
If you pass both filter and search, filter is used.
-
“No usable VLAN found” often means the port advertises none or they’re all in use.
-
If you want to skip availability checks, use get_l2vpn_payload() and post it yourself; otherwise use create_l2vpn_from_selection() to keep checks on.
Troubleshooting
- 401 / missing token → set a valid token or ensure FABRIC token is discoverable.
- Empty listings → loosen your filter/search; inspect /topology.
- Availability errors → verify get_port_vlans_available(port_id) shows a range that contains your requested VLAN token.
Changelog (relevant)
- Added set_l2vpn_payload(name, notifications): stage metadata once.
- Added get_l2vpn_payload(): build local payload without network.
- create_l2vpn_from_selection() no longer requires passing name/notifications; it uses staged metadata and runs a preview internally.
Install
Production (PyPI)
pip install sdxclient
or a specific version
pip install sdxclient==0.10.0
Test (TestPyPI pre-releases)
- Prefer exact RC version when installing from TestPyPI
pip install --index-url https://test.pypi.org/simple/
--extra-index-url https://pypi.org/simple
sdxclient==0.10.0rc1
- or allow any pre-release (if available)
pip install --index-url https://test.pypi.org/simple/
--extra-index-url https://pypi.org/simple
--pre sdxclient
Runtime configuration (test vs prod API)
-
sdxclient reads the base URL from the environment:
-
If SDX_BASE_URL isn’t set, the package falls back to production.
Releasing (maintainers)
- This project uses GitHub Actions + Trusted Publishing.
Branch/PR flow
-
Open PRs as usual. CI will build only (no publish).
-
On merge to main, if the version is a pre-release (contains rc), CI publishes to TestPyPI.
Test release (TestPyPI)
-
Bump version in sdx-client/pyproject.toml to an RC:
-
version = "X.Y.ZrcN"
Merge the PR to main or run the workflow manually:
-
Actions → “Build & Publish (TestPyPI → PyPI)” → Run workflow
-
target: testpypi
Install for testing:
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple \
sdxclient==X.Y.ZrcN
Releasing and Publishing
This project uses setuptools_scm for automatic versioning from Git tags.
GitHub Actions handles all publishing to TestPyPI and PyPI using OIDC Trusted Publishing — no API tokens needed.
Versioning Rules
- Do not edit the version manually in pyproject.toml.
- The version is derived automatically from your latest Git tag.
- Pre-releases (for testing) use release candidate tags:
git tag v0.10.1rc1
git push origin v0.10.1rc1
→ publishes to TestPyPI with version 0.10.1rc1.
- Final production releases use numeric tags only:
git tag -a v0.10.1 -m "Release 0.10.1"
git push origin v0.10.1
→ publishes to PyPI with version 0.10.1.
Delete tag to reissue it
git tag -d v0.10.2
git push origin :refs/tags/v0.10.2
Test Builds (TestPyPI)
-
Trigger:
-
Merge or push to the main branch
-
Manual workflow run with target=testpypi
-
Version format:
-
0.10.x.devN+gHASH (auto-generated dev build)
-
or 0.10.1rc1 (pre-release tag)
-
Install from TestPyPI:
pip install -i https://test.pypi.org/simple/ sdxclient
Production Releases (PyPI)
-
Trigger: push an annotated tag vX.Y.Z
-
Version format: clean X.Y.Z (no rc, no dev)
-
Install from PyPI:
pip install sdxclient==X.Y.Z
Manual Publishing (optional)
run the workflow manually from GitHub:
Actions → “Build & Publish (TestPyPI → PyPI)” → “Run workflow”
Pick:
- target: testpypi → expects pre-release or dev version
- target: pypi → expects final version
- Choose the branch or tag that contains your release commit.
Rules Enforced by the Workflow
-
TestPyPI: only accepts pre-release or dev versions (rc, devN, etc.).
-
PyPI: only accepts clean versions (no suffix).
-
No API tokens: OIDC Trusted Publishing handles authentication.
-
Same wheel: one build artifact published to both indexes.
-
Runtime URLs:
-
Test: SDX_BASE_URL=https://190.103.184.194
-
Prod: SDX_BASE_URL=https://sdxapi.atlanticwave-sdx.ai
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sdxclient-0.10.3.tar.gz.
File metadata
- Download URL: sdxclient-0.10.3.tar.gz
- Upload date:
- Size: 18.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3cc59885caf9616e15813c6466fa766ba5b1ce77117653fe47ebeeca52207a4
|
|
| MD5 |
4f8878a0f886489e1c91e04edbc07e6b
|
|
| BLAKE2b-256 |
2cc89fa652d2d39c824fec0f21661f576f3448c5f14328855633fa1942df9878
|
Provenance
The following attestation bundles were made for sdxclient-0.10.3.tar.gz:
Publisher:
publish.yml on atlanticwave-sdx/sdx-fabric
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sdxclient-0.10.3.tar.gz -
Subject digest:
c3cc59885caf9616e15813c6466fa766ba5b1ce77117653fe47ebeeca52207a4 - Sigstore transparency entry: 591205362
- Sigstore integration time:
-
Permalink:
atlanticwave-sdx/sdx-fabric@ee5d37a77ac1bf60c1f257c507cfaaf838b452c7 -
Branch / Tag:
refs/tags/v0.10.3 - Owner: https://github.com/atlanticwave-sdx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ee5d37a77ac1bf60c1f257c507cfaaf838b452c7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sdxclient-0.10.3-py3-none-any.whl.
File metadata
- Download URL: sdxclient-0.10.3-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efa9216a93eb7363d76c4feb11991c2f75ad9f702a89edf15b2bd4482d46d4da
|
|
| MD5 |
89d448330df82e216827eb7d4bce6742
|
|
| BLAKE2b-256 |
00923cb066a7c2f4ee98b97271843c3e626558aa23f74e280e24270eb7339b52
|
Provenance
The following attestation bundles were made for sdxclient-0.10.3-py3-none-any.whl:
Publisher:
publish.yml on atlanticwave-sdx/sdx-fabric
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sdxclient-0.10.3-py3-none-any.whl -
Subject digest:
efa9216a93eb7363d76c4feb11991c2f75ad9f702a89edf15b2bd4482d46d4da - Sigstore transparency entry: 591205366
- Sigstore integration time:
-
Permalink:
atlanticwave-sdx/sdx-fabric@ee5d37a77ac1bf60c1f257c507cfaaf838b452c7 -
Branch / Tag:
refs/tags/v0.10.3 - Owner: https://github.com/atlanticwave-sdx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ee5d37a77ac1bf60c1f257c507cfaaf838b452c7 -
Trigger Event:
push
-
Statement type: