how is this yang notification valid? - ietf-netmod-yang

yang 1.1 spec has this example,
The following example defines a notification in a data node:
module example-interface-module {
yang-version 1.1;
namespace "urn:example:interface-module";
prefix "if";
container interfaces {
list interface {
key "name";
leaf name {
type string;
}
notification interface-enabled {
leaf by-user {
type string;
}
}
}
}
}
A corresponding XML instance example of the complete notification:
<notification
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2008-07-08T00:01:00Z</eventTime>
<interfaces xmlns="urn:example:interface-module">
<interface>
<name>eth1</name>
<interface-enabled>
<by-user>fred</by-user>
</interface-enabled>
</interface>
</interfaces>
</notification>
My question is, when I raise a notification from server, I thought the notification content would be this :
<notification
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2008-07-08T00:01:00Z</eventTime>
<interface-enabled xmlns="urn:example:interface-module">
<by-user>fred</by-user>
</interface-enabled>
</notification>
But, such a notification will be useless without identifying the data node for which the notification is relevant.
I guess my question is, what rule/text in the spec tells me how to form the payload correctly

https://www.rfc-editor.org/rfc/rfc7950#section-7.16.2
When a notification node is defined as a child to a data node, the
element defined in [RFC5277] contains a hierarchy of
nodes that identifies the node in the datastore. It MUST contain all
containers and list nodes from the top level down to the list or
container containing the notification.
The notification payload must include all ancestor container/lists up to the module root. Only then it is always possible to identify the exact node to which the notification is referring.

Related

Yang Model recursive search for must condition

I have a problem with a restriction on my CLI. I've been investigating yang RFC7950 (https://www.rfc-editor.org/rfc/rfc7950) but I've found nothing.
Here is an example.
grouping httpGroup {
list http-list{
key "value";
leaf value {
status current { yexte:preliminary; }
description "value to match";
must "(not(../protocol)) and (not(../network-port)))" {
error-message "Not compatible with protocol or non-TCP ports";
}
type string { length "1..255"; }
}
}
}
This group will be included in several groups with the following structure:
list and {
leaf-list protocol { ..... }
uses A;
list or {
leaf-list protocol { ..... }
uses A;
}
}
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup;
}
I need this must condition included in httpGroup to verify that protocol value has not been configured in any level of the hierarchy.
I've made this be adding more relatives paths to search for this node:
// same level
not(../protocol)
// next level
not(../and/protocol)
not(../or/protocol)
// previous level
not(../../protocol)
not(../../protocol)
//recursively down previous level
not(../../and/protocol)
not(../../or/protocol)
// third level
not(../and/or/protocol)
not(../and/and/protocol)
As you can see, this is not a clean solution at all.
Is there any way it can be done for a whole hierarchy like:
if protocol node exists and http-list exists then error.
Thank you in advance.
Groupings are meant to be reusable. It is a bad practice to attempt to create a grouping that may only be used in specific contexts. This is exactly what happens if you define an XPath expression within a grouping and this expression references nodes that are "outside" this grouping (a not yet known ancestor data node, for example, or even worse - an ancestor with a specific name).
The proper way for you to handle this situation would be to use a refine statement in each different context where this grouping is used. You target the value leaf with it, then refine it by adding a must statement, the expression of which of course depends on usage context. You do not define a must statement within grouping http-list.
Within grouping A:
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup {refine "http-list/value" {must "not(../../protocol)";}}
}
As you can see, grouping A is now completely self-sufficient and may be used within any context - the must will not have any problems with it.

Can't get changed property from attachPropertyChange

I would like to know which property in the JSON model has changed when modified by a view.
For a test I took OpenUI5 walkthrough example and added the following lines in the application controller
oProductModel.attachPropertyChange( function(oEvent){
console.log("event: ", oEvent);
}, this);
When I change a property in the text input, the function in the attachPropertyChange is called but oEvent object is empty as I print it in console.
I know I could connect to text input change event, but I would like to use attachPropertyChange in case there would be multiple views of the same model.
As far as I understood, you'd like to avoid using the change event of the Input control because there is no information about which property in the model has changed. However, you can still get all the relevant information within the change handler via:
oControl.getBinding(/*controlPropertyName*/).getPath() to get the name of the bound property, or
oControl.getBindingContext(/*modelName*/).getPath(/*suffix*/) to get the path of the bound context. The getPath here awaits an optional suffix that will be appended to the context path with a "/" in between.
Combine those two APIs to get an absolute path in case the property binding was relative. E.g.:
onInputChange: function (event) {
const inputControl = event.getSource();
const property = inputControl.getBinding("value").getPath(); // "myProperty"
const absolutePath = inputControl.getBindingContext(/*modelName*/).getPath(property) // "/0/myProperty"
// ...
},
You can use change event for all input field in UI, and write event handling method in the controller. You will get the property as well as value in the oEvent of the event handling method easily. I hope you understood.

Conditional assignment of default values in yang

