Skip to content

Provider contract

F-Layer providers translate cloud-specific authentication and resource observations into an explicit, provider-neutral boundary. The first implementation supports read-only Yandex Cloud discovery. Lifecycle creation, mutation, ownership adoption, rollback and destruction remain issue #20 work.

Implemented interface

Import the generic boundary from flayer.providers.contracts and the first adapter from flayer.providers.yandex.

Public API Behavior
CloudProvider.Identity Provider ID, explicit resource scope and non-secret authentication source
CloudProvider.Capabilities Implemented inventory and lookup operations, independent of account permissions
CheckAvailability() Local CLI execution probe; authentication remains unknown
CheckAuthentication() Read-access probe to the configured folder through existing CLI credentials
ListResources(kind) Sorted, validated inventory for one supported resource kind
GetResource(reference) Lookup by resource ID with reference and returned-scope validation
DiscoverInventory() Inventory across every supported kind, or a failure without partial results

A ResourceReference binds provider ID, scope ID, resource kind and resource ID. A ProviderResource contains that reference, name, vendor status, optional zone, immutable ownership labels and public IPv4 endpoints. Unknown state is explicitly UNKNOWN. Raw provider JSON, instance metadata and credentials never become resource fields.

Supported ResourceKind values are INSTANCE, DISK, NETWORK, SUBNET, ADDRESS and SECURITY_GROUP. Results are sorted by resource ID within each kind; full inventory follows enum order. Listing and lookup do not assert resource ownership. HasLabels() is a comparison helper requiring non-empty matching labels; future mutation authorization must define its complete policy separately.

Explicit authentication and scope

YandexCloudSettings requires a folder ID. There is no fallback to a profile's default folder. Settings also accept a profile name, CLI executable, bounded command timeout and inventory limit. They contain no token, key, credential file or local infrastructure assumption.

The adapter uses the CLI's existing authentication mechanism. It does not initialize profiles, read credential files, export tokens, call iam create-token or modify authentication settings. CheckAuthentication() verifies access to the selected folder; failure can indicate invalid credentials, insufficient permission or unavailable infrastructure. It does not claim that every resource-kind permission is granted.

Every cloud command specifies --profile, --folder-id, --format json, --no-browser and --retry 0. SubprocessCommandRunner uses an argument vector, shell=False, closed stdin and an explicit timeout. Construction, identity and capability inspection have no side effects. Availability executes only yc --version.

The CLI resolves IDs globally across accessible folders. The adapter therefore validates every returned resource's folder_id and rejects mismatched provider/scope references before executing lookup. A successful vendor command alone is insufficient scope evidence.

Completeness and failure behavior

CLI list operations have a finite limit. The adapter requests an explicit limit, defaults to 10,000 resources per kind and rejects a response at or above that limit as INCOMPLETE_INVENTORY. This conservative rule can reject an exactly-full but complete response; increasing the configured limit within its bounded range resolves that ambiguity. Future pagination may replace this rule without changing callers' completeness requirement.

Malformed JSON, unexpected response structure, invalid resource IDs, duplicate IDs, malformed endpoints and unverified scope fail closed. One failed kind aborts DiscoverInventory() without returning a partial snapshot. Discovery is not an atomic cloud snapshot: resources may change between read operations.

ProviderError exposes a stable ProviderErrorCode, operation name and retry recommendation. Timeouts and throttling are retryable; automatic retry is not implemented. Known CLI markers map to authentication, permission, not-found, timeout, throttling and conflict categories; other nonzero exits become COMMAND_FAILED.

Vendor stdout/stderr are captured transiently to parse successful JSON or classify failures. They never appear in error messages. Subprocess and JSON exception chains are suppressed. CommandResult omits stdout/stderr from its representation. Returned names and labels are observed public resource fields; infrastructure owners must not place credentials in those fields.

Example

from flayer.providers.contracts import ResourceKind
from flayer.providers.yandex import YandexCloudProvider, YandexCloudSettings

provider = YandexCloudProvider(
    YandexCloudSettings(folder_id="example-folder", profile="example")
)

# These calls access the selected account; construction alone does not.
status = provider.CheckAuthentication()

if status.authenticated:
    instances = provider.ListResources(ResourceKind.INSTANCE)

For deterministic tests, inject a CommandRunner whose Run(command, timeout) returns CommandResult. Unit tests use synthetic resource IDs and documentation IP addresses. No tests invoke the CLI, read credentials or access real cloud resources.

Design and validation

ADR 0002 records the dependency and authorization decisions. The adapter adapts A-VPN's folder-scoped Compute/VPC discovery and label-based ownership comparison while separating them from deployment profiles and lifecycle mutation.

Official references:

Repository source