Exemplo n.º 1
0
static
unsigned rw_pb_create_field_indices(const rw_yang_pb_msgdesc_t* ypbc_msgdesc,
                               YangNode* ynode,
                               std::vector<int>& fields)
{
  RW_ASSERT(ypbc_msgdesc);
  RW_ASSERT(ynode);

  auto ypbc_fdescs = ypbc_msgdesc->ypbc_flddescs;
  unsigned nkeys = 0;

  if (ynode->get_stmt_type() == RW_YANG_STMT_TYPE_LIST) {
    for (YangKeyIter yki = ynode->key_begin(); yki != ynode->key_end(); yki++) {
      YangNode *knode = yki->get_key_node();
      for (unsigned i = 0; i < ypbc_msgdesc->num_fields; i++) {
        if (!strcmp(knode->get_name(), ypbc_fdescs[i].yang_node_name)) {
          fields.push_back(ypbc_fdescs[i].pbc_order);
        }
      }
      nkeys++;
    }
  }

  RW_ASSERT(fields.size() == nkeys);

  // Remaining fields in the yang-order, though it doesn't matter.
  for (unsigned i = 0; i < ypbc_msgdesc->num_fields; i++) {
    if (!(ypbc_fdescs[i].pbc_fdesc->rw_flags & RW_PROTOBUF_FOPT_KEY)) {
      fields.push_back(ypbc_fdescs[i].pbc_order);
    }
  }

  return nkeys;
}
Exemplo n.º 2
0
TEST (JsonSchema, JsonAugmentTest)
{
  TEST_DESCRIPTION ("Test for simple yang to json conversion");
  YangModelNcx* model = YangModelNcx::create_model();
  YangModel::ptr_t p(model);
  ASSERT_TRUE(model);
  YangNode* root = model->get_root_node();
  ASSERT_TRUE(root);
  
  YangModule* tnaa1 = model->load_module("test-json-schema");
  ASSERT_TRUE(tnaa1);
  YangAugment* person = tnaa1->get_first_augment();
  ASSERT_TRUE(person);
  YangNode* node = person->get_target_node();

  std::stringstream oss(node->to_json_schema(true));
  std::cout << oss.str() << std::endl;

  pt::ptree tree;
  pt::read_json(oss, tree);
  bool found_comp_list = false;

  BOOST_FOREACH(const pt::ptree::value_type& val, tree.get_child("person.properties"))
  {
    auto name = val.second.get<std::string>("name");

    if (name == "test-json-schema:company-list") {
      found_comp_list = true;
      EXPECT_STREQ (val.second.get<std::string>("type").c_str(), "list");
      EXPECT_STREQ (val.second.get<std::string>("cardinality").c_str(), "0..N");

      BOOST_FOREACH (const pt::ptree::value_type& v, val.second.get_child("properties")) {
        auto iname = v.second.get<std::string>("name");
        std::cout << iname << std::endl;
        if (iname == "iref1") {
          const auto& dtype = v.second.get_child("data-type.idref");
          EXPECT_STREQ (dtype.get<std::string>("base").c_str(), "tjs:riftio");
        }
        if (iname == "iref2") {
          const auto& dtype = v.second.get_child("data-type.idref");
          EXPECT_STREQ (dtype.get<std::string>("base").c_str(), "tjs:cloud-platform");
        }
      }
    }
  }
Exemplo n.º 3
0
rw_yang_netconf_op_status_t XMLDocMerger::do_delete(
                YangNode* child_ynode,
                XMLNode* new_node,
                XMLNode* new_child,
                XMLNode* delta_child)
{
  rw_yang_netconf_op_status_t status = RW_YANG_NETCONF_OP_STATUS_OK;
  
  // The deletion of last case node should add default-case default-values
  // This is taken care by fill_defaults()

  XMLNode* remove_node = new_child;
  xml_data_presence_t data_presence = check_if_data_exists(child_ynode,
                                              new_node, delta_child, &remove_node);
  switch(data_presence) {
    case XML_DATA_MISSING: {
      if (current_operation_ == XML_EDIT_OP_DELETE) {
        std::string const error_msg = "Node ("
                                      + new_node->get_local_name()
                                      + ") has missing data";
        report_error(delta_child, RW_YANG_NETCONF_OP_STATUS_DATA_MISSING, error_msg.c_str());
        return RW_YANG_NETCONF_OP_STATUS_DATA_MISSING;
      }
      return status;
    }
    case XML_DATA_EXISTS: {
      // If a leaf node has default value and is deleted, then don't report it,
      // just delete the node, the default value will added when fill_defaults
      // is invoked.
      if (child_ynode->get_default_value() == nullptr) {
        // Neither a leaf nor a leaf with default value
        report_delete(remove_node);
      } else {
        // has default value, if it is part of a case and is the last node, and
        // is not part of the default case then report deletion
        YangNode* ycase = child_ynode->get_case();
        YangNode* ychoice = child_ynode->get_choice();
        if (ychoice && ycase != ychoice->get_default_case()) {
          bool found = false;
          // Iterate thru the subtree to find if any node in the existing case
          // exists. If so, don't report
          for (XMLNodeIter it = new_node->child_begin();
               it != new_node->child_end(); ++it) {
            XMLNode* xnode = &(*it);
            if (xnode != remove_node && 
                xnode->get_yang_node()->get_case() == ycase) {
              found = true;
            }
          }
          if (!found) {
            report_delete(remove_node);
          }
        }
      }
      new_node->remove_child(remove_node);
      break;
    }
    case XML_DATA_LIST_EXISTS: {
      // remove all the data with the list name
      for (XMLNode* xchild = new_node->get_first_child(); xchild; ) {
        if (xchild->get_local_name() == child_ynode->get_name() &&
            xchild->get_name_space() == child_ynode->get_ns()) {
          XMLNode* next_node = xchild->get_next_sibling();

          // Multiple keyspecs, report the deletion and remove it from dom
          report_delete(xchild);
          new_node->remove_child(xchild);
          xchild = next_node;
        } else {
          xchild = xchild->get_next_sibling();
        }
      }
      break;
    }
  }

  return status;
}
Exemplo n.º 4
0
void XMLDocMerger::fill_defaults(
          YangNode* ynode,
          XMLNode*  new_node,
          XMLNode*  update_node,
          bool*     update_required
       )
{
  YangNode* yn = nullptr;
  XMLNode*  xchild = nullptr;

  for (YangNodeIter it = ynode->child_begin();
       it != ynode->child_end(); ++it) {
    yn = &(*it);
    const char* default_val = yn->get_default_value();
    if (!default_val && !yn->has_default()) {
      // Only default values or containers with default leaf descendents
      continue;
    }

    // Default values may be within a choice/case. Check if the choice has
    // another case. If the same case is present
    YangNode* ychoice = yn->get_choice();
    YangNode* ycase = yn->get_case();
    YangNode* other_choice = nullptr;
    YangNode* other_case   = nullptr;
    bool add_default = true;
    bool subtree_update = false;
    if (ychoice && ycase && (ychoice->get_default_case() != ycase)) {
      add_default = false;
    }

    for (XMLNodeIter xit = new_node->child_begin();
         xit != new_node->child_end(); ++xit) {
      xchild = &(*xit);
      if (xchild->get_local_name() == yn->get_name() &&
          xchild->get_name_space() == yn->get_ns()) {
        if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) {
          // The container has a default descendant node
          XMLNode* update_child = nullptr;
          bool created = false;
          if ((update_child = update_node->find(
                                yn->get_name(), yn->get_ns())) == nullptr) {
            update_child = update_node->add_child(yn);
            created = true;
          }
          fill_defaults(yn, xchild, update_child, &subtree_update);
          if (!subtree_update && created) {
            update_node->remove_child(update_child);
          }
          *update_required = (*update_required || subtree_update);
        }
        // Default node already present in the new-dom
        add_default = false;
        break;
      }
      
      if (!ychoice) {
        // Not part of a choice
        continue;
      }

      other_choice = xchild->get_yang_node()->get_choice();
      if (!other_choice || (other_choice != ychoice)) {
        // Other node is not a choice, or not the same choice, not conflicting
        continue;
      }

      other_case = xchild->get_yang_node()->get_case();
      if (other_case && (ycase != other_case)) {
        // There is a node with conflicting case. Hence no default
        add_default = false;
        break;
      }

      // Same case, in-case the case is not default, some-other node in the same
      // case is set. Then add this default, unless the same node is found in
      // the new-dom.
      add_default = true;
    }
    if (add_default) {
      XMLNode* xn = new_node->add_child(yn, default_val);
      RW_ASSERT(xn);
      XMLNode* un = update_node->add_child(yn, default_val);
      if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER) {
        // The container has a default descendant node
        fill_defaults(yn, xn, un, &subtree_update);
        if (!subtree_update) {
          new_node->remove_child(xn);
          update_node->remove_child(un);
        }
        *update_required = (*update_required || subtree_update);
      } else {
        *update_required = true;
      }
    }
  }
}
Exemplo n.º 5
0
// ATTN: This function seriously needs re-organization, will be done
// shortly.
rw_yang_netconf_op_status_t XMLDocMerger::do_edit(XMLNode* new_node, 
                XMLNode* delta_node,
                XMLNode* update_node,
                bool* update_required)
{
  rw_yang_netconf_op_status_t status = RW_YANG_NETCONF_OP_STATUS_OK;
  YangNode* ynode = new_node->get_descend_yang_node();
  XMLEditDefaultOperation parent_op = current_operation_;

  for(XMLNodeIter it = delta_node->child_begin();
      it != delta_node->child_end(); ++it)
  {
    XMLNode* delta_child = &(*it);
    std::string child_name = delta_child->get_local_name();
    std::string child_ns = delta_child->get_name_space();

    YangNode* child_ynode = ynode->search_child(child_name.c_str(), 
                                                child_ns.c_str());
    if (child_ynode == nullptr) {
      // Incoming node is not in our model and thus is an error
      std::string const err_msg = "Cannot find child ("+child_name+") of node ("+delta_node->get_local_name()+")";
      report_error(delta_node, RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE, err_msg.c_str());
      return RW_YANG_NETCONF_OP_STATUS_INVALID_VALUE;
    }

    // Set the current node operation (default=merge)
    status = set_current_operation(delta_child);
    if (status !=  RW_YANG_NETCONF_OP_STATUS_OK) {
      return status;
    }

    bool subtree_update = false;

    XMLNode* new_child = new_node->find(child_name.c_str(), child_ns.c_str());
    if (new_child == nullptr) {
      // Node not found in existing config, edit-config on new node
      status = do_edit_new(child_ynode, new_node, delta_child, 
                           update_node, &subtree_update);
    } else {
      status = do_edit_existing(child_ynode, new_node, new_child, delta_child,
                           update_node, &subtree_update);
    }

    *update_required = (*update_required || subtree_update);

    if (status !=  RW_YANG_NETCONF_OP_STATUS_OK) {
      return status;
    }
    current_operation_ = parent_op;
  }

  if (current_operation_ == XML_EDIT_OP_REPLACE) {
    // Iterate thru the config dom node and find the elements not in delta
    // Those are marked for deletion.
    do_delete_missing(new_node, delta_node);
  }

  // Add defaults
  fill_defaults(ynode, new_node, update_node, update_required);

  if (!(*update_required)) {
    // No updates on this subtree. Either it is delete/remove operation or
    // the config is not changed. So remove the update subtree. 
    XMLNode* parent = update_node->get_parent();
    if (parent) {
      parent->remove_child(update_node);
    }
  }

  if (new_node->get_first_child() == nullptr &&
      ynode->get_stmt_type() == RW_YANG_STMT_TYPE_CONTAINER &&
      !ynode->is_presence()) {
    // No children for a non-presence container, they are only present to
    // maintain hierarchy. Remove it
    XMLNode* parent = new_node->get_parent();
    if (parent) {
      parent->remove_child(new_node);
    }
  }

  return status;
}
Exemplo n.º 6
0
  virtual rw_xml_next_action_t visit(XMLNode* node, XMLNode** path, int32_t level)
  {
    if  (node == nullptr) {
      return RW_XML_ACTION_TERMINATE;
    }

    YangNode *yn = node->get_yang_node();
    
    if (nullptr == yn) {
      return RW_XML_ACTION_NEXT;
    }

    if (yn->get_stmt_type() == RW_YANG_STMT_TYPE_LIST) {
      return RW_XML_ACTION_NEXT_SIBLING;      
    }

    RW_ASSERT(to_node_);
    

    
    // This is the root node then this is the first time call
    if (level == 0) {
      RW_ASSERT(level_ == -1);

      std::string text = node->get_text_value();

      if (node->get_yang_node()->is_leafy() &&
          node->get_yang_node()->get_type()->get_leaf_type() != RW_YANG_LEAF_TYPE_EMPTY && 
          text.find_first_not_of("\t\n\v\f\r ") != std::string::npos) {
        if (text.find_first_of ("http")) {
          RW_CRASH();
        }
        
        curr_node_ = to_node_->add_child(node->get_yang_node(), node->get_text_value().c_str());
      } else {
        curr_node_ = to_node_->add_child(node->get_yang_node());
      }
      path_[++level_].first = node;
      path_[level_].second = curr_node_;
      
      return RW_XML_ACTION_NEXT;
    }
    
    XMLNode *from_parent = path[level-1];
    
    RW_ASSERT(from_parent);
    
    // Walk up our path and find the corresponding parent in teh vistor's tree
    
    while(level_ >= 0)  {
      if (path_[level_].first == from_parent) {
        // Found a common parent - break  and add the new node
        XMLNode *to_parent = static_cast<XMLNode*>(path_[level_].second);

        std::string text = node->get_text_value();

        if (text.find_first_not_of("\t\n\v\f\r ") != std::string::npos) {
          // A bit of a hack to ensure that white spaces are not inserted to the
          // XML. This is a problem for UT that read from files 
          
          curr_node_ = to_parent->add_child(node->get_yang_node(), node->get_text_value().c_str());
        } else {
          curr_node_ = to_parent->add_child(node->get_yang_node());
        }
        
        
        // Replace the node in the current path with the new node.
        path_[++level_].first = node;
        path_[level_].second  = curr_node_;
        break;
      }
      level_--;
    }
    RW_ASSERT(level_ > 0);
    
    return RW_XML_ACTION_NEXT;
  }