I have two properties in a model:
leaf protocol,
leaf port.
I want to specify that:
if protocol = 'ssh' then default port value is 22,
if protocol = 'http' then default port value is 80,
etc.
How do I express this in yang ?
There are no conditional default values in YANG - you need two default statements for two defaults with different values, and a single leaf may only have one default substatement. You can work around this, however. Perhaps by using a presence container instead of your protocol leaf:
module conditional-default {
namespace "http://example.com/conditional-default";
prefix "excd";
grouping common {
leaf port {
type int32;
}
}
container config {
container ssh {
presence "If this container is present, ssh is configured.";
uses common {
refine port {
default 22;
}
}
}
container http {
presence "If this container is present, http is configured.";
uses common {
refine port {
default 80;
}
}
}
}
}
From RFC6020, 7.5.5.:
The "presence" statement assigns a meaning to the presence of a
container in the data tree. It takes as an argument a string that
contains a textual description of what the node's presence means.

Calling method from console: "No current object"

I have a method that I need to test. I would like to do so from the console. Here is the method, as well as some metadata from the class:
Include HS.Common
Class Custom.class Extends Ens.BusinessOperation
{
Parameter ADAPTER = "EnsLib.EMail.OutboundAdapter";
Property Adapter As EnsLib.EMail.OutboundAdapter;
Method SendMessage(pSubject As %String, pMessage As %String, pEmailAddresses) As %Status
{
set tSC=$$$OK
set tMailMessage=##class(%Net.MailMessage).%New()
do tMailMessage.To.Insert($PIECE(pEmailAddresses,",",1))
for tI=2:1:$LENGTH(pEmailAddresses,",") {
do tMailMessage.Cc.Insert($PIECE(pEmailAddresses,",",tI))
}
set tMailMessage.Subject=pSubject
set tMailMessage.Charset="iso-8859-1"
set tSC=tMailMessage.TextData.Write(pMessage)
quit:'tSC
Set tSC1=..Adapter.SendMail(tMailMessage)
if 'tSC1 {
//Log warning about being unable to send mail.
do $SYSTEM.Status.DecomposeStatus(tSC1,.err)
$$$LOGWARNING("Could not send email: "_err(err))
kill err
}
quit tSC
}
...other methods here...
}
but when I perform this command:
set tResult = ##class(Custom.class).SendMessage("Test Subject","Test Message","my#email.com")
I get this error:
Set tSC1=..Adapter.SendMail(tMailMessage)
^
<NO CURRENT OBJECT>zSendMessage+11^Custom.class.1
I tried instantiating adapter, much like the property definition, before calling the method but that did not work. How can I call this method from a console session?
this method is an instance method, and you can't call it directly just for some class. Before, you should create an object, and then for that object, you can call any instance methods. But you still trying to call Ensemble classes, it is not so easy, because you should prepare environment, such as configured and started Ensemble Production, your class should be added as an Operation, configured and activated.
set oper=##class(Custom.class).%New("configName")
where configName - name for that operation in your production, by default it is same as class name (e.g. "Custom.class"). And now you can call your method.
write oper.SendMessage("testSubj","test body","my#mail.com")
But I would not recommend such way. It would be better if you test it through production, just sent test messages to this operation.

IT Hit WebDAV Ajax Browser Custom Columns

I am looking at a trial of the Ajax Browser Control by ItHit. So far it seems to be pretty responsive when it comes to pulling files across http protocol.
What I want to do at this point is have the details view pull custom properties from my excel workbooks. What is the most efficient way to connect my C# code that gets the custom properties to the Ajax control to display the correct values?
The easiest way to create a custom column is to return custom property from a WebDAV server. In the example below the server returns price in PricesNs:RetailPrice property.
On a client side you will define a custom column and specify custom property name and namespace:
{
Id: 'MyColumn1',
CustomPropertyName: 'RetailPrice',
CustomPropertyNamespace: 'PricesNs',
Text: 'Retail Price',
Width: '150px'
}
Another approach is to return an HTML from a Formatter function specified for column. You have a full control over what is being displayed in this case.
You can find more details and an example in this article: http://www.webdavsystem.com/ajaxfilebrowser/programming/grids_customization/
In case your WebDAV server is running on IT Hit WebDAV Server Engine, to return the requested property, you must implement IHierarchyItem.GetProperties method (or its asynchronous counterpart):
public IEnumerable<PropertyValue> GetProperties(IList<PropertyName> names, bool allprop)
{
if (allprop)
{
return getPropertyValues();
}
List<PropertyValue> propVals = new List<PropertyValue>();
foreach(PropertyName propName in names)
{
if( (propName.Namespace == "PricesNs") && (propName.Name == "RetailPrice") )
{
// Depending on the item you will return a different price,
// but here for the sake of simplicity we return one price regerdless of the item
propVals.Add(new PropertyValue(propName, "100"));
}
else
{
...
}
}
return propVals;
}