DSDL Mapping Tutorial
Introduction
One of the functions implemented in
pyang is the mapping of
YANG data
models to
DSDL schemas –
RELAX NG,
Schematron and DSRL. The
resulting schemas may be used with off-the-shelf XML tools for
validating NETCONF datastores and PDUs and other related purposes.
The mapping procedure is described in
draft-ietf-netmod-dsdl-map.
This tutorial works with a very simple data model consisting of two
YANG modules. We will first show how to perform the DSDL mapping
procedure with the
yang2dsdl script that is a part of
pyang
distribution, and then experiment with validating configuration
datastore contents.
Finally, we will dissect the
yang2dsdl script and discuss other
possible setups and applications of the DSDL mapping procedure.
The Data Model
As an example, we use the YANG module
acme-system shown at the
bottom of
WebHome (see also
acme-system.yang). To make things
slightly more interesting, we
augment this module by adding three new
nodes to the entries of the "interface" list. This is accomplished by
the following module (see also
extra-interface-data.yang):
module extra-interface-data {
namespace "http://foo.example.com/extra-if-data";
prefix eid;
import acme-system {
prefix acme;
}
import ietf-inet-types {
prefix inet;
}
augment "/acme:system/acme:interface" {
leaf enabled {
type boolean;
default "false";
must ".='false' or ../ipv4-address and ../subnet-mask-length" {
error-message "IP address and mask must be configured " +
"for enabled interfaces.";
}
}
leaf ipv4-address {
type inet:ipv4-address;
}
leaf subnet-mask-length {
type uint8 {
range "0..32";
}
}
}
}
Our data model now defines a
compound document containing nodes in
the namespaces of both the contributing modules,
acme-system and
extra-interface-data.
Generating the Schemas
The DSDL schemas can be generated quite easily (at least on Linux and
Unix systems) from the two YANG modules by using the
yang2dsdl shell
script which is provided with the
pyang distribution. The details
about its usage can be found in the
manual page or by running
yang2dsdl -h
.
But before we start, we need to decide which target document type the
generated schemas are to address. Currently,
yang2dsdl supports the
following targets that are selected via the
-t
command line option:
- dstore
- raw datastore content;
- get-reply
- a complete NETCONF message containing a reply to
<get>
operation;
- getconf-reply
- a complete NETCONF message containing a reply to
<get-config>
operation;
- rpc
- An RPC request defined in the input YANG module(s);
- rpc-reply
- An RPC reply defined in the input YANG module(s);
- notif
- An event notification defined in the input YANG module(s).
Only the first three targets make sense in our case as the YANG
modules define neither RPC operations nor event
notifications. Moreover, there are no operational state data or
statistics in our modules, so the replies to
<get>
and
<get-config>
are bound to be identical.
Another detail to consider are the file names in which the output
schemas will be stored. The names have the following general form:
BASE-TARGET.EXT
The first part, BASE, can be chosen by the user while the other two
cannot. TARGET is always set to the selected target (see above) and
EXT is a file extension specific for each DSDL schema language –
rng
is used for RELAX NG,
sch
for Schematron and
dsrl
for DSRL.
If the BASE part isn't provided by the user, the script constructs a
default one, which is a concatenation of the names of all input YANG
modules connected with the underscore character
_
. The result in
our example –
acme-system_extra-interface-data
– would lead to
rather long file names. We therefore decide to specify a shorter BASE
part explicitly, say
aug-acme-system
.
All right, let's generate the DSDL schemas for the "dstore" target. We
needn't use the
-t
option here as "dstore" is the default:
$ yang2dsdl -b aug-acme-system acme-system.yang extra-interface-data.yang
== Generating RELAX NG schema './aug-acme-system-dstore.rng'
Done.
== Generating Schematron schema './aug-acme-system-dstore.sch'
Done.
== Generating DSRL schema './aug-acme-system-dstore.dsrl'
Done.
As indicated by the program output, the resulting DSDL schemas were
written to three files:
But wait, the script also created a fourth file, namely
aug-acme-system-gdefs.rng. This
is actually a part of the RELAX NG schema containing all global
definitions (mapped from YANG top-level groupings and typedefs). For
technical reasons, these definitions have to be included from an
external file.
An Instance Configuration Datastore
In order to be able to see the generated DSDL schemas in action, we
need to create an XML document containing, in our case, a "raw"
configuration datastore. If we have an appropriate schema-aware
editor, we can provide it with the RELAX NG schema (or Schematron as
well). An excellent choice is
GNU Emacs with James Clark's
nXML mode.
The following is a valid datastore content (see also
aug-acme-system-dstore.xml):
<?xml version="1.0" encoding="utf-8"?>
<system xmlns="http://acme.example.com/system"
xmlns:eid="http://foo.example.com/extra-if-data">
<host-name>katz</host-name>
<domain-search>acme.example.com foo.example.com</domain-search>
<interface>
<name>eth0</name>
<type>Ethernet</type>
<mtu>1500</mtu>
<eid:enabled>true</eid:enabled>
<eid:ipv4-address>192.0.2.1</eid:ipv4-address>
<eid:subnet-mask-length>24</eid:subnet-mask-length>
</interface>
<interface>
<name>eth1</name>
<mtu>1500</mtu>
<type>Ethernet</type>
</interface>
</system>
Emacs with
nXML mode is also a user-friendly RELAX NG
validator. For example, we can try to change the value of the
<eid:subnet-mask-length>
element to
42
, which violates a datatype
constraint – this value must be in the range between 0 and 32. As a
result, the wrong value is underlined in
Emacs and the status line
indicates that the edited XML document is invalid.
Validation
We can use the
yang2dsdl script for validating the above
datastore content (the
-s
flag instructs the script to use the
existing DSDL schemas, without it the schemas would be regenerated):
$ yang2dsdl -s -b aug-acme-system -v aug-acme-system-dstore.xml
== Using pre-generated schemas
== Validating grammar and datatypes ...
aug-acme-system-dstore.xml validates
== Adding default values... done.
== Validating semantic constraints ...
No errors found.
Sure enough, no errors were detected in the instance document. Now,
let's change the value of the
<eid:subnet-mask-length>
element to
42
again and re-run the same command:
$ yang2dsdl -s -b aug-acme-system -v aug-acme-system-dstore.xml
== Using pre-generated schemas
== Validating grammar and datatypes ...
Relax-NG validity error : Extra element subnet-mask-length in interleave
aug-acme-system-dstore.xml:12: element subnet-mask-length: Relax-NG validity error : Element interface failed to validate content
Relax-NG validity error : Extra element interface in interleave
aug-acme-system-dstore.xml:6: element interface: Relax-NG validity error : Element system failed to validate content
aug-acme-system-dstore.xml fails to validate
The error message is not particularly informative – it is a direct
output of the RELAX NG validator built in the
xmllint tool – but at least the
conclusion in the last line is correct.
Next, change the value of
<eid:subnet-mask-length>
back to
24
but
also introduce two new errors in the second
<interface>
entry:
- Change the value of
<name>
from eth1
to eth0
. As a result, both list entries have the same key.
- Add a new element:
<eid:enabled>true</eid:enabled>
This violates the constraint stated by the 'must' statement in the extra-interface-data module.
In this case,
nXML mode won't complain since the instance document
remains gramatically valid and all datatype constraints are satisfied
as well. The errors we deal with here are
semantical. So let's try
the validation with
yang2dsdl again:
$ yang2dsdl -s -b aug-acme-system -v aug-acme-system-dstore.xml
== Using pre-generated schemas
== Validating grammar and datatypes ...
aug-acme-system-dstore.xml validates
== Adding default values... done.
== Validating semantic constraints ...
--- Validity error at "/acme:system/acme:interface":
Duplicate key "acme:name"
--- Failed assert at "/acme:system/acme:interface/eid:enabled":
IP address and mask must be configured for enabled interfaces.
The error messages are now very clear, Schematron rocks!
Feel free to make any other modifications in the instance documents
and re-run the validation to see what happens.
Looking under the Hood
TBD.