perimeta adapter

Features

The perimeta module manages configuration on Metaswitch / Microsoft Perimeta Session Border Controllers (SBCs) through the device’s HTTPS configuration REST API (https://<device>/config/V<api_version>/). It exposes the SBC’s configuration tree as Inmanta resources: accounts, SIP/media adjacencies, signaling and media realm groups, service interfaces, codec lists, TLS settings, routing, IPsec peers and many more. Each managed resource maps one-to-one onto an API resource, and the handler performs CRUD by issuing GET/PUT/DELETE against that resource’s URI. Unset/null attributes are left untouched on the device.

The bulk of the model and its Python types are code-generated from an RDF schema of the device’s API (under schemas/) via the inmanta-perimeta-generator tool. Because the Perimeta API has no “replace whole list” operation and manages every collection member independently, the module also ships a guard mechanism (perimeta::guard::ListGuard): a guard owns a collection URI and a set of managed_items, enumerates the collection’s actual members and prunes any member not present in the model. Resources additionally support a report_only flag that reports drift as non-compliant instead of mutating the device.

Api configuration

Connection is described by two entities:

perimeta::PerimetaDevice — the SBC connection target:

Attribute

Description

address

Device IP where the API is reachable

port

API port (default 443)

api_version

API version being configured, e.g. 5.5.20; used to build the /config/V<v>/ URL

agent_name

Inmanta agent name

verify

Whether to verify the SBC’s TLS server certificate (default true)

credentials

Relation to a PerimetaCredentials object

perimeta::PerimetaCredentials — API credentials:

Attribute

Description

client_certificate_path

Path to the client certificate (PEM)

private_key_path

Path to the RSA private key (PEM)

Authentication is mutual TLS plus request signing (no username/password). The handler uses the client certificate and private key for the mTLS handshake, then signs each request: it builds a token from the HTTP method, URL path, selected headers and body, signs it with RSA PKCS1v15 / SHA256 and puts the base64 signature in the Authorization header.

:bulb: client_certificate_path and private_key_path point to files that must be readable by the agent. No config files are read by the module at runtime.

Environment variables

The handler reads the following environment variables from the agent process:

Variable

Default

Description

PERIMETA_REQUEST_TIMEOUT

5

Connect/read timeout in seconds for a single Perimeta API request

Raise PERIMETA_REQUEST_TIMEOUT when the SBC is slow to answer write requests: a read timeout aborts the deploy of that resource, since the request may already have been processed by the device and is therefore never replayed.

Usage example

The example connects to an SBC over mutual TLS, configures an account with a limit and a SIP adjacency linked to it.

import perimeta
import perimeta::account as account
import perimeta::adjacency as adjacency
import perimeta::sip_message_manipulation as sip_message_manipulation

# Connect to the SBC (mutual TLS + request signing)
device = perimeta::PerimetaDevice(
    address="192.0.2.10",
    port=443,
    agent_name="192.0.2.10",
    api_version="5.5.20",
    verify=false,
    credentials=perimeta::PerimetaCredentials(
        client_certificate_path="/path/to/perimeta_sbc.cert",
        private_key_path="/path/to/perimeta_sbc.pem",
    ),
)

# Configure an account with a limit
acct = account::Account(
    device=device,
    account="ci-myaccount",
    account_limits=[
        account::AccountLimits(
            direction="as-source",
            call_appearances=42,
            call_appearances_use_default=false,
            call_setup_rate_max_sustain="manual",
            call_setup_rate_max_sustain_value=43,
            call_setup_rate_max_sustain_units="per-second",
        ),
    ],
)

# Configure a SIP adjacency linked to that account
adjacency::Sip(
    adjacency_name="ci-adjacency",
    device=device,
    service_address="ci-my-service-address",
    description="SIP created by CI",
    account=acct,
    error_profile=sip_message_manipulation::ErrorProfileUnmanaged(
        device=device,
        profile_name="ci-default-error-profile",
    ),
    p_charging_vector="ensure-present",
)

Each generated API resource comes as an <X>Identity / <X> (managed) / <X>Unmanaged triplet. Use the *Unmanaged variant (e.g. ErrorProfileUnmanaged above) to reference an API object the model does not own. To prune stray members from a collection, use perimeta::guard::ListGuard(device=device, collection_uri="...", managed_items=[...]).

Main entities

Core / hand-written entities:

  • perimeta::PerimetaDevice — SBC connection target.

  • perimeta::PerimetaCredentials — mTLS client-cert + RSA private-key paths.

  • perimeta::PerimetaApiObject — base for any API resource (_uri, _config, device).

  • perimeta::guard::ListGuard — prunes unmanaged members from a guarded collection.

The remaining entities are generated (hundreds across ~34 sub-modules), including for example:

  • account::Account (+ AccountLimits, account::TrafficGroup) — accounts and their call/traffic limits.

  • adjacency::Sip (+ nested SIP limit/policy/interop entities) — SIP adjacencies.

  • signaling::Signaling — signaling configuration.

  • media_realm_group::MediaRealmGroup — media realm groups.

  • service_interface::ServiceInterface (+ Ipv4, Ipv6, …) — service interfaces and IP addressing.

  • address_group::AddressGroup / address_group::IpAddress — address groups and members.

  • call_policy_set::CallPolicySet — call policy sets.

Further sub-modules cover codec_list, custom_codec, qos, routing, tunnel/inbound_tunnel, ipsec_peer, ip_access_control, interop_profile/interop_defaults, peer_group_sip, TLS settings, certificate stores, SIP signing/verification services, push notifications, diagnostics and more.