Clients and nodes¶
Niwaki and AsyncNiwaki own the session; NiwakiNode / AsyncNiwakiNode
are the DN-scoped handles they hand out. The clients observe — writing
goes through the design DSL (The design DSL).
Clients¶
- class niwaki.Niwaki(
- host=None,
- username=None,
- password=None,
- *,
- verify_ssl=True,
- timeout=30.0,
- refresh_threshold=60,
- retry=None,
Bases:
objectSync entry point for the ACI SDK.
Use as a sync context manager — authentication happens on
__enter__and the session is closed on__exit__. For async code useAsyncNiwakiinstead.Use as a context manager (recommended):
with Niwaki("https://apic.example.com", "admin", "secret") as aci: bds = aci.query(fvBD).fetch()
Use
connect()for explicit lifecycle management:aci = Niwaki.connect("https://apic.example.com", "admin", "secret") try: bd = aci.root.tenant("prod").bd("web").read() finally: aci.close()
- Parameters:
host (str | None) – Base URL of the APIC (e.g.
"https://sandboxapicdc.cisco.com"). Falls back toAPIC_HOSTenvironment variable if omitted.username (str | None) – APIC username. Falls back to
APIC_USERNAMEif omitted.password (str | None) – APIC password. Falls back to
APIC_PASSWORDif omitted.verify_ssl (bool | str) – TLS verification —
True(system CA store), a path to a PEM CA bundle (private/enterprise CA), orFalse(lab only). Default:True.timeout (float) – HTTP request timeout in seconds. Default: 30.
refresh_threshold (int) – Seconds before token expiry at which a proactive refresh is triggered. Default: 60.
retry (RetryConfig | None) – Custom retry policy. Defaults to 3 attempts with exponential back-off. Construct with
RetryConfig.
- classmethod connect(
- host,
- username,
- password,
- *,
- verify_ssl=True,
- timeout=30.0,
- refresh_threshold=60,
- retry=None,
Create a Niwaki instance and authenticate immediately (sync).
Equivalent to entering
Niwaki(...)as a sync context manager but without thewithstatement — the same session construction and login path is used, so every constructor option (including retry) behaves identically.- Parameters:
host (str) – Base URL of the APIC.
username (str) – APIC username.
password (str) – APIC password.
verify_ssl (bool | str) – TLS verification —
True, a PEM CA bundle path, orFalse. Default:True.timeout (float) – HTTP timeout in seconds. Default: 30.
refresh_threshold (int) – Proactive refresh threshold in seconds. Default: 60.
retry (RetryConfig | None) – Custom retry policy. Defaults to 3 attempts with exponential back-off.
- Returns:
Authenticated
Niwakiinstance.- Raises:
LoginError – APIC rejected the credentials.
ConnectionError – APIC host is unreachable.
TimeoutError – Login request timed out.
TLSError – TLS certificate verification failed.
- Return type:
Example:
aci = Niwaki.connect( "https://sandboxapicdc.cisco.com", "admin", "ciscopsdt", verify_ssl=False, )
- close()[source]¶
Close the sync HTTP session and release network resources.
Called automatically on
__exit__. Safe to call explicitly when not usingNiwakias a context manager. Afterclose(), any further operation raisesAuthError(mirrorsAsyncNiwaki.close()).
- property retry: RetryConfig | None¶
Custom retry policy passed at construction time, or
Nonefor the default.- Returns:
The
RetryConfigoverride, orNonewhen the session default (3 attempts) is in use.
- property subscriptions: SubscriptionManager¶
Bulk introspection/management for this session’s object-subscriptions.
- Returns:
A
SubscriptionManagerover the active session.
Example:
with Niwaki(...) as aci: sub = aci.query(fvBD).subscribe() for info in aci.subscriptions.list(): print(info.path, info.is_stale) aci.subscriptions.close_all()
- property root: NiwakiNode[ManagedObject]¶
Entry point for the ACI object hierarchy.
Returns a
NiwakiNodeat DN"uni"— the root of all ACI objects.- Returns:
NiwakiNodewithdn = "uni".
Example:
bd = aci.root.tenant("prod").bd("web").read()
- node(dn, cls=<class 'niwaki.models.base.ManagedObject'>)[source]¶
Access a node by explicit DN.
- Parameters:
dn (str) – Full Distinguished Name (e.g.
"uni/tn-prod/BD-web").cls (type[T]) – ACI class hint. Defaults to
ManagedObject.
- Returns:
NiwakiNodescoped to the given DN.- Return type:
NiwakiNode[T]
Example:
bd = aci.node("uni/tn-prod/BD-web", fvBD).read()
- query(cls: type[T]) Query[T][source]¶
- query(cls: str) Query[ManagedObject]
Build a global class query for the entire ACI fabric.
Returns a
Querybuilder targeting every instance of cls across the fabric (/api/class/{cls}.json). Add filters, scope constraints, or response enrichment before executing.Also accepts a plain string class name for querying any of the ~15 000 ACI classes — including read-only operational and stats classes that are not in the generated set. Attributes on unregistered classes are accessible via
obj.model_extra["attr"]or directly asobj.attr_name(Pydanticextra="allow").- Parameters:
cls (type[T] | str) – ACI class type (e.g.
fvBD) or plain string class name (e.g."topSystem").- Returns:
Querytargeting the global class index.- Return type:
Query[T]
Example:
with Niwaki(...) as aci: # All tenants tenants = aci.query(fvTenant).fetch() # Filtered bds = aci.query(fvBD).where(arpFlood=True).fetch() # Scoped to a DN bds = aci.query(fvBD).under("uni/tn-prod").fetch() # Count only n = aci.query(fvBD).count() # Unregistered / read-only class nodes = aci.query("topSystem").naming_only().fetch()
- class niwaki.AsyncNiwaki(
- host=None,
- username=None,
- password=None,
- *,
- verify_ssl=True,
- timeout=30.0,
- refresh_threshold=60,
- max_concurrent=10,
- retry=None,
Bases:
objectAsync entry point for the ACI SDK.
Mirrors
Niwakifor async code. Use as an async context manager — authentication happens on__aenter__and the session is closed on__aexit__.- Parameters:
host (str | None) – Base URL of the APIC (e.g.
"https://sandboxapicdc.cisco.com"). Falls back toAPIC_HOSTenvironment variable if omitted.username (str | None) – APIC username. Falls back to
APIC_USERNAMEif omitted.password (str | None) – APIC password. Falls back to
APIC_PASSWORDif omitted.verify_ssl (bool | str) – TLS verification —
True(system CA store), a path to a PEM CA bundle (private/enterprise CA), orFalse(lab only). Default:True.timeout (float) – HTTP request timeout in seconds. Default: 30.
refresh_threshold (int) – Seconds before token expiry at which a proactive refresh is triggered. Default: 60.
max_concurrent (int) – Maximum simultaneous HTTP requests in flight. Default: 10.
retry (RetryConfig | None) – Custom retry policy. Defaults to 3 attempts with exponential back-off. Construct with
RetryConfig.
Example:
async with AsyncNiwaki("https://apic.example.com", "admin", "pass") as aci: tenants = await aci.query(fvTenant).fetch() bd = await aci.root.tenant("prod").bd("web").read() # Concurrent reads via gather() async with AsyncNiwaki("https://apic.example.com", "admin", "pass") as aci: tenants, bd = await aci.gather( aci.query(fvTenant).fetch(), aci.root.tenant("prod").bd("web").read(), )
- async close()[source]¶
Close the async HTTP session and release network resources.
Called automatically on
__aexit__. Safe to call explicitly when not usingAsyncNiwakias an async context manager.
- property retry: RetryConfig | None¶
Custom retry policy passed at construction time, or
Nonefor the default.- Returns:
The
RetryConfigoverride, orNonewhen the session default (3 attempts) is in use.
- property subscriptions: AsyncSubscriptionManager¶
Bulk introspection/management for this session’s object-subscriptions.
- Returns:
An
AsyncSubscriptionManagerover the active session.
Example:
async with AsyncNiwaki(...) as aci: sub = await aci.query(fvBD).subscribe() for info in aci.subscriptions.list(): print(info.path, info.is_stale) await aci.subscriptions.close_all()
- property root: AsyncNiwakiNode[ManagedObject]¶
Entry point for the ACI object hierarchy.
- Returns:
AsyncNiwakiNodeat DN"uni".
Example:
bd = await aci.root.tenant("prod").bd("web").read()
- node(dn, cls=<class 'niwaki.models.base.ManagedObject'>)[source]¶
Access a node by explicit DN.
- Parameters:
dn (str) – Full Distinguished Name (e.g.
"uni/tn-prod/BD-web").cls (type[T]) – ACI class hint. Defaults to
ManagedObject.
- Returns:
AsyncNiwakiNodescoped to the given DN.- Return type:
- query(cls: type[T]) AsyncQuery[T][source]¶
- query(cls: str) AsyncQuery[ManagedObject]
Build a global class query for the entire ACI fabric (async variant).
Mirrors
query()for async contexts. The accumulator methods are synchronous; only the execution methods (fetch,first,count,stream) are coroutines, which means they compose naturally withgather().- Parameters:
cls (type[T] | str) – ACI class type (e.g.
fvBD) or plain string class name.- Returns:
AsyncQuerytargeting the global class index.- Return type:
AsyncQuery[T]
Example:
async with AsyncNiwaki(...) as aci: # All tenants tenants = await aci.query(fvTenant).fetch() # Concurrent reads via gather() tenants, bds = await aci.gather( aci.query(fvTenant).fetch(), aci.root.tenant("prod").bd().fetch(), ) # Async streaming async for bd in aci.query(fvBD).stream(): await process(bd)
- async gather(*coros)[source]¶
Run multiple coroutines concurrently under a structured TaskGroup.
The APIC concurrency semaphore (
max_concurrent) is already applied at the session level, so each coroutine naturally respects the limit. On the first coroutine that raises,TaskGroupcancels the others and raises anExceptionGroup(Python 3.11+). Do not usegatherfor concurrent writes: a failure cancels the in-flight siblings, which can leave a second design partially applied.- Parameters:
*coros (Coroutine[Any, Any, Any]) – Coroutines to run concurrently (e.g. results of
.read(),aci.query(...).fetch(),config.push(aci)).- Returns:
Tuple of results in the same order as the input coroutines.
- Raises:
ExceptionGroup – If one or more coroutines raise. Remaining siblings are cancelled (
TaskGroupsemantics), not awaited.- Return type:
Example:
tenants, bd = await aci.gather( aci.query(fvTenant).fetch(), aci.root.tenant("prod").bd("web").read(), )
Nodes¶
- class niwaki.NiwakiNode(niwaki, dn, cls)[source]¶
Bases:
_JargonNavMixin,GenericA DN-scoped handle for observing a single ACI object (sync).
Created via
Niwaki.rootorNiwaki.node(). Navigate the ACI hierarchy withmo()or the vocabulary accessors — each call descends one level and computes the child DN automatically from the parent DN and the child’s RN. Terminal operations are read-side (read(),query()) plusdelete(); configuration goes throughniwaki.design.- Parameters:
- property dn: str¶
Full Distinguished Name of this node (read-only).
- Returns:
DN string, e.g.
"uni/tn-prod/BD-web".
Example:
node = aci.root.mo(fvTenant, name="prod").mo(fvBD, name="web") node.dn # → "uni/tn-prod/BD-web"
- property cls: type[T]¶
ACI class associated with this node.
- Returns:
The
ManagedObjectsubclass used to construct and deserialise objects at this DN.
- mo(cls, **naming_kwargs)[source]¶
Descend to a child node, computing its DN automatically.
Creates a temporary instance of
clspurely to derive the RN from_rn_format. The child DN isself.dn + "/" + child.rn.- Parameters:
cls (type[U]) – ACI class of the child object.
**naming_kwargs (Any) – Naming props required by
cls(e.g.name="web").
- Returns:
A new
NiwakiNodescoped to the child DN.- Raises:
ValidationError – If
naming_kwargsviolate the model constraints forcls.- Return type:
NiwakiNode[U]
Example:
aci.root .mo(fvTenant, name="prod") .mo(fvBD, name="web") .mo(fvSubnet, ip="10.0.0.1/24")
- read()[source]¶
Fetch the ACI object at this DN from the APIC.
- Returns:
Typed
ManagedObjectinstance.- Raises:
NotFoundError – The object does not exist on the APIC.
ForbiddenError – Insufficient privileges.
ServerError – APIC server-side error.
- Return type:
T
Example:
bd = aci.root.mo(fvTenant, name="prod").mo(fvBD, name="web").read() print(bd.unicast_routing)
- delete()[source]¶
Delete the ACI object at this DN.
- Raises:
NotFoundError – The object does not exist on the APIC.
ForbiddenError – Insufficient privileges.
ServerError – APIC server-side error.
Example:
aci.root.mo(fvTenant, name="prod").mo(fvBD, name="web").delete()
- query(cls: type[U]) Query[U][source]¶
- query(cls: str) Query[ManagedObject]
Build a query scoped to this node’s DN.
Returns all instances of cls that are descendants of this node, using the APIC
query-target=subtree&target-subtree-class=clsquery mode. Chain filter, scope, and enrichment methods before executing withfetch(),first(),count(), orstream().This is also the entry point for querying unregistered classes (the full APIC class catalogue of ~15 000 classes): pass a plain string class name and the result will be a
Query[ManagedObject]whose objects expose all APIC attributes viamodel_extra.- Parameters:
cls (type[U] | str) – ACI class type (e.g.
fvBD) or plain string class name (e.g."topSystem").- Returns:
Queryscoped to this node’s DN.- Return type:
Query[U]
Example:
# All BDs under tenant "prod" bds = aci.root.tenant("prod").query(fvBD).fetch() # Count subnets in a specific BD n = aci.root.tenant("prod").bd("web").query(fvSubnet).count() # Unregistered / read-only class nodes = aci.root.query("topSystem").naming_only().fetch()
- class niwaki.AsyncNiwakiNode(niwaki, dn, cls)[source]¶
Bases:
_JargonNavMixin,GenericA DN-scoped handle for observing a single ACI object (async).
Mirrors
NiwakiNodefor async contexts. Terminal operations (read(),delete()) are coroutines; configuration goes throughniwaki.design.- Parameters:
niwaki (AsyncNiwaki) – Parent
AsyncNiwakiinstance.dn (str) – Full Distinguished Name of this node.
cls (type[T]) – ACI class associated with this node. Used to deserialise reads.
- property dn: str¶
Full Distinguished Name of this node (read-only).
- Returns:
DN string, e.g.
"uni/tn-prod/BD-web".
- property cls: type[T]¶
ACI class associated with this node.
- Returns:
The
ManagedObjectsubclass used to construct and deserialise objects at this DN.
- mo(cls, **naming_kwargs)[source]¶
Descend to a child node, computing its DN automatically.
- Parameters:
cls (type[U]) – ACI class of the child object.
**naming_kwargs (Any) – Naming props required by
cls.
- Returns:
A new
AsyncNiwakiNodescoped to the child DN.- Raises:
ValidationError – If
naming_kwargsviolate model constraints.- Return type:
- async read()[source]¶
Fetch the ACI object at this DN from the APIC.
- Returns:
Typed
ManagedObjectinstance.- Raises:
NotFoundError – The object does not exist.
ForbiddenError – Insufficient privileges.
ServerError – APIC server-side error.
- Return type:
T
- async delete()[source]¶
Delete the ACI object at this DN.
- Raises:
NotFoundError – Object does not exist.
ForbiddenError – Insufficient privileges.
ServerError – APIC server-side error.
- query(cls: type[U]) AsyncQuery[U][source]¶
- query(cls: str) AsyncQuery[ManagedObject]
Build a query scoped to this node’s DN (async variant).
Mirrors
query()for async contexts. All accumulator methods are synchronous; only the execution methods (fetch,first,count,stream) are coroutines.- Parameters:
cls (type[U] | str) – ACI class type or plain string class name.
- Returns:
AsyncQueryscoped to this node’s DN.- Return type:
AsyncQuery[U]
Example:
bds = await aci.root.tenant("prod").query(fvBD).fetch() n = await aci.root.tenant("prod").bd("web").query(fvSubnet).count()
Subscription management¶
aci.subscriptions — bulk introspection/refresh/stop over every
subscription open on the session’s shared WebSocket; see
Subscribing to live changes.
- class niwaki.facade.SubscriptionManager(session)[source]¶
Bases:
objectBulk introspection/management for a session’s object-subscriptions (sync).
Reached via
subscriptions. Operates on whichever subscriptions are currently open on the session’s shared WebSocket — every method is a safe no-op (empty list, or nothing to do) until at least oneaci.query(...).subscribe()call has opened it.- list()[source]¶
List every subscription currently tracked, or
[]if none is open.- Returns:
One
SubscriptionInfoper tracked subscription —.is_staleflags one with at least one recent refresh failure.- Return type:
Example:
for info in aci.subscriptions.list(): print(info.path, info.consecutive_refresh_failures, info.is_stale)
- refresh_all()[source]¶
Force an immediate refresh of every tracked subscription, on demand.
A diagnostic tool, distinct from the automatic background refresh sweep — a failure here never triggers the automatic recovery escalation a missed scheduled refresh would.
- Returns:
The post-refresh snapshot of every subscription.
- Return type:
- close_all()[source]¶
Stop every tracked subscription — the shared socket itself stays open.
Every open
Subscription’s iterator ends with a plainStopIteration. Distinct from closing the wholeNiwakisession: a lateraci.query(...).subscribe()reuses the same still-open socket immediately, with no reconnect needed.
- class niwaki.facade.AsyncSubscriptionManager(session)[source]¶
Bases:
objectAsync counterpart of
SubscriptionManager. Reached viasubscriptions.- list()[source]¶
List every subscription currently tracked, or
[]if none is open.Synchronous even on the async facade — see
list_subscriptions().- Returns:
One
SubscriptionInfoper tracked subscription.- Return type:
Retry policy¶
Retries are configured on the client with RetryConfig
(documented with the transport layer that applies it).