# How Resource Backings Manage Storage and Network Resources in Avocado-VT

> Discover how Resource Backings in Avocado VT manage storage and network resources by isolating virtualization assets and orchestrating pool connections for efficient testing.

- Repository: [avocado/avocado-vt](https://github.com/avocado-framework/avocado-vt)
- Tags: internals
- Published: 2026-02-25

---

**Resource backings in the Avocado-VT framework isolate virtualization assets from infrastructure specifics by orchestrating pool connections for shared resources and node-local backing instances for concrete operations, exposing a unified command API through the `ResourceBackingManager` singleton.**

The `avocado-framework/avocado-vt` virtualization testing framework delegates the handling of storage volumes and network interfaces to a specialized resource-backing subsystem. This architecture allows worker nodes to provision local files, NFS mounts, and Linux bridge ports through a consistent interface while the controller node manages logical resource requirements. By decoupling pool connectivity from resource lifecycle operations, the framework supports diverse backend technologies without modifying high-level test logic.

## Architecture of the Resource Backing Subsystem

The resource-backing implementation follows a four-layer design that separates connection management, resource operations, orchestration, and class discovery.

| Layer | Core Abstraction | Key Implementation Files |
|-------|------------------|--------------------------|
| **Pool Connection** | `ResourcePoolConnection` (abstract) | [`resource_backings/pool_connection.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/pool_connection.py) |
| **Resource Backing** | `ResourceBacking` (abstract) | [`resource_backings/backing.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/backing.py) |
| **Orchestration** | `_ResourceBackingManager` (singleton `rb_mgr`) | [`resource_backing_manager.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backing_manager.py) |
| **Factory Registry** | Type-to-class mapping functions | [`resource_backings/__init__.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/__init__.py) |

### ResourcePoolConnection: Linking Workers to Shared Pools

The `ResourcePoolConnection` abstract base class in [`resource_backings/pool_connection.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/pool_connection.py) establishes the link between a worker node and a shared resource pool. Concrete implementations include `DirPoolConnection` for local filesystem directories, `NfsPoolConnection` for remote NFS exports, and `TapNetworkConnection` for Linux bridge networking. Each connection class implements an `open()` method that prepares the pool for use—such as mounting an NFS share or validating a bridge configuration—and maintains a `POOL_TYPE` identifier for factory registration.

### ResourceBacking: Node-Local Resource Operations

Defined in [`resource_backings/backing.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/backing.py), the `ResourceBacking` abstract class represents the node-local object that executes real operations on a single resource instance. Subclasses like `DirVolumeBacking`, `NfsVolumeBacking`, and `TapPortBacking` implement the abstract methods `allocate_resource`, `release_resource`, `clone_resource`, `sync_resource_info`, and `is_resource_allocated`. Each backing maintains a `_handlers` dictionary mapping commands (`"allocate"`, `"release"`, `"sync"`) to their implementation methods, ensuring a uniform API regardless of whether the resource is a storage volume or network port.

### ResourceBackingManager: Orchestration and State Persistence

The `_ResourceBackingManager` class, instantiated as the singleton `rb_mgr` in [`resource_backing_manager.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backing_manager.py), serves as the central orchestrator. It maintains two critical registries: `self._pool_connections` (mapping pool UUIDs to connection objects) and `self._backings` (mapping backing UUIDs to resource instances). The manager persists its state to `BACKING_MGR_ENV_FILENAME`, enabling worker nodes to reload existing pool connections after a restart via the internal `_load()` method. It exposes a thin RPC-style API—including `create_pool_connection`, `create_backing_object`, and `update_resource_by_backing`—that the controller node invokes to drive resource lifecycles.

### Factory Registry: Dynamic Class Resolution

The [`resource_backings/__init__.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/__init__.py) file implements a factory registry that decouples type strings from class implementations. The `get_pool_connection_class(pool_type)` function maps pool type strings (e.g., `"filesystem"`, `"nfs"`, `"linux_bridge"`) to their respective connection classes. Similarly, `get_resource_backing_class(pool_type, resource_type)` resolves the concrete backing class based on both the pool technology and resource category. This registration pattern enables the dynamic instantiation of the correct objects without hardcoding class references in the manager.

## Resource Lifecycle Management

The `ResourceBackingManager` coordinates the complete lifecycle of virtualization resources through five distinct phases, translating high-level controller commands into concrete node operations.

### 1. Pool Connection Creation

The controller initiates resource availability by submitting a pool configuration containing a type, UUID, and specifications. The manager looks up the connection class using `get_pool_connection_class(pool_type)`, instantiates it, and invokes `open()`.

```python
from avocado_vt.agent.managers.resource_backings.resource_backing_manager import rb_mgr

fs_pool_cfg = {
    "meta": {"uuid": "pool-001", "type": "filesystem"},
    "spec": {"path": "test_data/fs_root"}
}

rc, out = rb_mgr.create_pool_connection(fs_pool_cfg)

```

The connection object is stored in `self._pool_connections` keyed by its UUID, and the state is serialized to `BACKING_MGR_ENV_FILENAME`.

### 2. Backing Object Instantiation

When binding a specific resource to a pool, the manager retrieves the active pool connection and resolves the backing class via `get_resource_backing_class()`. It then creates the backing instance and registers it in `self._backings` with a generated UUID.

```python
vol_cfg = {
    "meta": {"uuid": "vol-123", "type": "volume", "pool": "pool-001"},
    "spec": {"size": "1G"}
}

rc, out = rb_mgr.create_backing_object(vol_cfg)
backing_id = out["out"]["backing"]

```

### 3. Resource Allocation

The test triggers resource materialization by sending an allocate command. The manager forwards this to the backing's handler, which executes technology-specific provisioning—such as creating a file in a directory or attaching a TAP interface to a bridge.

```python
rc, out = rb_mgr.update_resource_by_backing(backing_id, "allocate", {})

```

For `TapPortBacking`, this invokes `tap.open_tap()` and `bridge.add_to_bridge()`, while `DirVolumeBacking` creates a sparse file of the requested size in the pool's root directory.

### 4. State Synchronization and Querying

Workers or controllers can query current resource attributes through the manager's `get_resource_info_by_backing()` method. Setting `verbose=True` includes the parent pool configuration in the response.

```python
info = rb_mgr.get_resource_info_by_backing(backing_id, verbose=True)

```

The backing's `sync_resource_info()` method refreshes metadata such as allocation status, file paths, or interface names, ensuring the returned state reflects the actual system condition.

### 5. Teardown and Cleanup

Resource cleanup follows the reverse sequence. `destroy_backing_object(backing_id)` removes the specific resource backing after releasing its assets, while `destroy_pool_connection(pool_id)` closes the pool link and removes it from the persistent state store.

```python
rb_mgr.destroy_backing_object(backing_id)
rb_mgr.destroy_pool_connection("pool-001")

```

## Storage and Network Backing Implementations

The backing architecture accommodates diverse infrastructure technologies through specialized subclasses that inherit common behaviors from `ResourceBacking`.

### Filesystem and NFS Storage Backings

**`DirVolumeBacking`** (paired with `DirPoolConnection`) manages file-based volumes within a local directory. The pool connection's `open()` method initializes the root directory (`init_dir`), while the backing resolves URIs relative to this root during allocation. **`NfsVolumeBacking`** operates identically but on an NFS mount point established by `NfsPoolConnection`, allowing tests to use remote storage transparently.

### TAP Network Backings

**`TapPortBacking`** (using `TapNetworkConnection` with `POOL_TYPE="linux_bridge"`) handles virtual network interfaces. The connection stores bridge metadata, while the backing's `allocate_resource()` creates the TAP device, attaches it to the specified bridge, and stores the file descriptor and interface name. The `release_resource()` method detaches the interface and brings it down, ensuring network isolation between tests.

## Practical Implementation Examples

### Creating a Filesystem Pool and Volume

```python
from avocado_vt.agent.managers.resource_backings.resource_backing_manager import rb_mgr

# Configure and open a local filesystem pool

fs_pool_cfg = {
    "meta": {"uuid": "pool-001", "type": "filesystem"},
    "spec": {"path": "test_data/fs_root"}
}
rc, out = rb_mgr.create_pool_connection(fs_pool_cfg)
assert rc == 0, f"Pool creation failed: {out}"

# Create a volume backing in the pool

vol_cfg = {
    "meta": {"uuid": "vol-123", "type": "volume", "pool": "pool-001"},
    "spec": {"size": "1G"}
}
rc, out = rb_mgr.create_backing_object(vol_cfg)
assert rc == 0, f"Backing creation failed: {out}"
backing_id = out["out"]["backing"]

# Allocate the storage (creates the file)

rc, out = rb_mgr.update_resource_by_backing(backing_id, "allocate", {})
print(out["out"]["spec"])  # Contains path and allocation status

```

### Provisioning a TAP Network Port

```python

# Configure a Linux bridge pool

bridge_cfg = {
    "meta": {"uuid": "net-pool-01", "type": "linux_bridge"},
    "spec": {"bridge_name": "br0"}
}
rb_mgr.create_pool_connection(bridge_cfg)

# Create a TAP port backing

tap_cfg = {
    "meta": {"uuid": "tap-001", "type": "tap", "pool": "net-pool-01"},
    "spec": {}
}
rc, out = rb_mgr.create_backing_object(tap_cfg)
tap_backing_id = out["out"]["backing"]

# Allocate creates the interface and attaches to bridge

rc, out = rb_mgr.update_resource_by_backing(tap_backing_id, "allocate", {})
print(out["out"]["spec"]["ifname"])  # e.g., "tap_abcd1234"

```

### Querying Resource State

```python

# Get verbose info including pool configuration

info = rb_mgr.get_resource_info_by_backing(tap_backing_id, verbose=True)
print(info["meta"]["allocated"])  # True

print(info["spec"]["ifname"])     # Interface name

```

### Cleanup Operations

```python

# Release specific resources

rb_mgr.destroy_backing_object(tap_backing_id)
rb_mgr.destroy_backing_object(backing_id)

# Close pool connections

rb_mgr.destroy_pool_connection("net-pool-01")
rb_mgr.destroy_pool_connection("pool-001")

```

## Summary

- **Resource backings** abstract virtualization assets into node-local objects that implement concrete create, release, and sync operations.
- The **`ResourceBackingManager`** singleton orchestrates pool connections and backings while persisting state to `BACKING_MGR_ENV_FILENAME` for recovery.
- **Factory registries** in [`resource_backings/__init__.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/__init__.py) enable dynamic instantiation of connection and backing classes based on type strings.
- Storage resources use **volume backings** (`DirVolumeBacking`, `NfsVolumeBacking`) that manage files within pool-specific directories.
- Network resources use **port backings** (`TapPortBacking`) that manipulate system network interfaces and bridge memberships.
- The command-handler pattern (`_handlers` dictionary) provides a consistent RPC-style API for allocate, release, and sync operations across all resource types.

## Frequently Asked Questions

### What is the difference between a pool connection and a resource backing?

A **pool connection** (`ResourcePoolConnection` subclass) establishes and maintains the link to a shared resource pool—such as mounting an NFS export or referencing a Linux bridge—while a **resource backing** (`ResourceBacking` subclass) performs node-local operations on individual instances within that pool, such as creating a specific volume file or configuring a TAP interface. The connection manages the "where" (the pool), while the backing manages the "what" (the specific resource).

### How does Avocado-VT persist resource state across worker restarts?

The `ResourceBackingManager` serializes the internal registries of pool connections and backing objects to a file defined by `BACKING_MGR_ENV_FILENAME` whenever state changes occur. Upon initialization, the manager calls its internal `_load()` method to deserialize this state, allowing workers that restart or run collocated controllers to recover existing pool connections without reconfiguration.

### Can a single worker node manage multiple pool types simultaneously?

Yes. The `ResourceBackingManager` stores pool connections in the `self._pool_connections` dictionary keyed by UUID, allowing simultaneous connections to filesystem directories, NFS shares, and Linux bridges. Each backing object references its parent pool via the pool UUID, enabling heterogeneous resource allocation from a single worker.

### How do I implement a custom resource backing for a new storage type?

To add support for a new storage technology, create a subclass of `ResourcePoolConnection` implementing `open()` and other lifecycle methods, and a subclass of `ResourceBacking` implementing the abstract methods `allocate_resource`, `release_resource`, `clone_resource`, `sync_resource_info`, and `is_resource_allocated`. Register both classes in [`resource_backings/__init__.py`](https://github.com/avocado-framework/avocado-vt/blob/main/resource_backings/__init__.py) using the factory functions `get_pool_connection_class()` and `get_resource_backing_class()` to map your custom type strings to these implementations.