corenova / yang-js

YANG parser and composer
Apache License 2.0
56 stars 18 forks source link

enable() of Model instance is not working #52

Closed vcshox closed 7 years ago

vcshox commented 7 years ago

I have a yang file with feature statement for example:

module example-sports {
  namespace "http://example.com/example";
  prefix example;

  feature my_feature {
    description "my feature";
  }
  container feature-test {
    if-feature my_feature;
    leaf a-leaf {
      type string;
    }
  }
}

When I eval the schema with the data:

{
 "example-sports:feature-test":{
    "a-leaf":"hello"
  }
}

a model instance (ex:x) is generated.

I called x.enable("my_feature") and got the following error: PropertyError: [/example-sports] unable to enable unknown feature 'my_feature'

Is there a any bug or I misunderstand the function?

sekur commented 7 years ago

I think you meant x.enable("my_feature")?

The way the feature system is supported by yang-js is by binding a feature to the schema.

You can bind during constructor/parse as follows:

var Yang = require('yang-js');
var schema = Yang("module  ...", {
  'feature(my_feature)': => { this.content = { ...yourFeature }; }
});

You can bind after parsing as follows:

var Yang = require('yang-js');
var schema = Yang("module  ...");
schema.bind({
  'feature(my_feature)': => { this.content = { ...yourFeature }; }
});

You can also specify the feature during enable:

x.enable("my_feature", ...yourFeature);

Hope this helps.

sekur commented 7 years ago

BTW, the difference between binding to a schema vs. assigning during enable is that when you bind, then every subsequent eval of that schema will use the bound function when the content of that element is accessed. When you assign during enable, the feature applies to that particular instance of the Model only.

vcshox commented 7 years ago

@saintkepha

Thanks for your clear explanation! Yes, I meant x.enable("my_feature") !

So, is the function bound to the feature like a switch of it? (For example return true means feature active, return false means non-active.)

sekur commented 7 years ago

The key idea here is that you actually bind the implementation of that feature to become accessible from the schema. It's a bit beyond simple true/false conditional - since one of the main functionality of yang-js is to operate as a runtime evaluator.

The feature is considered available if there is a function bound to the feature element and unavailable otherwise. So from the parse/eval perspective of dealing with if-feature conditional, you should actually use the bind mechanism.

Now, when you enable a feature, it attempts to retrieve that feature module (either from the binding or via explicit assignment) and attach that feature into the internal @engine property. This would internally emit enable:my_feature event and would allow that feature implementation to perform activation/initialization logic. It's considered runtime active at this point, which is different from the available/unavailable status which is mainly used for conditional schema parse/eval.

You can also take a look at the yang-express module and see how the feature bindings are accessed and used inside control logic bindings (such as rpc run).

vcshox commented 7 years ago

@saintkepha

Thank you! This is really a great help!

sekur commented 7 years ago

@vcshox - sure thing. The feature handling subsystem is a bit experimental and not very well documented so give it a whirl and let me know if any ideas pop up on how we can improve it.

vcshox commented 7 years ago

@saintkepha I think multiple feature conditions for if-feature is not working?

module example-sports {

  namespace "http://example.com/example";
  prefix example;

  feature my_feature1 {
    description "my feature1";
  }
  feature my_feature2 {
    description "my feature2";
  }
  container feature-test {
    if-feature "my_feature1 and my_feature2";
    leaf a-leaf {
      type string;
    }
  }
}

Both my_feature1 and my_feature2 are bound with one function

But after eval, the container feature-test is not active

sekur commented 7 years ago

Allowing boolean conditionals in if-feature statement is a YANG 1.1 (RFC 7950) spec. Current yang-js does not have full RFC 7950 spec compliance yet.

You will need to use multiple if-feature statements for the intended effect:

if-feature my_feature1;
if-feature my_feature2;

Would be happy to receive a PR to enable this, if interested, take a look at https://github.com/corenova/yang-js/blob/master/src/lang/extensions.coffee#L401

Inside the transform function, @tag would contain the argument "my_feature1 and my_feature2" as a string. It's just a matter of parsing the conditional expression and performing the proper lookups to see if the feature is present in the schema (and then whether there's a binding on it or not).

Should comply with the RFC: https://tools.ietf.org/html/rfc7950#section-7.20.2

vcshox commented 7 years ago

@saintkepha

OK, I will try.

But I am not that familiar with the pull request process and coffeescript, it might take some time.

sekur commented 7 years ago

@vcshox - I've implemented the if-feature boolean conditional evaluator using comparse. Feel free to take a look at the commit at #54.