PY-SIL Code Generation
The py-sil-gen.py plugin for pyang library can be used to generate PY-SIL code-stub files for the netconfd-pro server.
pyang is a YANG validator, code generator, and transformation tool written in python. It can be used to validate YANG modules for correctness, to transform YANG modules into other formats, and to write plugins to generate code from the modules.
Currently generation of EDIT3 ,GET2, RPC, ACTION and NOTIFICATION callbacks are supported.
Usage Requirements
Minimum python version is 3.8.10
Minimum pyang version 2.6.0
pyang
python library should be installed, it can be done using following command:
> pip install pyang
When server is built with WITH_PY_SIL option, plugin will be installed into pyang library plugins directory.
Usage
pyang [--plugindir] [--libsavedir] [--bundle] [--deviation-module] [--path] [-f py-sil] file...
Only options required for PY-SIL code generation is provided above. Refer to pyang documentation for the full options reference.
Options
--plugindir
plugindirSpecify the directory containing py-sil-gen.py plugin. By default, installation process will try to install it into pyang plugins directory.
--libsavedir
directorySpecify the directory for saving generated PY-SIL code.
--bundle
bundlenameSpecify the bundle name to be generated if you would like to combine modules in bundle.
--deviation-module
This option is used to specify a deviation module. This option can be given multiple times.
--path
pathPath is a colon (:) separated list of directories to search for imported modules. This option may be given multiple times.
-f
py-silSpecify the output format as PY-SIL code.
file...
One or more file parameters may be given on the command line. They denote either YANG modules to be processed.
Usage Examples
To generate stub PY-SIL code for a single YANG file:
> pyang -f py-sil mymod.yang
To generate stub PY-SIL code using bundles:
> pyang -f py-sil --bundle mybundle mymod1.yang mymod2.yang mymod3.yang
To generate PY-SIL code for a single YANG file and apply deviations from another file:
> pyang -f py-sil --deviation-module mymod-devs.yang mymod.yang
Example of PY-SIL Code Generated by Plugin
Example below is generated with following command for toaster.yang module:
> pyang -f py-sil toaster.yang
Following file structure will be generated:
toaster/
|-- u_toaster.py
|-- y_toaster.py
Refer to PY-SIL Tutorial for more details on how to use this PY-SIL code.
Module toaster.yang
module toaster {
namespace "http://netconfcentral.org/ns/toaster";
prefix "toast";
organization
"Netconf Central";
contact
"Andy Bierman <[email protected]>";
description
"YANG version of the TOASTER-MIB.
Copyright (c) 2009 Andy Bierman and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the BSD 3-Clause License
http://opensource.org/licenses/BSD-3-Clause";
revision 2009-11-20 {
description "Toaster module in progress.";
}
identity toast-type {
description
"Base for all bread types supported by the toaster.
New bread types not listed here nay be added in the
future.";
}
identity white-bread {
description
"White bread.";
base toast:toast-type;
}
identity wheat-bread {
description
"Wheat bread.";
base toast-type;
}
identity wonder-bread {
description
"Wonder bread.";
base toast-type;
}
identity frozen-waffle {
description
"Frozen waffle.";
base toast-type;
}
identity frozen-bagel {
description
"Frozen bagel.";
base toast-type;
}
identity hash-brown {
description
"Hash browned potatos.";
base toast-type;
}
typedef DisplayString {
description
"YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
reference "RFC 2579, section 2.";
type string {
length "0 .. 255";
}
}
container toaster {
presence
"Indicates the toaster service is available";
description
"Top-level container for all toaster database objects.";
leaf toasterManufacturer {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's manufacturer. For instance,
Microsoft Toaster.";
}
leaf toasterModelNumber {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's model. For instance,
Radiant Automatic.";
}
leaf toasterStatus {
type enumeration {
enum up {
value 1;
description
"The toaster knob position is up.
No toast is being made now.";
}
enum down {
value 2;
description
"The toaster knob position is down.
Toast is being made now.";
}
}
config false;
mandatory true;
description
"This variable indicates the current state of
the toaster.";
}
}
rpc make-toast {
description
"Make some toast.
The toastDone notification will be sent when
the toast is finished.
An 'in-use' error will be returned if toast
is already being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.";
input {
leaf toasterDoneness {
type uint32 {
range "1 .. 10";
}
default 5;
description
"This variable controls how well-done is the
ensuing toast. It should be on a scale of 1 to 10.
Toast made at 10 generally is considered unfit
for human consumption; toast made at 1 is warmed
lightly.";
}
leaf toasterToastType {
type identityref {
base toast:toast-type;
}
default toast:wheat-bread;
description
"This variable informs the toaster of the type of
material that is being toasted. The toaster
uses this information, combined with
toasterDoneness, to compute for how
long the material must be toasted to achieve
the required doneness.";
}
}
}
rpc cancel-toast {
description
"Stop making toast, if any is being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.";
}
notification toastDone {
description
"Indicates that the toast in progress has completed.";
leaf toastStatus {
description
"Indicates the final toast status";
type enumeration {
enum done {
description
"The toast is done.";
}
enum cancelled {
description
"The toast was cancelled.";
}
enum error {
description
"The toaster service was disabled or
the toaster is broken.";
}
}
}
}
/*************************************************************
Original TOASTER-MIB
TOASTER-MIB DEFINITIONS ::= BEGIN
IMPORTS
enterprises
FROM RFC1155-SMI
OBJECT-TYPE
FROM RFC-1212
DisplayString
FROM RFC-1213;
epilogue OBJECT IDENTIFIER ::= {enterprises 12}
toaster OBJECT IDENTIFIER ::= {epilogue 2}
toasterManufacturer OBJECT-TYPE
SYNTAX DisplayString
ACCESS read-only
STATUS mandatory
DESCRIPTION
"The name of the toaster's manufacturer. For instance,
Microsoft Toaster."
::= {toaster 1}
toasterModelNumber OBJECT-TYPE
SYNTAX DisplayString
ACCESS read-only
STATUS mandatory
DESCRIPTION
"The name of the toaster's model. For instance,
Radiant Automatic."
::= {toaster 2}
toasterControl OBJECT-TYPE
SYNTAX INTEGER {up (1), down (2)}
ACCESS read-write
STATUS mandatory
DESCRIPTION
"This variable controls the current state of the toaster.
To begin toasting, set it to down (2). To abort toasting
(perhaps in the event of an emergency), set it to up (2)."
::= {toaster 3}
toasterDoneness OBJECT-TYPE
SYNTAX INTEGER (1..10)
ACCESS read-write
STATUS mandatory
DESCRIPTION
"This variable controls how well-done is the
ensuing toast. It should be on a scale of 1 to 10.
Toast made at 10 generally is considered unfit
for human consumption; toast made at 1 is warmed
lightly."
::= {toaster 4}
toasterToastType OBJECT-TYPE
SYNTAX INTEGER {
white-bread (1),
wheat-bread (2),
wonder-bread (3),
frozen-waffle (4),
frozen-bagel (5),
hash-brown (6),
other (7)
}
ACCESS read-write
STATUS mandatory
DESCRIPTION
"This variable informs the toaster of the type of
material that is being toasted. The toaster
uses this information, combined with
toasterToastDoneness, to compute for how
long the material must be toasted to achieve
the required doneness."
::= {toaster 5}
END
*************************************************************/
}
u_toaster.py
"""
* Copyright (c) 2008 - 2012, Andy Bierman, All Rights Reserved.
* Copyright (c) 2012 - 2024, YumaWorks, Inc., All Rights Reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*** Generated by py-sil plugin (pyang)
User PY-SIL module
module toaster
revision 2009-11-20
prefix toast
namespace http://netconfcentral.org/ns/toaster
Created: 2024-05-01T00:28:53Z
Online Developer Manual:
https://docs.yumaworks.com/en/latest/dev/index.html
CLI parameters: -f py-sil toaster.yang
"""
from pysil.module import (
STATUS_T,
GETCB_MODE_T,
SILCbGet,
SILCbInvoke,
SILCbValidate,
OP_EDITOP_T,
AGT_CBTYP_T,
SILCbEdit,
)
from .y_toaster import PYSILModuleToasterBase
class PYSILModuleToaster(PYSILModuleToasterBase):
def edit_toaster(self, silcb: SILCbEdit):
"""
Edit database object callback
Path: container /toast:toaster
Parameters
----------
silcb: SILCbEdit
Control block
Returns
-------
STATUS_T
Return status for the phase.
"""
self.log(
f"Enter 'edit3_toaster' callback toaster@2009-11-20 for {AGT_CBTYP_T(silcb.cbtyp).name} phase silcb.editop={OP_EDITOP_T(silcb.editop).name}"
)
if silcb.cbtyp == AGT_CBTYP_T.AGT_CB_VALIDATE:
# description-stmt validation here
pass
elif silcb.cbtyp == AGT_CBTYP_T.AGT_CB_APPLY:
# database manipulation done here
pass
elif silcb.cbtyp == AGT_CBTYP_T.AGT_CB_COMMIT:
# device instrumentation done here
if silcb.editop == OP_EDITOP_T.OP_EDITOP_DELETE:
# Delete all data from the device
self.log(f"Delete entry")
else:
# Use silcb.update_json to update your device data
#
# The technique here is to replace the existing data
# with this composite Update value.
self.log(f"UPDATE entry with {silcb.update_json}")
elif silcb.cbtyp == AGT_CBTYP_T.AGT_CB_ROLLBACK:
# undo device instrumentation here
pass
else:
return self.flag_internal_error()
return STATUS_T.NO_ERR
def get_toasterManufacturer(self, silcb: SILCbGet):
"""
Get database object callback
Path: leaf /toast:toaster/toasterManufacturer
Parameters
----------
silcb: SILCbGet
Control block
Returns
-------
STATUS_T
status of the callback.
"""
self.log(f"Enter 'get_toasterManufacturer' callback toaster@2009-11-20")
data_found = False
has_more = False
# Check callback mode (silcb.cbmode) to find data required to return
# If the callback mode is GETCB_GET_VALUE (get first value), use first record from your filtered data
if silcb.cbmode == GETCB_MODE_T.GETCB_GET_VALUE:
pass
# If the callback mode is GETCB_GETNEXT_VALUE (get next value) Find current item first (by keys values from current node) and get next item to return
if silcb.cbmode == GETCB_MODE_T.GETCB_GETNEXT_VALUE:
# use keys silcb.local_keys to filter data and find next record
pass
# If item doesn't exist, exit with an error
if not data_found:
return STATUS_T.ERR_NCX_NO_INSTANCE
# Item found. Set specific return_data value
return_data = (
"DisplayString" # *required - replace value with correct <DisplayString>
)
# Save return data and mark if next item exists
res = silcb.add_return_data(data=return_data, has_more=has_more)
# Return status
return res
def get_toasterModelNumber(self, silcb: SILCbGet):
"""
Get database object callback
Path: leaf /toast:toaster/toasterModelNumber
Parameters
----------
silcb: SILCbGet
Control block
Returns
-------
STATUS_T
status of the callback.
"""
self.log(f"Enter 'get_toasterModelNumber' callback toaster@2009-11-20")
data_found = False
has_more = False
# Check callback mode (silcb.cbmode) to find data required to return
# If the callback mode is GETCB_GET_VALUE (get first value), use first record from your filtered data
if silcb.cbmode == GETCB_MODE_T.GETCB_GET_VALUE:
pass
# If the callback mode is GETCB_GETNEXT_VALUE (get next value) Find current item first (by keys values from current node) and get next item to return
if silcb.cbmode == GETCB_MODE_T.GETCB_GETNEXT_VALUE:
# use keys silcb.local_keys to filter data and find next record
pass
# If item doesn't exist, exit with an error
if not data_found:
return STATUS_T.ERR_NCX_NO_INSTANCE
# Item found. Set specific return_data value
return_data = (
"DisplayString" # *required - replace value with correct <DisplayString>
)
# Save return data and mark if next item exists
res = silcb.add_return_data(data=return_data, has_more=has_more)
# Return status
return res
def get_toasterStatus(self, silcb: SILCbGet):
"""
Get database object callback
Path: leaf /toast:toaster/toasterStatus
Parameters
----------
silcb: SILCbGet
Control block
Returns
-------
STATUS_T
status of the callback.
"""
self.log(f"Enter 'get_toasterStatus' callback toaster@2009-11-20")
data_found = False
has_more = False
# Check callback mode (silcb.cbmode) to find data required to return
# If the callback mode is GETCB_GET_VALUE (get first value), use first record from your filtered data
if silcb.cbmode == GETCB_MODE_T.GETCB_GET_VALUE:
pass
# If the callback mode is GETCB_GETNEXT_VALUE (get next value) Find current item first (by keys values from current node) and get next item to return
if silcb.cbmode == GETCB_MODE_T.GETCB_GETNEXT_VALUE:
# use keys silcb.local_keys to filter data and find next record
pass
# If item doesn't exist, exit with an error
if not data_found:
return STATUS_T.ERR_NCX_NO_INSTANCE
# Item found. Set specific return_data value
return_data = "str" # *required - replace value with correct <str>
# Save return data and mark if next item exists
res = silcb.add_return_data(data=return_data, has_more=has_more)
# Return status
return res
def validate_make_toast(self, silcb: SILCbValidate):
"""
Validation phase callback for "<validate_make_toast>" operation.
All YANG constraints have passed at this point.
Add description-stmt checks in this function.
Path: rpc /toast:make-toast
Description:
Make some toast.
The toastDone notification will be sent when
the toast is finished.
An 'in-use' error will be returned if toast
is already being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.
Parameters
----------
silcb: SILCbValidate
Control block
Returns
-------
STATUS_T
Return status for the phase.
An error in validate phase will cancel invoke phase
An rpc-error will be added if an error is returned and the msg error Q is empty
Additional
----------
silcb.input_params: dict with input parameters
silcb.input_params["toasterDoneness"]: int
This variable controls how well-done is the
ensuing toast. It should be on a scale of 1 to 10.
Toast made at 10 generally is considered unfit
for human consumption; toast made at 1 is warmed
lightly.
silcb.input_params["toasterToastType"]: identityref
This variable informs the toaster of the type of
material that is being toasted. The toaster
uses this information, combined with
toasterDoneness, to compute for how
long the material must be toasted to achieve
the required doneness.
"""
self.log(
f"Enter 'validate_make_toast' callback toaster@2009-11-20 input_params={silcb.input_params}"
)
res = STATUS_T.NO_ERR
# if you have an error you also could set errorval
# silcb.set_errorval("testerrorval")
return res
def invoke_make_toast(self, silcb: SILCbInvoke):
"""
Invocation phase callback for "<invoke_make_toast>" operation.
Validation callback has passed at this point.
Call device instrumentation code in this function.
Path: rpc /toast:make-toast
Description:
Make some toast.
The toastDone notification will be sent when
the toast is finished.
An 'in-use' error will be returned if toast
is already being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.
Parameters
----------
silcb: SILCbInvoke
Control block
Returns
-------
STATUS_T
Return status for the phase.
An error in validate phase will cancel invoke phase
An rpc-error will be added if an error is returned and the msg error Q is empty
Additional
----------
silcb.input_params: dict with input parameters
silcb.input_params["toasterDoneness"]: int
This variable controls how well-done is the
ensuing toast. It should be on a scale of 1 to 10.
Toast made at 10 generally is considered unfit
for human consumption; toast made at 1 is warmed
lightly.
silcb.input_params["toasterToastType"]: identityref
This variable informs the toaster of the type of
material that is being toasted. The toaster
uses this information, combined with
toasterDoneness, to compute for how
long the material must be toasted to achieve
the required doneness.
"""
self.log(
f"Enter 'invoke_make_toast' callback toaster@2009-11-20 input_params={silcb.input_params}"
)
res = STATUS_T.NO_ERR
# if you have an error you also could set errorval
# silcb.set_errorval("testerrorval")
# Item found. Create a python object (dict, list, etc) with item data
return_data = {}
# Save return data
res = silcb.add_return_data(data=return_data)
return res
def validate_cancel_toast(self, silcb: SILCbValidate):
"""
Validation phase callback for "<validate_cancel_toast>" operation.
All YANG constraints have passed at this point.
Add description-stmt checks in this function.
Path: rpc /toast:cancel-toast
Description:
Stop making toast, if any is being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.
Parameters
----------
silcb: SILCbValidate
Control block
Returns
-------
STATUS_T
Return status for the phase.
An error in validate phase will cancel invoke phase
An rpc-error will be added if an error is returned and the msg error Q is empty
"""
self.log(f"Enter 'validate_cancel_toast' callback toaster@2009-11-20")
res = STATUS_T.NO_ERR
# if you have an error you also could set errorval
# silcb.set_errorval("testerrorval")
return res
def invoke_cancel_toast(self, silcb: SILCbInvoke):
"""
Invocation phase callback for "<invoke_cancel_toast>" operation.
Validation callback has passed at this point.
Call device instrumentation code in this function.
Path: rpc /toast:cancel-toast
Description:
Stop making toast, if any is being made.
A 'resource-denied' error will be returned
if the toaster service is disabled.
Parameters
----------
silcb: SILCbInvoke
Control block
Returns
-------
STATUS_T
Return status for the phase.
An error in validate phase will cancel invoke phase
An rpc-error will be added if an error is returned and the msg error Q is empty
"""
self.log(f"Enter 'invoke_cancel_toast' callback toaster@2009-11-20")
res = STATUS_T.NO_ERR
# if you have an error you also could set errorval
# silcb.set_errorval("testerrorval")
# Item found. Create a python object (dict, list, etc) with item data
return_data = {}
# Save return data
res = silcb.add_return_data(data=return_data)
return res
def send_toastDone(self, data: dict):
"""
Send a "<toastDone>" notification.
Path: /toast:toastDone
Called by your code when notification event occurs.
This API is optional. It can be replaced with
any function of your choice that provides the same functionality.
Create an internal notification message (agt_not_msg_t) and queue
it for delivery to client sessions.
The parameters depend in the data definitions within the
notification-stmt for this event type.
Parameters
----------
data: dict
Notification data in format:
data = {
"toastStatus": "str", # remove or replace value with correct <str>
}
Returns
-------
None
"""
self.log(f"Enter 'send_toastDone' notification toaster@2009-11-20 data={data}")
self.send_notification(name="toastDone", data=data)
def init(self):
"""
Phase 1: Initialize the toaster server instrumentation library.
Called by server when module is loaded.
Returns
-------
STATUS_T
Return status.
An error will cause the module load to fail.
"""
self.log(f"Enter 'init' toaster@2009-11-20")
return STATUS_T.NO_ERR
def init2(self):
"""
Phase 2: Initialize the toaster server instrumentation library.
SIL init phase 2: non-config data structures.
Called after running config is loaded.
Returns
-------
STATUS_T
Return status for the cleanup.
An error will cause the server initialization to fail.
"""
self.log(f"Enter 'init2' toasters@2009-11-20")
return STATUS_T.NO_ERR
def cleanup(self):
"""
Cleanup the toaster server instrumentation library.
Called by server when module is unloaded.
Returns
-------
STATUS_T
Return status for the cleanup.
"""
self.log(f"Enter 'cleanup' toaster@2009-11-20")
return STATUS_T.NO_ERR
module = PYSILModuleToaster()
y_toaster.py
"""
* Copyright (c) 2008 - 2012, Andy Bierman, All Rights Reserved.
* Copyright (c) 2012 - 2024, YumaWorks, Inc., All Rights Reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*** Generated by py-sil plugin (pyang)
YumaPro PY-SIL module
module toaster
revision 2009-11-20
prefix toast
namespace http://netconfcentral.org/ns/toaster
Created: 2024-05-01T00:28:53Z
Online Developer Manual:
https://docs.yumaworks.com/en/latest/dev/index.html
CLI parameters: -f py-sil toaster.yang
"""
from pysil.module import PYSILModuleBase
class PYSILModuleToasterBase(PYSILModuleBase):
"""Base Python module with configuration for PY-SIL-APP toaster"""
def __init__(self):
config = {
"name": "toaster",
"revision": "2009-11-20",
"container_name": "toaster",
"callbacks": [
{"path": "/toast:toaster", "cb_edit3": "edit_toaster"},
{
"path": "/toast:toaster/toasterManufacturer",
"cb_get2": "get_toasterManufacturer",
"lvl": 3,
},
{
"path": "/toast:toaster/toasterModelNumber",
"cb_get2": "get_toasterModelNumber",
"lvl": 3,
},
{
"path": "/toast:toaster/toasterStatus",
"cb_get2": "get_toasterStatus",
"lvl": 3,
},
{
"path": "/toast:make-toast",
"cb_validate": "validate_make_toast",
"cb_invoke": "invoke_make_toast",
"input_params": [
{
"name": "toasterDoneness",
"type": "uint32",
},
{
"name": "toasterToastType",
"type": "identityref",
},
],
},
{
"path": "/toast:cancel-toast",
"cb_validate": "validate_cancel_toast",
"cb_invoke": "invoke_cancel_toast",
},
],
}
super().__init__(config=config)