Skip to content

Commit

Permalink
Add sample for XR json read+write (#387)
Browse files Browse the repository at this point in the history
* Improve logging for codec service
 * Also do not build cpp bundle after code generation. Make building and
   installing a separate step after generation
  • Loading branch information
Abhi Keshav committed Feb 22, 2017
1 parent 2faead8 commit 6437e31
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 16 deletions.
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Options:
--generate-doc Generation documentation
--output-directory The output-directory . If not specified the output can be found under `ydk-gen/gen-api/python`
```
The below steps specify how to use `ydk-gen` to generate the python core and a python bundle. Similar steps can be followed for C++. Pre-generated bundles and core are available for python and C++: [ydk-py](https://github.com/CiscoDevNet/ydk-py) and [ydk-cpp](https://github.com/CiscoDevNet/ydk-cpp).
The below steps specify how to use `ydk-gen` to generate the core and a bundle. Pre-generated bundles and core are available for python and C++: [ydk-py](https://github.com/CiscoDevNet/ydk-py) and [ydk-cpp](https://github.com/CiscoDevNet/ydk-cpp).

### First step: choose your bundle profile

Expand Down Expand Up @@ -180,36 +180,51 @@ Only directory examples are shown below.

First, generate the core and install it:

For python:
```
$ ./generate.py --python --core
$ pip install gen-api/python/ydk/dist/ydk*.tar.gz
```

For C++:
```
$ ./generate.py --cpp --core
$ cd gen-api/cpp/ydk/build && make && sudo make install
```

### Third step: Generate & install your bundle
Then, generate your bundle using a bundle profile and install it:


For python:
```
$ ./generate.py --python --bundle profiles/<name-of-profile>.json
$ pip install gen-api/python/<name-of-bundle>-bundle/dist/ydk*.tar.gz
```

Now, doing `pip list` should show the `ydk` (refering to the core package) and `ydk-<name-of-bundle>` packages installed:

```
```
$ pip list
...
ydk (0.5.2)
ydk-models-<name-of-bundle> (0.5.1)
...
```

For C++:
```
$ ./generate.py --cpp --bundle profiles/<name-of-profile>.json
$ cd gen-api/cpp/<name-of-bundle>-bundle/build && make && make install
```

### Fourth step: Writing your first app

Now, you can start creating apps based on the models in your bundle. Assuming you generated a python bundle, the models will be available for importing in your app under `ydk.models.<name-of-your-bundle>`. See [ydk-py-samples](https://github.com/CiscoDevNet/ydk-py-samples#a-hello-world-app) for examples. Also refer to the [documentation](http://ydk.cisco.com/py/docs/developer_guide.html).
Now, you can start creating apps based on the models in your bundle. Assuming you generated a python bundle, the models will be available for importing in your app under `ydk.models.<name-of-your-bundle>`. For examples, see [ydk-py-samples](https://github.com/CiscoDevNet/ydk-py-samples#a-hello-world-app) and [C++ samples](sdk/cpp/samples). Also refer to the [documentation for python](http://ydk.cisco.com/py/docs/developer_guide.html) and [for C++](http://ydk.cisco.com/cpp/docs/developer_guide.html).

### Documentation

When generating the YDK documentation for several bundles and the core, it is recommended to generate the bundles without the `--generate-doc` option. After generating all the bundles, the combined documentation for all the bundles and the core can be generated using the `--core --generate-doc` option. For example, the below sequence of commands will generate the documentation for the three bundles and the core. Note that this process could take a few hours due to the size of the `cisco_ios_xr` bundle:
When generating the YDK documentation for several bundles and the core, it is recommended to generate the bundles without the `--generate-doc` option. After generating all the bundles, the combined documentation for all the bundles and the core can be generated using the `--core --generate-doc` option. For example, the below sequence of commands will generate the documentation for the three python bundles and the python core (for C++, use `--cpp` instead of `--python`).

Note that the below process could take a few hours due to the size of the `cisco_ios_xr` bundle.

```
./generate.py --python --bundle profiles/bundles/ietf_0_1_1.json
Expand Down
5 changes: 2 additions & 3 deletions generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,10 @@ def create_shared_libraries(output_directory):
os.chdir(cmake_build_dir)
try:
subprocess.check_call(['cmake', '-DCMAKE_C_COMPILER=/usr/bin/clang', '-DCMAKE_CXX_COMPILER=/usr/bin/clang++', '..'])
subprocess.check_call(['make'])
except subprocess.CalledProcessError as e:
print('\nERROR: Failed to create shared library!\n')
sys.exit(e.returncode)
print('\nSuccessfully created shared libraries at {0}.\nTo install, run "[sudo] make install" from {1}'.format(output_directory, cmake_build_dir))
print('\nSuccessfully generated code at {0}.\nTo build and install, run "make && [sudo] make install" from {1}'.format(output_directory, cmake_build_dir))
print('\n=================================================')
print('Successfully generated C++ YDK at %s' % (cpp_sdk_root,))
print('Please read %s/README.md for information on how to use YDK\n' % (
Expand Down Expand Up @@ -312,7 +311,7 @@ def _get_time_taken(start_time):

minutes_str, seconds_str = _get_time_taken(start_time)
print('\nTime taken for code/doc generation: {0} {1}\n'.format(minutes_str, seconds_str))
print('\nBuilding {0} package...\n'.format(language))
print('\nCreating {0} package...\n'.format(language))

if options.cpp:
create_shared_libraries(output_directory)
Expand Down
4 changes: 4 additions & 0 deletions sdk/cpp/core/src/codec_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
//
//////////////////////////////////////////////////////////////////

#include <libyang/libyang.h>

#include "codec_provider.hpp"
#include "entity_lookup.hpp"

Expand All @@ -29,7 +31,9 @@ CodecServiceProvider::CodecServiceProvider(path::Repository & repo, EncodingForm
: m_encoding{encoding}, m_repo{repo}
{
augment_lookup_tables();
ly_verb(LY_LLSILENT); //turn off libyang logging at the beginning
m_root_schema = std::unique_ptr<ydk::path::RootSchemaNode>(m_repo.create_root_schema(get_global_capabilities()));
ly_verb(LY_LLVRB); // enable libyang logging after payload has been created
}

CodecServiceProvider::~CodecServiceProvider()
Expand Down
7 changes: 4 additions & 3 deletions sdk/cpp/core/src/codec_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ CodecService::encode(CodecServiceProvider & provider, Entity & entity, bool pret
{
path::DataNode& data_node = get_data_node_from_entity(entity, root_schema);
path::CodecService core_codec_service{};
return core_codec_service.encode(data_node, provider.m_encoding, pretty);
std::string result = core_codec_service.encode(data_node, provider.m_encoding, pretty);
YLOG_DEBUG("Performing encode operation, resulting in {}", result);
return result;
}
catch (const YCPPInvalidArgumentError& e)
{
Expand All @@ -80,7 +82,7 @@ CodecService::encode(CodecServiceProvider & provider, std::map<std::string, std:
std::unique_ptr<Entity>
CodecService::decode(CodecServiceProvider & provider, std::string & payload, std::unique_ptr<Entity> entity)
{
YLOG_DEBUG("Decoding {}", payload);
YLOG_DEBUG("Performing decode operation on {}", payload);
path::RootSchemaNode& root_schema = provider.get_root_schema();

path::CodecService core_codec_service{};
Expand All @@ -107,7 +109,6 @@ CodecService::decode(CodecServiceProvider & provider, std::map<std::string, std:
{
for (auto it: payload_map)
{
YLOG_DEBUG("Decoding {}", it.second);
std::unique_ptr<Entity> entity = decode(provider, it.second, std::move(entity_map[it.first]));
entity_map[it.first] = std::move(entity);
}
Expand Down
25 changes: 22 additions & 3 deletions sdk/cpp/samples/args_parser.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
#include "args_parser.h"
/* ----------------------------------------------------------------
Copyright 2016 Cisco Systems
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
------------------------------------------------------------------*/

#include <iostream>

#include "args_parser.h"

using namespace std;

void show_usage(string name)
Expand All @@ -10,12 +27,14 @@ void show_usage(string name)

vector<string> parse_args(int argc, char* argv[])
{
if (argc < 2) {
if (argc < 2)
{
show_usage(argv[0]);
return {};
}
string arg = argv[1];
if ((arg == "-h") || (arg == "--help")) {
if ((arg == "-h") || (arg == "--help"))
{
show_usage(argv[0]);
return {};
}
Expand Down
16 changes: 16 additions & 0 deletions sdk/cpp/samples/args_parser.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/* ----------------------------------------------------------------
Copyright 2016 Cisco Systems
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
------------------------------------------------------------------*/

#ifndef _ARGS_PARSER_H_
#define _ARGS_PARSER_H_

Expand Down
2 changes: 2 additions & 0 deletions sdk/cpp/samples/bgp_xr_json/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build*
config_read.json
56 changes: 56 additions & 0 deletions sdk/cpp/samples/bgp_xr_json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 2.8.9)
cmake_policy(SET CMP0048 NEW)
project(samples)


set(SAMPLE_DESCRIPTION "BGP sample application using YANG Development Kit Library, the library for YDK API.")


set(samples bgp_xr_json_read
bgp_xr_json_write)

# set default build type if not specified by user
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -fprofile-arcs -ftest-coverage")

# Find dependent libraries
find_library(ydk_location ydk)
find_library(ydk_cisco_ios_xr_location ydk_cisco_ios_xr)
find_library(xml2_location xml2)
find_library(curl_location curl)
find_library(ssh_location ssh)
find_library(ssh_threads_location ssh_threads)
find_library(pcre_location pcre)
find_library(xslt_location xslt)
find_library(pthread_location pthread)
find_library(dl_location dl)

include_directories(SYSTEM)

# set default build type if not specified by user
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE debug)
endif()

foreach(sample IN LISTS samples)
add_executable(${sample} ${sample}.cpp ../args_parser.cpp)

target_link_libraries(${sample}
${ydk_location}
${ydk_cisco_ios_xr_location}
${xml2_location}
${curl_location}
${ssh_location}
${ssh_threads_location}
${pcre_location}
${xslt_location}
${pthread_location}
${dl_location}
-rdynamic
)

set_property(TARGET ${sample} PROPERTY CXX_STANDARD 11)
set_property(TARGET ${sample} PROPERTY CXX_STANDARD_REQUIRED ON)
endforeach(sample)

19 changes: 19 additions & 0 deletions sdk/cpp/samples/bgp_xr_json/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# YDK C++ BGP JSON Samples for XR
###Prerequisite
First install the [system requirements](https://github.com/CiscoDevNet/ydk-gen#system-requirements). Then follow the [ydk-gen README](https://github.com/CiscoDevNet/ydk-gen#usage) and generate/install the C++ core, [ietf bundle](https://github.com/CiscoDevNet/ydk-gen/blob/master/profiles/bundles/ietf_0_1_1.json) and [cisco-ios-xr bundle](https://github.com/CiscoDevNet/ydk-gen/blob/master/profiles/bundles/cisco-ios-xr_6_1_2.json).
### 1) Build the sample apps
```
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make && sudo make install
$ cd ..
```

### 2) Run the apps

Note: `-v` will turn on verbose mode
```
$ cd build
$ ./bgp_xr_json_write ssh://<username>:<password>@<host address>:<port> [-v]
$ ./bgp_xr_json_read ssh://<username>:<password>@<host address>:<port> [-v]
```
91 changes: 91 additions & 0 deletions sdk/cpp/samples/bgp_xr_json/bgp_xr_json_read.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* ----------------------------------------------------------------
Copyright 2016 Cisco Systems
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
------------------------------------------------------------------*/
#include <iostream>
#include <fstream>

#include <ydk/codec_provider.hpp>
#include <ydk/codec_service.hpp>
#include <ydk/crud_service.hpp>
#include <ydk/netconf_provider.hpp>
#include <ydk/path_api.hpp>
#include <ydk/types.hpp>

#include <ydk_cisco_ios_xr/Cisco_IOS_XR_ipv4_bgp_cfg.hpp>
#include <spdlog/spdlog.h>

#include "../args_parser.h"

using namespace ydk;
using namespace ydk::Cisco_IOS_XR_ipv4_bgp_cfg;
using namespace std;

#define CONFIG_FILE "../config_read.json"

void write_json_config(string json)
{
ofstream config_file;
config_file.open (CONFIG_FILE);
config_file << json;
config_file.close();
}

int main(int argc, char* argv[])
{
vector<string> args = parse_args(argc, argv);
if(args.empty()) return 1;

string host, username, password;
int port;

username = args[0]; password = args[1]; host = args[2]; port = stoi(args[3]);

bool verbose=(args[4]=="--verbose");
if(verbose)
{
auto logger = spdlog::stdout_color_mt("ydk");
logger->set_level(spdlog::level::debug);
}

try
{
path::Repository repo{};
NetconfServiceProvider provider{repo, host, username, password, port};
CrudService crud{};

auto bgp = make_unique<Bgp>();
auto bgp_read = crud.read_config(provider, *bgp);
if(bgp_read == nullptr)
{
cout << "=================================================="<<endl;
cout << "No entries found"<<endl<<endl;
cout << "=================================================="<<endl;
return 0;
}
cout << "Read operation success" << endl;

CodecService codec_service{};
CodecServiceProvider codec_provider{repo, EncodingFormat::JSON};

auto json = codec_service.encode(codec_provider, *bgp_read);

write_json_config(json);
cout << "Writing JSON config" << endl;
}
catch(YCPPError & e)
{
cerr << "Error details: " << e << endl;
}
}
Loading

0 comments on commit 6437e31

Please sign in to comment.