Exemplo n.º 7
0
XMLNode* get_node_by_hkeypath (XMLNode *node,
                               confd_hkeypath_t *keypath,
                               uint16_t stop_at)

{
  const char *ns = 0;

  int i = keypath->len;

  while (i > stop_at) {

    confd_value_t *val = &keypath->v[i-1][0];
    const char *tag = 0;
    char value[CONFD_MAX_STRING_LENGTH];
    struct confd_cs_node *cs_node = confd_find_cs_node (keypath, keypath->len - (i - 1));


    RW_ASSERT(cs_node);
    RW_ASSERT(C_XMLTAG == val->type);

    tag = confd_hash2str (val->val.xmltag.tag);
    ns = confd_hash2str (val->val.xmltag.ns);

    node = node->find (tag, ns);

    if (nullptr == node) {
      return nullptr;
    }

    i--;

    if (i == 0) {
      return node;
    }

    YangNode *yn = node->get_yang_node();
    
    if (!yn->is_listy()) {
      continue;
    }

    if (!yn->has_keys()) {
      // Keyless list - there should be only a single "key-value", which should
      // be a ptr to a sibling value. There is no list node parent in XML.
      RW_ASSERT(keypath->v[i-1][0].type == C_INT64);
      RW_ASSERT(keypath->v[i-1][1].type == C_NOEXISTS);
      XMLNode *sibling = (XMLNode *) (keypath->v[i-1][0].val.i64);
      if (nullptr == sibling) {
        return nullptr;
      }

      
      RW_ASSERT (sibling->get_parent() == node->get_parent());

      // There could be multiple keyless lists
      node = sibling;
      i --;
      continue;
    }
    
    bool matched = true;

    // The node has moved to the *first* list entry that it could find.
    // go through all its siblings with matching names to see if any match
    // all the keys.

    while (node) {

      matched = true;

      for (int j = 0; val->type != C_NOEXISTS; j++) {
        
        val = &keypath->v[i-1][j];

        RW_ASSERT(cs_node->info.keys[j]);
        tag = confd_hash2str(cs_node->info.keys[j]);

        switch (val->type) {
          case C_NOEXISTS:
          case C_XMLEND:
          case C_BIT32:
          case C_BIT64:
          case C_XMLTAG:
            RW_CRASH();
            break;
          case C_ENUM_VALUE:
            if (nullptr == node->find_enum (tag, ns, CONFD_GET_ENUM_VALUE (val))) {
              matched = false;
            }
            break;
          default:
            size_t len =  confd_pp_value (value, sizeof (value), val);
            RW_ASSERT (len < sizeof (value));
            
            if (!len || nullptr == node->find_value (tag, value, ns)) {
              matched = false;
            }
            break;
        }
        if (!matched) {
          break;
        }
        val = &keypath->v[i-1][j+1];
      }

      if (matched) {
        break;
      }
      node = node->get_next_sibling(node->get_local_name(), node->get_name_space());
    }

    if (!matched) {
      return nullptr;
    }
    // Account for the key
    i--;
  }
  return node;
}
Exemplo n.º 8
0
rw_status_t get_confd_case ( rw_yang::XMLNode *root,
                             confd_hkeypath_t *keypath,
                             confd_value_t *choice,
                             confd_value_t *case_val)
{
  RW_ASSERT (case_val);
  rw_yang::XMLNode *node = get_node_by_hkeypath (root, keypath, 0);

  if (nullptr == node) {
    return RW_STATUS_FAILURE;
  }

  XMLNodeList::uptr_t children(node->get_children());

  for (size_t i = 0; i < children->length(); i++) {
    XMLNode* child = children->at(i);
    YangNode *yn = child->get_descend_yang_node();

    if (nullptr == yn) {
      continue;
    }

    YangNode *yn_case = yn->get_case();
    if (nullptr == yn_case) {
      continue;
    }

    // The comparision starts with the choice..
    YangNode *yn_choice = yn_case->get_choice();
    RW_ASSERT (yn_choice);

    while (choice->type != C_NOEXISTS) {

      RW_ASSERT (choice->type == C_XMLTAG);

      const char * tag = confd_hash2str (choice->val.xmltag.tag);
      int n_s = choice->val.xmltag.ns;
      const char *ns = confd_hash2str (n_s);

      if (strcmp (tag, yn_choice->get_name()) ||
          strcmp (ns, yn_choice->get_ns())) {
        break;
      }

      // The case matches - check if choice exists
      choice++;

      if (C_NOEXISTS == choice->type) {
        case_val->type = C_XMLTAG;
        case_val->val.xmltag.ns = n_s;
        case_val->val.xmltag.tag = confd_str2hash (yn_case->get_name());
        return RW_STATUS_SUCCESS;
      }

      RW_ASSERT (choice->type == C_XMLTAG);

      yn_case = yn_choice->get_case();

      // Can this be null??
      RW_ASSERT (yn_case);

      tag = confd_hash2str (choice->val.xmltag.tag);
      ns = confd_hash2str (choice->val.xmltag.ns);

      if (strcmp (tag, yn_case->get_name()) ||
          strcmp (ns, yn_case->get_ns())) {
        break;
      }
    }
  }

  return RW_STATUS_FAILURE;
}
Exemplo n.º 9
0
rw_tree_walker_status_t add_xml_child (XMLNode *parent,
                                       rw_confd_value_t *confd,
                                       XMLNode*& child)
{
  confd_cs_node *cs_node = confd->cs_node;
  confd_value_t *child_src = confd->value;
  const char *name = confd_hash2str (confd->cs_node->tag);
  const char *ns = confd_hash2str (confd->cs_node->ns);

  YangNode *child_yn = nullptr;
  child = nullptr;

  YangNode *yn = parent->get_yang_node();
  if (!yn) {
    return RW_TREE_WALKER_FAILURE;
  }

  child_yn = yn->search_child (name, ns);
  if (!child_yn) {
    return RW_TREE_WALKER_FAILURE;
  }

  if (!child_yn->is_leafy()) {
    child = parent->add_child(child_yn);
    if (child) {
      return RW_TREE_WALKER_SUCCESS;
    }

    return RW_TREE_WALKER_FAILURE;
  }

  char value[1024];
  char *val_p = nullptr;
  
  switch (child_src->type) {
    default:
    case C_QNAME: 
    case C_DATETIME: 
    case C_DATE: 
    case C_TIME: 
    case C_DURATION:
    case C_NOEXISTS:
    case C_STR:
    case C_SYMBOL:
    case C_BIT32: 
    case C_BIT64:
    case C_XMLBEGIN:  
    case C_XMLEND: 
    case C_OBJECTREF: 
    case C_UNION: 
    case C_PTR: 
    case C_CDBBEGIN: 
    case C_OID: 
    case C_DEFAULT: 
    case C_IDENTITYREF: 
    case C_XMLBEGINDEL: 
    case C_DQUAD: 
    case C_HEXSTR: 

      RW_CRASH();
    break;
    
    case C_XMLTAG:
      break;

    case C_BUF: 
    case C_INT8: 
    case C_INT16: 
    case C_INT32: 
    case C_INT64: 
    case C_UINT8: 
    case C_UINT16: 
    case C_UINT32: 
    case C_UINT64: 
    case C_DOUBLE: 
    case C_BOOL: 
    case C_ENUM_VALUE:
    case C_BINARY: 
    case C_DECIMAL64: 
    case C_IPV4: 
    case C_IPV6: 
    case C_IPV4PREFIX:
    case C_IPV4_AND_PLEN: 
    case C_IPV6_AND_PLEN: 
    case C_IPV6PREFIX: {

      struct confd_type *ct = cs_node->info.type;
      
      int len = confd_val2str (ct, child_src, value, sizeof (value));
      if (len < 0) {
        return RW_TREE_WALKER_FAILURE;
      }
      val_p = &value[0];
    }
      
      break;
    case C_LIST: {
      
      // ATTN: ATTN:
      // This code is inefficient. TAIL-F has been asked what the best method
      // for doing this is. Once TAILF responds, change this code.

      // ATTN: ATTN:
      // This also needs to change when protobuf representation of a leaf list
      // transitions to becoming a list of single elements
      

      struct confd_type *ct = confd_get_leaf_list_type (cs_node);
      RW_ASSERT(ct);
      
      int len = confd_val2str (ct, child_src, value, sizeof (value));
      if (len < 0) {
        return RW_TREE_WALKER_FAILURE;
      }
      val_p = &value[0];
    }
      break;
  }
  child = parent->add_child (child_yn, val_p);
  if (child) {
    return RW_TREE_WALKER_SUCCESS;
  }

  return RW_TREE_WALKER_FAILURE;
}