-
Notifications
You must be signed in to change notification settings - Fork 2
yang schema
Pre-Alpha. This page describes behavior that may change.
Every plugin that has its own configuration ships a YANG schema. Ze parses the schema at plugin registration, uses it to drive the CLI prompts, the web UI forms, the REST API, and the MCP tools, and runs the validators on every commit. The plugin gets the parsed config delivered during stage 2 of startup, as a list of JSON-encoded sections.
This page covers how to author a schema for a plugin. The deeper reference material lives in the in-tree YANG schema guide.
You declare the schema in the Schema field of sdk.Registration, the struct you pass to p.Run().
p := sdk.NewWithConn("my-plugin", conn)
p.Run(ctx, sdk.Registration{
Schema: &sdk.SchemaDecl{
Module: "ze-my-plugin",
Namespace: "urn:ze:my-plugin",
YANGText: myPluginYANG,
Handlers: []string{"my-plugin"},
},
WantsConfig: []string{"my-plugin"},
})| Field | Purpose |
|---|---|
Module |
YANG module name. |
Namespace |
URI unique to this module. |
YANGText |
The full text of the YANG module. |
Handlers |
Config path prefixes this plugin handles. |
Internal plugins embed the YANG file at compile time with //go:embed. External plugins can load it from any source: a file, a constant, a network fetch.
import _ "embed"
//go:embed my-plugin.yang
var myPluginYANG stringmodule my-plugin {
namespace "urn:my-company:my-plugin";
prefix mp;
container my-plugin {
leaf enabled {
type boolean;
default true;
}
}
}That is enough for Ze to accept a my-plugin { enabled true; } block in a config file, validate it, and deliver the parsed JSON to the plugin in stage 2.
| YANG type | Go type | Notes |
|---|---|---|
string |
string |
Plain text, optionally with length or pattern constraints. |
boolean |
bool |
true or false. |
uint8, uint16, uint32, uint64
|
unsigned integers |
range restricts valid values. |
int8, int16, int32, int64
|
signed integers | Same. |
enumeration |
string (enum member name) | Fixed set of values. |
leafref |
the referenced type | Validated against another YANG leaf in the tree. |
Ze runs the schema validators on every commit. Use them. Do not defer validation to your handler code when the schema can catch the problem at commit time.
leaf port {
type uint16 {
range "1..65535";
}
}
leaf hold-time {
type uint16 {
range "0 | 3..65535";
}
}
leaf name {
type string {
length "1..64";
}
}
leaf ipv4-address {
type string {
pattern '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+';
}
}
leaf action {
type enumeration {
enum allow;
enum deny;
enum log;
}
}A container is a single named block with sub-fields. A list is a named list keyed by one or more leaves.
container settings {
leaf timeout { type uint32; }
leaf retries { type uint8; }
}
list endpoint {
key "name";
leaf name { type string; }
leaf url { type string; }
leaf enabled { type boolean; default true; }
}In the config file:
settings {
timeout 30;
retries 3;
}
endpoint api {
url "https://api.example.com";
}
endpoint backup {
url "https://backup.example.com";
enabled false;
}
YANG has a mandatory true flag for leaves that must be present. Ze also has a custom extension, ze:required, for leaves that must be present after inheritance resolves (the BGP subtree uses it for the remote IP, remote AS, and local AS of every peer). Use mandatory for leaves that must be in the literal config; use ze:required for leaves that must exist somewhere in the inheritance chain.
leaf required-field {
type string;
mandatory true;
}
leaf optional-field {
type uint32;
default 100;
}leafref ties one leaf's value to another leaf in the tree. Ze validates the reference at commit time and rejects configs where the referenced value does not exist.
list peer-group {
key "name";
leaf name { type string; }
}
leaf group {
type leafref {
path "/bgp/peer-group/name";
}
}- Use meaningful namespaces. Include your organisation or project prefix. Collisions are painful.
-
Write descriptions on every container and leaf. They appear in the CLI help, the web UI tooltips, and
ze schema show. - Set sensible defaults. Reduce the amount of config a user has to write to get something working.
- Validate in YANG first. Ranges, patterns, enums, lengths, leafrefs. Do not duplicate validation in handler code.
-
List your handler prefixes. The
Handlersfield inSchemaDecltells Ze which config paths your plugin handles. Without it, the plugin does not see the config sections.
module acme-monitor {
namespace "urn:acme:monitor";
prefix acme;
description "ACME endpoint monitoring plugin";
container acme-monitor {
description "Monitor configuration";
leaf endpoint {
type string;
mandatory true;
description "HTTPS endpoint to monitor";
}
leaf interval {
type uint32 {
range "10..3600";
}
default 60;
description "Check interval in seconds";
}
list alert {
key "name";
description "Alert destinations";
leaf name {
type string { length "1..64"; }
}
leaf email {
type string;
}
}
}
}And the plugin main:
package main
import (
"context"
_ "embed"
"log"
"os"
"os/signal"
"codeberg.org/thomas-mangin/ze/pkg/plugin/sdk"
)
//go:embed acme-monitor.yang
var acmeMonitorYANG string
func main() {
p, err := sdk.NewFromEnv("acme-monitor")
if err != nil {
log.Fatal(err)
}
p.OnConfigure(func(sections []sdk.ConfigSection) error {
for _, s := range sections {
log.Printf("config root=%s data=%s", s.Root, s.Data)
}
return nil
})
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
err = p.Run(ctx, sdk.Registration{
Schema: &sdk.SchemaDecl{
Module: "acme-monitor",
Namespace: "urn:acme:monitor",
YANGText: acmeMonitorYANG,
Handlers: []string{"acme-monitor"},
},
WantsConfig: []string{"acme-monitor"},
})
if err != nil {
log.Fatal(err)
}
}- Handlers for how the parsed config reaches your plugin.
- Go plugins for the SDK surface.
- In-tree YANG schema guide for the long version.
Adapted from main/docs/plugin-development/schema.md.
Unreviewed draft. This wiki was authored in bulk and has not been reviewed. File corrections on the issue tracker.
- Overview
- YANG Model
- Editor Workflow
- Archive and Rollback
- System
- Interfaces
- VRRP
- BFD
- FIB
- OSPF
- IS-IS
- MPLS / LDP / RSVP-TE
- RSVP-TE
- SRv6
- Static Routes
- Policy Routing
- Firewall
- Traffic Control
- Class of Service
- L2TP/PPP
- PPPoE
- VPP Data Plane
- RPKI
- IPsec VPN
- TACACS+ AAA
- RADIUS AAA
- AS112 DNS
- Authorization
- Fleet
- BGP
- Starting and Stopping
- Show Commands
- Monitoring
- Flow Export
- DDoS Mitigation
- Anomaly Detection
- Health Checks
- Audit Trail
- Production Diagnostics
- Logging
- Operational Reports
- Healthcheck
- Self-Update
- Zero-Touch Provisioning
- MRT Analysis
- Upgrade and Restart
- Storage
- Policy
- Core
- Resilience
- Validation
- Capabilities
- Address Families
- Protocol
- Subsystems
- Infrastructure
- Route Server at an IXP
- Transit Edge with RPKI
- Public Looking Glass
- ExaBGP Migration Walkthrough
- FlowSpec Injection
- Chaos-Tested Peering
- AS Path Topology