diff --git a/.travis.yml b/.travis.yml index c838f3916..10c0788d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,10 +10,12 @@ matrix: - os: osx osx_image: xcode8.3 language: generic + go: 1.9 - os: osx env: GNMI=true osx_image: xcode8.3 language: generic + go: 1.9 # - env: DOCKER=true OS_TYPE=centos OS_VERSION=centos7 PYTHON_VERSION=2.7 # - env: DOCKER=true OS_TYPE=centos OS_VERSION=centos7 PYTHON_VERSION=2.7 GNMI=true - env: DOCKER=true OS_TYPE=centos OS_VERSION=centos7 PYTHON_VERSION=3.6 diff --git a/CHANGES.md b/CHANGES.md index c8bde74bc..a040d0cee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ ### 2019-05-15 version 0.8.3 #### Resolved GitHub issues + * YDK return value of YANG action missing some attributes ([#871](https://github.com/CiscoDevNet/ydk-gen/issues/871)) * Duplicate code in generated cisco-ios-xe Go bundle ([#891](https://github.com/CiscoDevNet/ydk-gen/issues/891)) * Memory leaks in YDK C++ core ([#899](https://github.com/CiscoDevNet/ydk-gen/issues/899)) diff --git a/sdk/cpp/CHANGES.md b/sdk/cpp/CHANGES.md index 36f8d59ed..59315e0f8 100644 --- a/sdk/cpp/CHANGES.md +++ b/sdk/cpp/CHANGES.md @@ -1,6 +1,7 @@ ### 2019-05-15 version 0.8.3 #### Resolved GitHub issues + * YDK return value of YANG action missing some attributes ([#871](https://github.com/CiscoDevNet/ydk-gen/issues/871)) * Duplicate code in generated cisco-ios-xe Go bundle ([#891](https://github.com/CiscoDevNet/ydk-gen/issues/891)) * Memory leaks in YDK C++ core ([#899](https://github.com/CiscoDevNet/ydk-gen/issues/899)) diff --git a/sdk/cpp/core/docsgen/api/path/sessions/netconf_session.rst b/sdk/cpp/core/docsgen/api/path/sessions/netconf_session.rst index 9177f2e87..0c0143a7b 100644 --- a/sdk/cpp/core/docsgen/api/path/sessions/netconf_session.rst +++ b/sdk/cpp/core/docsgen/api/path/sessions/netconf_session.rst @@ -90,26 +90,33 @@ NetconfSession :param on_demand: Enable on demand downloading by default. :param timeout: The timeout in microseconds, -1 for infinite timeout, 0 for non-blocking - .. cpp:function:: virtual path::RootSchemaNode& get_root_schema() const + .. cpp:function:: path::RootSchemaNode& get_root_schema() const Returns the :cpp:class:`RootSchemaNode` tree supported by this instance of the ``NetconfSession``. :return: Pointer to the :cpp:class:`RootSchemaNode` or ``nullptr`` if one could not be created. - .. cpp:function:: virtual std::shared_ptr invoke(path::Rpc& rpc) const + .. cpp:function:: std::shared_ptr invoke(path::Rpc& rpc) const - Invokes or executes the given rpc and returns a :cpp:class:`DataNode` pointer if the Rpc has an output modelled in YANG. + Invokes or executes the given RPC and returns a :cpp:class:`DataNode` pointer if the Rpc has an output modelled in YANG. :param rpc: Reference to the :cpp:class:`Rpc` node. :return: Shared pointer to the :cpp:class:`DataNode` representing the output. - .. cpp:function:: virtual std::shared_ptr invoke(path::DataNode& datanode) const + .. cpp:function:: std::shared_ptr invoke(path::DataNode& datanode) const Invokes or executes the given DataNode containing a YANG 1.1 action and returns a :cpp:class:`DataNode` pointer if the action has an output modeled in YANG. :param datanode: Reference to the :cpp:class:`DataNode` node. :return: Pointer to the :cpp:class:`DataNode` representing the output. + .. cpp:function:: std::string execute_netconf_operation(path::Rpc& rpc) const + + Sends the specified RPC to device (similar to `invoke` function) and returns device response in XML encoded string. + + :param rpc: Reference to the :cpp:class:`Rpc` node. + :return: std::string, which represents the RPC output. + .. cpp:function:: std::vector get_capabilities() const Returns a vector of the client's capabilities diff --git a/sdk/cpp/core/docsgen/api/path/sessions/restconf_session.rst b/sdk/cpp/core/docsgen/api/path/sessions/restconf_session.rst index f8c53a557..39ca0ee76 100644 --- a/sdk/cpp/core/docsgen/api/path/sessions/restconf_session.rst +++ b/sdk/cpp/core/docsgen/api/path/sessions/restconf_session.rst @@ -44,17 +44,17 @@ RestconfSession :param config_url_root: To provider backwards compatibility with older drafts of restconf RFC, this can be "/config" or "/data" (which is the default) :param state_url_root: To provider backwards compatibility with older drafts of restconf RFC, this can be "/operational" or "/data" (which is the default) - .. cpp:function:: virtual path::RootSchemaNode& get_root_schema() const + .. cpp:function:: path::RootSchemaNode& get_root_schema() const Returns the :cpp:class:`RootSchemaNode` tree supported by this instance of the ``RestconfSession``. :return: Reference to the :cpp:class:`RootSchemaNode` or ``nullptr`` if one could not be created. - .. cpp:function:: virtual std::shared_ptr invoke(path::Rpc& rpc) const + .. cpp:function:: std::shared_ptr invoke(path::Rpc& rpc) const Invokes or executes the given rpc and returns a :cpp:class:`DataNode` pointer if the Rpc has an output modeled in YANG. :param rpc: Reference to the :cpp:class:`Rpc` node. :return: Pointer to the :cpp:class:`DataNode` representing the output. - .. cpp:function:: virtual ~RestconfSession() + .. cpp:function:: ~RestconfSession() diff --git a/sdk/cpp/core/src/netconf_session.cpp b/sdk/cpp/core/src/netconf_session.cpp index 38e38f811..eb2f51716 100644 --- a/sdk/cpp/core/src/netconf_session.cpp +++ b/sdk/cpp/core/src/netconf_session.cpp @@ -63,7 +63,7 @@ static string get_read_rpc_name(bool config); static bool is_config(path::Rpc & rpc); static string get_filter_payload(path::Rpc & ydk_rpc); static string get_netconf_payload(path::DataNode & input, const string& data_tag, const string& data_value); -static shared_ptr handle_rpc_output(const string & reply, path::RootSchemaNode & root_schema, const string& rpc_path); +static shared_ptr handle_rpc_output(const string & reply, path::RootSchemaNode & root_schema, path::DataNode & input); static void check_rpc_reply_for_error(const string& reply); static void log_rpc_request(const string& payload); @@ -74,6 +74,7 @@ const string PROTOCOL_TCP = "tcp"; static bool is_netconf_get_rpc(path::Rpc & rpc); static shared_ptr netconf_output_to_datanode(const string & data, path::RootSchemaNode & root_schema); static string get_netconf_output(const string & reply); +static string extract_rpc_output(const string & reply); NetconfSession::NetconfSession(path::Repository & repo, const string& address, @@ -301,7 +302,7 @@ shared_ptr NetconfSession::handle_netconf_operation(path::Rpc& y } else if (ydk_rpc.has_output_node()) { - return handle_rpc_output(reply, *root_schema, ydk_rpc.get_input_node().get_path()); + return handle_rpc_output(reply, *root_schema, ydk_rpc.get_input_node()); } return nullptr; } @@ -322,11 +323,9 @@ std::string NetconfSession::execute_netconf_operation(path::Rpc& ydk_rpc) const { return get_netconf_output(reply); } - else if (ydk_rpc.has_output_node()) - { - handle_rpc_output(reply, *root_schema, ydk_rpc.get_input_node().get_path()); + else { + return extract_rpc_output(reply); } - return {}; } shared_ptr NetconfSession::invoke(path::DataNode& datanode) const @@ -344,7 +343,7 @@ shared_ptr NetconfSession::invoke(path::DataNode& datanode) cons string reply = execute_payload(netconf_payload); check_rpc_reply_for_error(reply); - return handle_rpc_output(reply, *root_schema, datanode.get_action_node_path()); + return handle_rpc_output(reply, *root_schema, datanode); } shared_ptr NetconfSession::invoke(path::Rpc& rpc) const @@ -379,7 +378,7 @@ shared_ptr NetconfSession::invoke(path::Rpc& rpc) const string NetconfSession::execute_payload(const string & payload) const { string reply = client->execute_payload(payload); - YLOG_INFO("============= Reply RPC received from device =============\n{}", reply); + YLOG_INFO("============= Received RPC from device =============\n{}", reply); return reply; } @@ -559,10 +558,10 @@ static shared_ptr handle_crud_edit_reply(string reply, NetconfCl //need to send the commit request string commit_payload = get_commit_rpc_payload(); - YLOG_INFO("============= Executing commit =============\n{}\n", commit_payload); + YLOG_INFO("============= Executing commit =============\n{}", commit_payload); reply = client.execute_payload(commit_payload); - YLOG_INFO("============= Reply RPC received from device =============\n{}", reply); + YLOG_INFO("============= RPC received from device =============\n{}", reply); if(reply.find("") == string::npos) { YLOG_ERROR("RPC error occurred: {}", reply); @@ -618,24 +617,87 @@ static shared_ptr netconf_output_to_datanode(const string & data return datanode; } -static shared_ptr handle_rpc_output(const string & reply, path::RootSchemaNode & root_schema, const string& rpc_path) +static string +extract_rpc_data(const string & reply, const string & start_tag, const string & end_tag, bool first_tag=false) +{ + auto data_start = reply.find(start_tag); + auto data_end = reply.rfind(end_tag); + if (data_start == string::npos || data_end == string::npos || (first_tag && data_start > 0)) { + return reply; + } + if (start_tag.find("<") == 0 && start_tag.find("", data_start); + data_start = data_start_end + 1; + } + else { + data_start += start_tag.length(); + } + string data = trim( reply.substr(data_start, data_end - data_start) ); + return data; +} + +static string +extract_rpc_output(const string & reply) { - path::Codec codec_service{}; + string rpc_output = extract_rpc_data(reply, ""); + if (rpc_output.length() == reply.length()) { + // Try with Netconf namespace prefix + rpc_output = extract_rpc_data(reply, ""); + } + + string reply_data = rpc_output; + rpc_output = extract_rpc_data(reply_data, "", true); + if (rpc_output.length() == reply_data.length()) { + rpc_output = extract_rpc_data(reply_data, "", true); + } + + rpc_output = extract_rpc_data(rpc_output, "", true); + return rpc_output; +} + +shared_ptr +NetconfSession::handle_action_rpc_output(const string & reply, path::DataNode& action_dn) +{ + return handle_rpc_output(reply, *root_schema, action_dn); +} + +static shared_ptr +handle_rpc_output(const string & reply, path::RootSchemaNode & root_schema, path::DataNode& input_dn) +{ + path::Codec codec_service{}; + + string data = extract_rpc_data(reply, ""); + if (data.length() == reply.length()) { + // Try with Netconf namespace prefix + data = extract_rpc_data(reply, ""); + } + + string data_node_path = input_dn.get_action_node_path(); + if (data_node_path.empty()) + { + if(reply.find("") != string::npos) + return nullptr; - auto data_start = reply.find("", data_start); - //need to find the end of the "", data_start); - data_start = data_start_end + 1; + data_node_path = input_dn.get_path(); + } + else { + if (reply.find("") != string::npos || reply.find("") != string::npos) + { + YLOG_INFO( "Found empty data tag"); + return nullptr; + } - string data = reply.substr(data_start, data_end - data_start); - if(data.find("") != string::npos) - return nullptr; + string rpc_output = data; + data = extract_rpc_data(rpc_output, "", true); + if (data.length() == reply.length()) { + data = extract_rpc_data(reply, "", true); + } + } shared_ptr datanode = codec_service.decode_rpc_output( root_schema, data, - rpc_path, + data_node_path, EncodingFormat::XML); return datanode; } @@ -680,7 +742,7 @@ static void check_rpc_reply_for_error(const string& reply) static void log_rpc_request(const string& payload) { - YLOG_INFO("============= Generated RPC to send to device =============\n{}\n", payload); + YLOG_INFO("============= Sending RPC to device =============\n{}", payload); } } //namespace path diff --git a/sdk/cpp/core/src/path/data_node.cpp b/sdk/cpp/core/src/path/data_node.cpp index 541cb8658..830d1a06f 100644 --- a/sdk/cpp/core/src/path/data_node.cpp +++ b/sdk/cpp/core/src/path/data_node.cpp @@ -106,6 +106,8 @@ ydk::path::DataNodeImpl::get_path() const void ydk::path::DataNodeImpl::populate_new_schemas_from_path(const std::string& path) { + if (path.empty()) return; + YLOG_DEBUG("Populating schema for '{}'", path); check_ly_schema_node_for_path(m_node, path); auto snode = reinterpret_cast(m_node->schema->priv); snode->populate_new_schemas_from_path(path); @@ -139,13 +141,9 @@ ydk::path::DataNodeImpl::create_datanode(const std::string& path, const std::str YLOG_DEBUG("Replacing value '{}' with '{}'", value, v); } } - - YLOG_DEBUG("Populating schemas for path '{}'", path); populate_new_schemas_from_path(path); - if (!v.empty()) { - YLOG_DEBUG("Populating schemas for value '{}'", v); - populate_new_schemas_from_path(v); - } + populate_new_schemas_from_path(v); + return create_helper(path, v); } diff --git a/sdk/cpp/core/src/path/path.cpp b/sdk/cpp/core/src/path/path.cpp index e5e1a0ff1..f4f0cb569 100644 --- a/sdk/cpp/core/src/path/path.cpp +++ b/sdk/cpp/core/src/path/path.cpp @@ -257,7 +257,6 @@ ydk::path::Codec::encode(const ydk::path::DataNode& dn, ydk::EncodingFormat form throw(ydk::YInvalidArgumentError{"No data in data node"}); } char* buffer = nullptr; - //lyd_node* temp_node = m_node->prev->next; m_node->prev->next = nullptr; // Fixing libyang bug in printer_json if(!lyd_print_mem(&buffer, m_node, scheme, (pretty ? LYP_FORMAT : 0)|LYP_WD_ALL|LYP_KEEPEMPTYCONT)) { if(!buffer) { @@ -269,7 +268,6 @@ ydk::path::Codec::encode(const ydk::path::DataNode& dn, ydk::EncodingFormat form ret = buffer; std::free(buffer); } - //m_node->prev->next = temp_node; // Fixing libyang bug in printer_json } return ret; } @@ -310,8 +308,9 @@ ydk::path::Codec::decode_rpc_output(RootSchemaNode & root_schema, const std::str YLOG_ERROR( "Parsing failed with message {}", ly_errmsg()); throw(YCodecError{YCodecError::Error::XML_INVAL}); } + auto dn = perform_decode(rs_impl, root); if (rpc) lyd_free(rpc); - return perform_decode(rs_impl, root); + return dn; } std::shared_ptr diff --git a/sdk/cpp/core/src/path/repository.cpp b/sdk/cpp/core/src/path/repository.cpp index 75741359b..08db7db8e 100644 --- a/sdk/cpp/core/src/path/repository.cpp +++ b/sdk/cpp/core/src/path/repository.cpp @@ -396,7 +396,6 @@ ydk::path::RepositoryPtr::get_new_ly_modules_from_path(ly_ctx* ctx, const std::string& path, const std::unordered_map& lookup_table) { - //YLOG_DEBUG("Getting new modules from '{}'", path); auto module_names = path::segmentalize_module_names(path); return get_new_ly_modules_from_lookup(ctx, module_names, lookup_table); } diff --git a/sdk/cpp/core/src/path/root_schema_node.cpp b/sdk/cpp/core/src/path/root_schema_node.cpp index 0ae820dec..3f8163fcf 100644 --- a/sdk/cpp/core/src/path/root_schema_node.cpp +++ b/sdk/cpp/core/src/path/root_schema_node.cpp @@ -243,8 +243,10 @@ ydk::path::RootSchemaNodeImpl::populate_new_schemas_from_payload(const std::stri } void -ydk::path::RootSchemaNodeImpl::populate_new_schemas_from_path(const std::string& path) { - YLOG_DEBUG("Getting new modules for '{}'", path); +ydk::path::RootSchemaNodeImpl::populate_new_schemas_from_path(const std::string& path) +{ + if (path.empty()) return; + YLOG_DEBUG("Getting new modules for path '{}'", path); auto new_modules = m_priv_repo->get_new_ly_modules_from_path(m_ctx, path, m_name_namespace_lookup); populate_new_schemas(new_modules); } diff --git a/sdk/cpp/core/src/path/schema_node.cpp b/sdk/cpp/core/src/path/schema_node.cpp index 7fe27a581..290cdaf02 100644 --- a/sdk/cpp/core/src/path/schema_node.cpp +++ b/sdk/cpp/core/src/path/schema_node.cpp @@ -181,10 +181,10 @@ ydk::path::SchemaNodeImpl::get_root() const noexcept void ydk::path::SchemaNodeImpl::populate_new_schemas_from_path(const string& path) { + if (path.empty()) return; YLOG_DEBUG("Looking to populate schemas for '{}'", path); auto snode = const_cast(&get_root()); auto rsnode = reinterpret_cast(snode); - //YLOG_DEBUG("Ready to populate schemas for {}", path); rsnode->populate_new_schemas_from_path(path); } diff --git a/sdk/cpp/core/src/path_api.hpp b/sdk/cpp/core/src/path_api.hpp index d79d13f21..d23213bc0 100644 --- a/sdk/cpp/core/src/path_api.hpp +++ b/sdk/cpp/core/src/path_api.hpp @@ -37,7 +37,6 @@ #include "errors.hpp" #include "types.hpp" #include "validation_service.hpp" -#include "path_api.hpp" namespace ydk { @@ -1085,6 +1084,9 @@ class NetconfSession : public Session { std::vector get_capabilities() const; std::string execute_netconf_operation(Rpc& netconf_rpc) const; + // This function is for YDK internal tests only + std::shared_ptr handle_action_rpc_output(const std::string & rpc_reply, path::DataNode& action_dn); + private: std::vector get_yang_1_1_capabilities() const; std::shared_ptr handle_crud_edit( diff --git a/sdk/cpp/core/tests/test_entity.cpp b/sdk/cpp/core/tests/test_entity.cpp index d350cff32..35eb5d1e8 100644 --- a/sdk/cpp/core/tests/test_entity.cpp +++ b/sdk/cpp/core/tests/test_entity.cpp @@ -499,6 +499,8 @@ TEST_CASE("test_ylist") ep = ylist_1.pop("test1"); REQUIRE(ep == nullptr); + + delete list_holder; } //TODO Test for issue #800 to be resolved @@ -520,4 +522,6 @@ TEST_CASE("test_ylist") // // auto ep = ylist["test1"]; // REQUIRE(ep != nullptr); +// +// delete list_holder; //} diff --git a/sdk/cpp/gnmi/src/gnmi_session.cpp b/sdk/cpp/gnmi/src/gnmi_session.cpp index 5a6a6d7cd..cc027adaa 100644 --- a/sdk/cpp/gnmi/src/gnmi_session.cpp +++ b/sdk/cpp/gnmi/src/gnmi_session.cpp @@ -220,7 +220,8 @@ bool gNMISession::handle_set(Rpc& ydk_rpc) const } } - return client->execute_set_operation(setRequest); + bool result = client->execute_set_operation(setRequest); + return result; } shared_ptr @@ -271,7 +272,6 @@ gNMISession::handle_get(Rpc& rpc) const for (auto response : reply) { YLOG_DEBUG("\n{}", response); } - return handle_get_reply(reply); } diff --git a/sdk/cpp/gnmi/tests/test_core_gnmi.cpp b/sdk/cpp/gnmi/tests/test_core_gnmi.cpp index 8af8ffe3a..d73a3e697 100644 --- a/sdk/cpp/gnmi/tests/test_core_gnmi.cpp +++ b/sdk/cpp/gnmi/tests/test_core_gnmi.cpp @@ -64,6 +64,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE( "test_gnmi_entity_leaf_to_path" ) @@ -97,6 +100,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE( "test_gnmi_entity_key_and_leaf_to_path" ) @@ -130,6 +136,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE( "test_gnmi_entity_key_and_leaf_to_path2" ) @@ -175,6 +184,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE( "test_gnmi_datanode_to_path" ) @@ -213,6 +225,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE( "test_gnmi_datanode_to_path_2" ) @@ -244,6 +259,9 @@ elem { } )"; REQUIRE(path->DebugString() == expected); + + path->Clear(); + delete path; } TEST_CASE("gnmi_test_json_payload" ) diff --git a/sdk/cpp/tests/test_path_api.cpp b/sdk/cpp/tests/test_path_api.cpp index f1d534fca..f3a7de018 100644 --- a/sdk/cpp/tests/test_path_api.cpp +++ b/sdk/cpp/tests/test_path_api.cpp @@ -668,3 +668,17 @@ TEST_CASE("iana_if_type_decode") REQUIRE(xml == ifc_payload); } +TEST_CASE( "rpc_get_schema_no_decode" ) +{ + ydk::path::Repository repo{}; + + ydk::path::NetconfSession session{repo,"127.0.0.1", "admin", "admin", 12022}; + ydk::path::RootSchemaNode& schema = session.get_root_schema(); + + auto rpc = schema.create_rpc("ietf-netconf-monitoring:get-schema"); + rpc->get_input_node().create_datanode("identifier", "ydktest-sanity-action"); + + auto reply = session.execute_netconf_operation(*rpc); + REQUIRE(!reply.empty()); + //cout << reply << endl; +} diff --git a/sdk/cpp/tests/test_sanity_codec.cpp b/sdk/cpp/tests/test_sanity_codec.cpp index 4bf0d77a2..95e2e48bf 100644 --- a/sdk/cpp/tests/test_sanity_codec.cpp +++ b/sdk/cpp/tests/test_sanity_codec.cpp @@ -547,3 +547,28 @@ TEST_CASE("json_encode_decode") openconfig_interfaces::Interfaces * entity_ptr = dynamic_cast(ifcs_d.get()); REQUIRE(ifcs == *entity_ptr); } + +TEST_CASE( "test_codec_action_rpc" ) +{ + ydk::path::Repository repo{TEST_HOME}; + ydk::path::NetconfSession session{repo,"127.0.0.1", "admin", "admin", 12022}; + ydk::path::RootSchemaNode& schema = session.get_root_schema(); + + auto & data = schema.create_datanode("ydktest-sanity-action:data"); + auto & actn = data.create_action("action-node"); + actn.create_datanode("test", "status"); + + string rpc_reply = R"( + + ok + + +)"; + + auto reply_dn = session.handle_action_rpc_output(rpc_reply, data); + REQUIRE(reply_dn != nullptr); + + ydk::path::Codec s{}; + auto xml_reply = s.encode(*reply_dn, EncodingFormat::XML, false); + REQUIRE(xml_reply==R"(ok)"); +} diff --git a/sdk/cpp/tests/test_sanity_levels.cpp b/sdk/cpp/tests/test_sanity_levels.cpp index 6489bbbc5..79f0fef2e 100644 --- a/sdk/cpp/tests/test_sanity_levels.cpp +++ b/sdk/cpp/tests/test_sanity_levels.cpp @@ -89,7 +89,7 @@ TEST_CASE("one_level_aug_pos") bool reply = crud.delete_(provider, *r_1); REQUIRE(reply); - r_1->ydktest_sanity_augm_one_->twin_number = 1; + r_1->ydktest_sanity_augm_one->twin_number = 1; reply = crud.create(provider, *r_1); REQUIRE(reply); @@ -99,11 +99,11 @@ TEST_CASE("one_level_aug_pos") ydktest_sanity::Runner * r_2_ptr = dynamic_cast(r_2.get()); REQUIRE(r_2_ptr!=nullptr); - REQUIRE(r_1->ydktest_sanity_augm_one_->twin_number == r_2_ptr->ydktest_sanity_augm_one_->twin_number); + REQUIRE(r_1->ydktest_sanity_augm_one->twin_number == r_2_ptr->ydktest_sanity_augm_one->twin_number); //UPDATE r_1 = make_unique(); - r_1->ydktest_sanity_augm_one_->twin_number = 10; + r_1->ydktest_sanity_augm_one->twin_number = 10; filter = make_unique(); reply = crud.update(provider, *r_1); @@ -114,7 +114,7 @@ TEST_CASE("one_level_aug_pos") r_2_ptr = dynamic_cast(r_2.get()); REQUIRE(r_2_ptr!=nullptr); - REQUIRE(r_1->ydktest_sanity_augm_one_->twin_number == r_2_ptr->ydktest_sanity_augm_one_->twin_number); + REQUIRE(r_1->ydktest_sanity_augm_one->twin_number == r_2_ptr->ydktest_sanity_augm_one->twin_number); // DELETE filter = make_unique(); diff --git a/sdk/go/CHANGES.md b/sdk/go/CHANGES.md index 79d631a1f..af49c054b 100644 --- a/sdk/go/CHANGES.md +++ b/sdk/go/CHANGES.md @@ -1,6 +1,7 @@ ### 2019-05-15 version 0.8.3 #### Resolved GitHub issues + * YDK return value of YANG action missing some attributes ([#871](https://github.com/CiscoDevNet/ydk-gen/issues/871)) * Duplicate code in generated cisco-ios-xe Go bundle ([#891](https://github.com/CiscoDevNet/ydk-gen/issues/891)) ##### Note diff --git a/sdk/python/CHANGES.md b/sdk/python/CHANGES.md index b93aeaae0..437eaa9b3 100644 --- a/sdk/python/CHANGES.md +++ b/sdk/python/CHANGES.md @@ -1,6 +1,7 @@ ### 2019-05-15 version 0.8.3 #### Resolved GitHub issues + * YDK return value of YANG action missing some attributes ([#871](https://github.com/CiscoDevNet/ydk-gen/issues/871)) * Duplicate code in generated cisco-ios-xe Go bundle ([#891](https://github.com/CiscoDevNet/ydk-gen/issues/891)) ##### Note diff --git a/sdk/python/core/CMakeLists.txt b/sdk/python/core/CMakeLists.txt index de440088e..867d8c339 100644 --- a/sdk/python/core/CMakeLists.txt +++ b/sdk/python/core/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0.0) cmake_policy(SET CMP0048 NEW) -project(path VERSION 0.8.3 LANGUAGES C CXX) +project(path VERSION 0.8.2 LANGUAGES C CXX) set(CMAKE_MACOSX_RPATH 1) diff --git a/sdk/python/core/docsgen/api/path/netconf_session.rst b/sdk/python/core/docsgen/api/path/netconf_session.rst index 8bb1504c3..1d70f4257 100644 --- a/sdk/python/core/docsgen/api/path/netconf_session.rst +++ b/sdk/python/core/docsgen/api/path/netconf_session.rst @@ -29,20 +29,28 @@ NetconfSession .. py:method:: invoke(rpc) - :param rpc: (:py:class:`Rpc`) Given RPC to be executed. - Invokes or executes the given RPC and returns a :py:class:`DataNode` pointer, if the RPC has an output modeled in YANG. + :param rpc: (:py:class:`Rpc`) Given RPC to be executed. + :returns: :py:class:`DataNode`. .. py:method:: invoke(datanode) - :param datanode: (:py:class:`Rpc`) Given DataNode containing YANG 1.1 action to be executed. - Invokes or executes the given DataNode and returns a :py:class:`DataNode` pointer if the action has an output modeled in YANG. + :param datanode: (:py:class:`Rpc`) Given DataNode containing YANG 1.1 action to be executed. + :returns: :py:class:`DataNode`. + .. py:method:: execute_netconf_operation(rpc) + + Sends specified RPC to device (similar to `invoke` function) and returns device response as XML encoded string. + + :param rpc: (:py:class:`Rpc`) The RPC to be executed. + + :returns: ``str`` - reply from device in XML encoded string. + .. py:method:: get_capabilities() Returns a list of capabilities of the client diff --git a/sdk/python/core/python.cpp b/sdk/python/core/python.cpp index e0701f04a..da0e59920 100644 --- a/sdk/python/core/python.cpp +++ b/sdk/python/core/python.cpp @@ -384,6 +384,7 @@ PYBIND11_MODULE(ydk_, ydk) .def("get_root_schema", &ydk::path::NetconfSession::get_root_schema, return_value_policy::reference) .def("invoke", (std::shared_ptr (ydk::path::NetconfSession::*)(ydk::path::Rpc& rpc) const) &ydk::path::NetconfSession::invoke, return_value_policy::reference) .def("invoke", (std::shared_ptr (ydk::path::NetconfSession::*)(ydk::path::DataNode& rpc) const) &ydk::path::NetconfSession::invoke, return_value_policy::reference) + .def("execute_netconf_operation", (std::string (ydk::path::NetconfSession::*)(ydk::path::Rpc& rpc) const) &ydk::path::NetconfSession::execute_netconf_operation) .def("get_capabilities", &ydk::path::NetconfSession::get_capabilities, return_value_policy::reference); class_(path, "RestconfSession") diff --git a/sdk/python/core/tests/test_sanity_levels.py b/sdk/python/core/tests/test_sanity_levels.py index 2e5e8284c..1f0631a47 100644 --- a/sdk/python/core/tests/test_sanity_levels.py +++ b/sdk/python/core/tests/test_sanity_levels.py @@ -96,7 +96,7 @@ def test_one_level_pos(self): def test_one_aug_level_pos(self): # READ r_1 = Runner() - r_1.ydktest_sanity_augm_one_.twin_number = 1 + r_1.ydktest_sanity_augm_one.twin_number = 1 self.crud.create(self.ncc, r_1) r_2 = self.crud.read(self.ncc, Runner()) @@ -104,7 +104,7 @@ def test_one_aug_level_pos(self): # UPDATE r_1= Runner() - r_1.ydktest_sanity_augm_one_.twin_number = 10 + r_1.ydktest_sanity_augm_one.twin_number = 10 self.crud.update(self.ncc, r_1) r_2 = self.crud.read(self.ncc, Runner()) diff --git a/sdk/python/core/tests/test_sanity_path.py b/sdk/python/core/tests/test_sanity_path.py index f111a6fa2..9ce86fd98 100644 --- a/sdk/python/core/tests/test_sanity_path.py +++ b/sdk/python/core/tests/test_sanity_path.py @@ -228,6 +228,14 @@ def test_path_codec_list(self): xml_decode = self.codec.encode(node_decode, EncodingFormat.XML, True) self.assertEqual(xml_encode, xml_decode) + def test_rpc_get_schema_no_decode(self): + rpc = self.root_schema.create_rpc("ietf-netconf-monitoring:get-schema") + rpc.get_input_node().create_datanode("identifier", "ydktest-sanity-action") + + reply = self.nc_session.execute_netconf_operation(rpc) + self.assertTrue(len(reply)>0) + #print(reply) + def enable_logging(level): log = logging.getLogger('ydk') log.setLevel(level) diff --git a/sdk/python/core/ydk/path/sessions/netconf_session.py b/sdk/python/core/ydk/path/sessions/netconf_session.py index 90fa4751d..31090bfce 100644 --- a/sdk/python/core/ydk/path/sessions/netconf_session.py +++ b/sdk/python/core/ydk/path/sessions/netconf_session.py @@ -65,5 +65,8 @@ def get_root_schema(self): def invoke(self, rpc): return super(NetconfSession, self).invoke(rpc) + def execute_netconf_operation(self, rpc): + return super(NetconfSession, self).execute_netconf_operation(rpc) + def get_capabilities(self): - return super(NetconfSession, self).get_capabilities() \ No newline at end of file + return super(NetconfSession, self).get_capabilities() diff --git a/test/dependencies_osx.sh b/test/dependencies_osx.sh index 0404aeeb6..1d2d2881b 100755 --- a/test/dependencies_osx.sh +++ b/test/dependencies_osx.sh @@ -114,7 +114,7 @@ MSG_COLOR=$YELLOW install_libssh install_confd -install_golang +#install_golang brew install pybind11 check_python_installation diff --git a/test/gnmi_tests.sh b/test/gnmi_tests.sh index 993433d61..6696fdcc9 100755 --- a/test/gnmi_tests.sh +++ b/test/gnmi_tests.sh @@ -80,7 +80,7 @@ function pip_check_install { print_msg "Custom pip install of $@ for CentOS" ${PIP_BIN} install --install-option="--install-purelib=/usr/lib64/python${PYTHON_VERSION}/site-packages" --no-deps $@ else - ${PIP_BIN} install $@ + ${PIP_BIN} install --no-deps $@ fi } @@ -137,8 +137,11 @@ function init_go_env { print_msg "Initializing Go environment" if [[ $(uname) == "Darwin" ]]; then - source /Users/travis/.gvm/scripts/gvm - gvm use go1.9.2 + #source /Users/travis/.gvm/scripts/gvm + #gvm use go1.9.2 + if [[ $GOPATH. == "." ]]; then + export GOPATH="$(pwd)/golang" + fi print_msg "GOROOT: $GOROOT" print_msg "GOPATH: $GOPATH" else diff --git a/test/tests.sh b/test/tests.sh index 9217eac25..731eee9a7 100755 --- a/test/tests.sh +++ b/test/tests.sh @@ -80,7 +80,7 @@ function pip_check_install { print_msg "Custom pip install of $@ for CentOS" ${PIP_BIN} install --install-option="--install-purelib=/usr/lib64/python${PYTHON_VERSION}/site-packages" --no-deps $@ -U else - ${PIP_BIN} install $@ -U + ${PIP_BIN} install --no-deps $@ -U fi } @@ -171,8 +171,11 @@ function init_go_env { print_msg "Initializing Go environment" if [[ $(uname) == "Darwin" ]]; then - source /Users/travis/.gvm/scripts/gvm - gvm use go1.9.2 + #source /Users/travis/.gvm/scripts/gvm + #gvm use go1.9.2 + if [[ $GOPATH. == "." ]]; then + export GOPATH="$(pwd)/golang" + fi print_msg "GOROOT: $GOROOT" print_msg "GOPATH: $GOPATH" else @@ -259,7 +262,7 @@ function install_py_core { print_msg "Installing Python YDK core" if [[ $run_with_coverage ]] ; then - print_msg "Building python with coverage" + print_msg "Building Python with coverage" export YDK_COVERAGE= fi cd $YDKGEN_HOME/sdk/python/core @@ -291,7 +294,7 @@ function generate_install_specified_cpp_bundle { run_test generate.py --bundle ${bundle_profile} --cpp &> /dev/null cd gen-api/cpp/${bundle_name}/build run_exec_test make &> /dev/null - sudo make install + run_exec_test sudo make install cd - } @@ -359,7 +362,7 @@ function cpp_test_gen { run_test generate.py --bundle profiles/test/ydk-models-test.json --generate-tests --cpp &> /dev/null cd gen-api/cpp/models_test-bundle/build/ run_exec_test make &> /dev/null - sudo make install + run_exec_test sudo make install # cpp_test_gen_test }